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