// Copyright 2017 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "cobalt/dom/mutation_observer.h"

#include "base/trace_event/trace_event.h"
#include "cobalt/base/debugger_hooks.h"
#include "cobalt/base/polymorphic_downcast.h"
#include "cobalt/dom/dom_settings.h"
#include "cobalt/dom/mutation_observer_task_manager.h"
#include "cobalt/dom/node.h"
#include "cobalt/script/exception_message.h"

namespace cobalt {
namespace dom {
namespace {
// script::ExceptionState that will DCHECK on exception.
class NativeExceptionState : public script::ExceptionState {
 public:
  void SetException(const scoped_refptr<script::ScriptException>&) override {
    NOTREACHED();
  }

  void SetSimpleExceptionVA(script::SimpleExceptionType, const char*,
                            va_list) override {
    NOTREACHED();
  }
};
}  // namespace
// Abstract base class for a MutationCallback.
class MutationObserver::CallbackInternal {
 public:
  virtual bool RunCallback(const MutationRecordSequence& mutations,
                           const scoped_refptr<MutationObserver>& observer) = 0;
  virtual ~CallbackInternal() {}
};

namespace {
// Implement the CallbackInternal interface for a JavaScript callback.
class ScriptCallback : public MutationObserver::CallbackInternal {
 public:
  ScriptCallback(const MutationObserver::MutationCallbackArg& callback,
                 MutationObserver* owner)
      : callback_(owner, callback) {}
  bool RunCallback(const MutationObserver::MutationRecordSequence& mutations,
                   const scoped_refptr<MutationObserver>& observer) override {
    script::CallbackResult<void> result =
        callback_.value().Run(mutations, observer);
    return !result.exception;
  }

 private:
  MutationObserver::MutationCallbackArg::Reference callback_;
};

// Implement the CallbackInternal interface for a native callback.
class NativeCallback : public MutationObserver::CallbackInternal {
 public:
  explicit NativeCallback(
      const MutationObserver::NativeMutationCallback& callback)
      : callback_(callback) {}
  bool RunCallback(const MutationObserver::MutationRecordSequence& mutations,
                   const scoped_refptr<MutationObserver>& observer) override {
    callback_.Run(mutations, observer);
    return true;
  }

 private:
  MutationObserver::NativeMutationCallback callback_;
};

}  // namespace

MutationObserver::MutationObserver(
    const NativeMutationCallback& native_callback,
    MutationObserverTaskManager* task_manager,
    base::DebuggerHooks* debugger_hooks)
    : task_manager_(task_manager), debugger_hooks_(debugger_hooks) {
  callback_.reset(new NativeCallback(native_callback));
  task_manager_->OnMutationObserverCreated(this);
}

MutationObserver::MutationObserver(script::EnvironmentSettings* settings,
                                   const MutationCallbackArg& callback)
    : task_manager_(base::polymorphic_downcast<DOMSettings*>(settings)
                        ->mutation_observer_task_manager()),
      debugger_hooks_(base::polymorphic_downcast<DOMSettings*>(settings)
                          ->debugger_hooks()) {
  callback_.reset(new ScriptCallback(callback, this));
  task_manager_->OnMutationObserverCreated(this);
}

MutationObserver::~MutationObserver() {
  task_manager_->OnMutationObserverDestroyed(this);
}

void MutationObserver::Observe(const scoped_refptr<Node>& target,
                               const MutationObserverInit& options) {
  NativeExceptionState exception_state;
  ObserveInternal(target, options, &exception_state);
}

void MutationObserver::Disconnect() {
  CancelDebuggerAsyncTasks();
  // The disconnect() method must, for each node in the context object's
  // list of nodes, remove any registered observer on node for which the context
  // object is the observer, and also empty context object's record queue.
  for (WeakNodeVector::iterator it = observed_nodes_.begin();
       it != observed_nodes_.end(); ++it) {
    dom::Node* node = it->get();
    if (node != NULL) {
      node->UnregisterMutationObserver(base::WrapRefCounted(this));
    }
  }
  observed_nodes_.clear();
  record_queue_.clear();
}

MutationObserver::MutationRecordSequence MutationObserver::TakeRecords() {
  CancelDebuggerAsyncTasks();
  // The takeRecords() method must return a copy of the record queue and then
  // empty the record queue.
  MutationRecordSequence record_queue;
  record_queue.swap(record_queue_);
  return record_queue;
}

void MutationObserver::QueueMutationRecord(
    const scoped_refptr<MutationRecord>& record) {
  TRACE_EVENT0("cobalt::dom", "MutationObserver::QueueMutationRecord()");
  record_queue_.push_back(record);
  task_manager_->QueueMutationObserverMicrotask();
  MutationRecord* task = record.get();
  debugger_hooks_->AsyncTaskScheduled(
      task, record->type().c_str(),
      base::DebuggerHooks::AsyncTaskFrequency::kOneshot);
}

bool MutationObserver::Notify() {
  TRACE_EVENT0("cobalt::dom", "MutationObserver::Notify()");
  // https://www.w3.org/TR/dom/#mutationobserver
  // Step 3 of "notify mutation observers" steps:
  //     1. Let queue be a copy of mo's record queue.
  //     2. Empty mo's record queue.
  MutationRecordSequence records;
  records.swap(record_queue_);

  //     3. Remove all transient registered observers whose observer is mo.
  // TODO: handle transient registered observers.

  //     4. If queue is non-empty, call mo's callback with queue as first
  //        argument, and mo (itself) as second argument and callback this
  //        value. If this throws an exception, report the exception.
  if (!records.empty()) {
    // Report the first (earliest) stack as the async cause.
    MutationRecord* task = records.begin()->get();
    base::ScopedAsyncTask async_task(debugger_hooks_, task);
    return callback_->RunCallback(records, base::WrapRefCounted(this));
  }
  // If no records, return true to indicate no error occurred.
  return true;
}

void MutationObserver::TraceMembers(script::Tracer* tracer) {
  tracer->TraceItems(observed_nodes_);
  tracer->TraceItems(record_queue_);
}

void MutationObserver::CancelDebuggerAsyncTasks() {
  for (auto record : record_queue_) {
    MutationRecord* task = record.get();
    debugger_hooks_->AsyncTaskCanceled(task);
  }
}

void MutationObserver::TrackObservedNode(const scoped_refptr<dom::Node>& node) {
  for (WeakNodeVector::iterator it = observed_nodes_.begin();
       it != observed_nodes_.end();) {
    if (it->get() == NULL) {
      it = observed_nodes_.erase(it);
      continue;
    }
    if (*it == node) {
      return;
    }
    ++it;
  }
  observed_nodes_.push_back(base::AsWeakPtr(node.get()));
}

void MutationObserver::ObserveInternal(
    const scoped_refptr<Node>& target, const MutationObserverInit& options,
    script::ExceptionState* exception_state) {
  if (!target) {
    // |target| is not nullable, so if this is NULL that indicates a bug in the
    // bindings layer.
    NOTREACHED();
    return;
  }
  if (!target->RegisterMutationObserver(base::WrapRefCounted(this), options)) {
    // This fails if the options are invalid.
    exception_state->SetSimpleException(script::kTypeError, "Invalid options.");
    return;
  }
  TrackObservedNode(target);
}

}  // namespace dom
}  // namespace cobalt
