// Copyright 2021 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/performance_observer.h"

#include <unordered_set>

#include "cobalt/base/polymorphic_downcast.h"
#include "cobalt/dom/dom_settings.h"
#include "cobalt/dom/performance.h"
#include "cobalt/dom/performance_entry.h"
#include "cobalt/dom/window.h"
#include "cobalt/web/dom_exception.h"

namespace cobalt {
namespace dom {

namespace {
// Implement the CallbackInternal interface for a JavaScript callback.
class ScriptCallback : public PerformanceObserver::CallbackInternal {
 public:
  ScriptCallback(
      const PerformanceObserver::PerformanceObserverCallbackArg& callback,
      PerformanceObserver* observer)
      : callback_(observer, callback) {}
  bool RunCallback(
      const scoped_refptr<PerformanceObserverEntryList>& entries,
      const scoped_refptr<PerformanceObserver>& observer) override {
    // ScriptCallback's lifetime is bined with JS PerformanceObserver object. We
    // should not run callback, When JS object has been destroyed.
    if (callback_.referenced_value().IsNull()) return false;
    script::CallbackResult<void> result =
        callback_.value().Run(entries, observer);
    return !result.exception;
  }

 private:
  PerformanceObserver::PerformanceObserverCallbackArg::Reference callback_;
};

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

