// 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,
    const 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