 private:
  PerformanceObserver::NativePerformanceObserverCallback callback_;
};

}  // namespace

PerformanceObserver::PerformanceObserver(
    const NativePerformanceObserverCallback& native_callback,
    const scoped_refptr<Performance>& performance)
    : performance_(base::AsWeakPtr(performance.get())),
      observer_type_(PerformanceObserverType::kUndefined),
      is_registered_(false) {
  callback_.reset(new NativeCallback(native_callback));
}

PerformanceObserver::PerformanceObserver(
    script::EnvironmentSettings* env_settings,
    const PerformanceObserverCallbackArg& callback)
    : performance_(
          base::AsWeakPtr(base::polymorphic_downcast<DOMSettings*>(env_settings)
                              ->window()
                              ->performance()
                              .get())),
      observer_type_(PerformanceObserverType::kUndefined),
      is_registered_(false) {
  callback_.reset(new ScriptCallback(callback, this));
}

PerformanceObserver::~PerformanceObserver() {}

void PerformanceObserver::Observe(const PerformanceObserverInit& options,
                                  script::ExceptionState* exception_state) {
  // The algorithm for registering the observer.
  //   https://www.w3.org/TR/2019/WD-performance-timeline-2-20191024/#observe-method
  // 1.  Let observer be the context object.
  // 2.  Let relevantGlobal be observer's relevant global object.
  if (!performance_) {
    return;
  }
  // 3.  If options's entryTypes and type members are both omitted, then throw
  // a SyntaxError.
  bool has_entry_types = options.has_entry_types();
  bool has_type = options.has_type();
  if (!has_entry_types && !has_type) {
    web::DOMException::Raise(web::DOMException::kSyntaxErr, exception_state);
  }
  // 4.  If options's entryTypes is present and any other member is also
  // present, then throw a SyntaxError.
  bool entry_types_present = has_entry_types && !options.entry_types().empty();
  bool type_present = has_type && !options.type().empty();
  if (entry_types_present && type_present) {
    web::DOMException::Raise(web::DOMException::kSyntaxErr, exception_state);
  }
  // 5.  Update or check observer's observer type by running these steps:
  // 5.1   If observer's observer type is "undefined":
  if (observer_type_ == PerformanceObserverType::kUndefined) {
    // 5.1.1  If options's entryTypes member is present, then set observer's
    // observer type to "multiple".
    if (entry_types_present) {
      observer_type_ = PerformanceObserverType::kMultiple;
    }
    // 5.1.2  If options's type member is present, then set observer's
    // observer type to "single".
    if (type_present) {
      observer_type_ = PerformanceObserverType::kSingle;
    }
  }
  // 5.2  If observer's observer type is "single" and options's entryTypes
  // member is present, then throw an InvalidModificationError.
  if (observer_type_ == PerformanceObserverType::kSingle &&
      entry_types_present) {
    web::DOMException::Raise(web::DOMException::kInvalidModificationErr,
                             exception_state);
  }
  // 5.3  If observer's observer type is "multiple" and options's type member
  // is present, then throw an InvalidModificationError.
  if (observer_type_ == PerformanceObserverType::kMultiple && type_present) {
    web::DOMException::Raise(web::DOMException::kInvalidModificationErr,
                             exception_state);
  }
  // 6  If observer's observer type is "multiple", run the following steps:
  if (observer_type_ == PerformanceObserverType::kMultiple) {
    // 6.1  Let entry types be options's entryTypes sequence.
    script::Sequence<std::string> entry_types;
    // 6.2  Remove all types from entry types that are not contained in
    // relevantGlobal's frozen array of supported entry types. The user agent
    // SHOULD notify developers if entry types is modified. For example, a
    // console warning listing removed types might be appropriate.
    for (const auto& entry_type_string : options.entry_types()) {
      PerformanceEntryType entry_type =
          PerformanceEntry::ToEntryTypeEnum(entry_type_string);
      if (entry_type != PerformanceEntry::kInvalid) {
        entry_types.push_back(entry_type_string);
      } else {
        DLOG(WARNING) << "The entry type " + entry_type_string +
                             " does not exist or isn't supported.";
      }
    }
    // 6.3  If the resulting entry types sequence is an empty sequence,
    // abort these steps. The user agent SHOULD notify developers when the
    // steps are aborted to notify that registration has been aborted.
    // For example, a console warning might be appropriate.
    if (entry_types.empty()) {
      DLOG(WARNING) << "An observe() call must include either entryTypes.";
      return;
    }
    // 6.4  If the list of registered performance observer objects of
    // relevantGlobal contains a registered performance observer whose
    // observer is the context object, replace its options list with a list
    // containing options as its only item.
    if (is_registered_) {
      performance_->ReplaceRegisteredPerformanceObserverOptionsList(
          base::WrapRefCounted(this), options);
      // 6.5  Otherwise, create and append a registered performance observer
      // object to the list of registered performance observer objects of
      // relevantGlobal, with observer set to the context object and options
      // list set to a list containing options as its only item.
    } else {
      performance_->RegisterPerformanceObserver(base::WrapRefCounted(this),
                                                options);
      is_registered_ = true;
    }
    // 7.  Otherwise, run the following steps:
  } else {
    // 7.1  Assert that observer's observer type is "single".
    DCHECK(observer_type_ == PerformanceObserverType::kSingle);
    // 7.2  If options's type is not contained in the relevantGlobal's frozen
    // array of supported entry types, abort these steps. The user agent SHOULD
    // notify developers when this happens, for instance via a console warning.
    PerformanceEntryType options_type =
        PerformanceEntry::ToEntryTypeEnum(options.type());
    if (options_type == PerformanceEntry::kInvalid) {
      DLOG(WARNING) << "The type " + options.type() +
                           " does not exist or isn't supported.";
      return;
    }
    // 7.3  If the list of registered performance observer objects of
    // relevantGlobal contains a registered performance observer obs whose
    // observer is the context object:
    if (is_registered_) {
      // 7.3.1  If obs's options list contains a PerformanceObserverInit item
      // currentOptions whose type is equal to options's type, replace
      // currentOptions with options in obs's options list.
      // 7.3.2  Otherwise, append options to obs's options list.
      performance_->UpdateRegisteredPerformanceObserverOptionsList(
          base::WrapRefCounted(this), options);
      // 7.4  Otherwise, create and append a registered performance observer
      // object to the list of registered performance observer objects of
      // relevantGlobal, with observer set to the context object and options
      // list set to a list containing options as its only item.
    } else {
      performance_->RegisterPerformanceObserver(base::WrapRefCounted(this),
                                                options);
      is_registered_ = true;
    }
  }
}

void PerformanceObserver::Observe(script::ExceptionState* exception_state) {
  PerformanceObserverInit options;
  Observe(options, exception_state);
}

void PerformanceObserver::Disconnect() {
  // The disconnect() method must remove the context object from the list of
  // registered performance observer objects of relevant global object, and
  // also empty context object's observer buffer.
  //   https://www.w3.org/TR/2019/WD-performance-timeline-2-20191024/#disconnect-method
  if (performance_) {
    performance_->UnregisterPerformanceObserver(base::WrapRefCounted(this));
  }
  observer_buffer_.clear();
  is_registered_ = false;
}

PerformanceEntryList PerformanceObserver::TakeRecords() {
  // The takeRecords() method must return a copy of the context object's
  // observer buffer, and also empty context object's observer buffer.
  //   https://www.w3.org/TR/2019/WD-performance-timeline-2-20191024/#takerecords-method
  PerformanceEntryList performance_entries;
  performance_entries.swap(observer_buffer_);
  return performance_entries;
}

script::Sequence<std::string> PerformanceObserver::supported_entry_types() {
  // Each global object has an associated frozen array of supported entry
  // types, which is initialized to the FrozenArray created from the
  // sequence of strings among the registry that are supported for the
  // global object, in alphabetical order.
  //   https://www.w3.org/TR/2019/WD-performance-timeline-2-20191024/#supportedentrytypes-attribute
  // TODO: Implement the 'Time Entry Names Registry'.
  //   // https://w3c.github.io/timing-entrytypes-registry/#registry
  // When supportedEntryTypes's attribute getter is called, run the
  // following steps:
  // 1.  Let globalObject be the environment settings object's global object.
  script::Sequence<std::string> supported_entry_type_list;
  for (size_t i = 0; i < arraysize(PerformanceEntry::kEntryTypeString); ++i) {
    const char* entry_type = PerformanceEntry::kEntryTypeString[i];
    if (!base::LowerCaseEqualsASCII("invalid", entry_type)) {
      std::string entry_type_string(entry_type);
      supported_entry_type_list.push_back(entry_type_string);
    }
  }

  // 2.  Return globalObject's frozen array of supported entry types.
  return supported_entry_type_list;
}

void PerformanceObserver::EnqueuePerformanceEntry(
    const scoped_refptr<PerformanceEntry>& entry) {
  observer_buffer_.push_back(entry);
}

void PerformanceObserver::TraceMembers(script::Tracer* tracer) {
  tracer->TraceItems(observer_buffer_);
}

}  // namespace dom
}  // namespace cobalt
