// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#include "libcef/renderer/dom_document_impl.h"
#include "libcef/renderer/dom_node_impl.h"
#include "libcef/renderer/thread_util.h"

#include "base/logging.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_element.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_node.h"
#include "third_party/blink/public/web/web_range.h"

using blink::WebDocument;
using blink::WebElement;
using blink::WebLocalFrame;
using blink::WebNode;
using blink::WebRange;
using blink::WebString;
using blink::WebURL;

CefDOMDocumentImpl::CefDOMDocumentImpl(CefBrowserImpl* browser,
                                       WebLocalFrame* frame)
    : browser_(browser), frame_(frame) {
  const WebDocument& document = frame_->GetDocument();
  DCHECK(!document.IsNull());
}

CefDOMDocumentImpl::~CefDOMDocumentImpl() {
  CEF_REQUIRE_RT();

  // Verify that the Detach() method has been called.
  DCHECK(frame_ == nullptr);
}

CefDOMDocumentImpl::Type CefDOMDocumentImpl::GetType() {
  if (!VerifyContext())
    return DOM_DOCUMENT_TYPE_UNKNOWN;

  const WebDocument& document = frame_->GetDocument();
  if (document.IsHTMLDocument())
    return DOM_DOCUMENT_TYPE_HTML;
  if (document.IsXHTMLDocument())
    return DOM_DOCUMENT_TYPE_XHTML;
  if (document.IsPluginDocument())
    return DOM_DOCUMENT_TYPE_PLUGIN;
  return DOM_DOCUMENT_TYPE_UNKNOWN;
}

CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetDocument() {
  const WebDocument& document = frame_->GetDocument();
  return GetOrCreateNode(document.GetDocument());
}

CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetBody() {
  const WebDocument& document = frame_->GetDocument();
  return GetOrCreateNode(document.Body());
}

CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetHead() {
  WebDocument document = frame_->GetDocument();
  return GetOrCreateNode(document.Head());
}

CefString CefDOMDocumentImpl::GetTitle() {
  CefString str;
  if (!VerifyContext())
    return str;

  const WebDocument& document = frame_->GetDocument();
  const WebString& title = document.Title();
  if (!title.IsNull())
    str = title.Utf16();

  return str;
}

CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetElementById(const CefString& id) {
  const WebDocument& document = frame_->GetDocument();
  return GetOrCreateNode(
      document.GetElementById(WebString::FromUTF16(id.ToString16())));
}

CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetFocusedNode() {
  const WebDocument& document = frame_->GetDocument();
  return GetOrCreateNode(document.FocusedElement());
}

bool CefDOMDocumentImpl::HasSelection() {
  if (!VerifyContext())
    return false;

  return frame_->HasSelection();
}

int CefDOMDocumentImpl::GetSelectionStartOffset() {
  if (!VerifyContext())
    return 0;

  if (!frame_->HasSelection())
    return 0;

  const WebRange& range = frame_->SelectionRange();
  if (range.IsNull())
    return 0;

  return range.StartOffset();
}

int CefDOMDocumentImpl::GetSelectionEndOffset() {
  if (!VerifyContext())
    return 0;

  if (!frame_->HasSelection())
    return 0;

  const WebRange& range = frame_->SelectionRange();
  if (range.IsNull())
    return 0;

  return range.EndOffset();
}

CefString CefDOMDocumentImpl::GetSelectionAsMarkup() {
  CefString str;
  if (!VerifyContext())
    return str;

  if (!frame_->HasSelection())
    return str;

  const WebString& markup = frame_->SelectionAsMarkup();
  if (!markup.IsNull())
    str = markup.Utf16();

  return str;
}

CefString CefDOMDocumentImpl::GetSelectionAsText() {
  CefString str;
  if (!VerifyContext())
    return str;

  if (!frame_->HasSelection())
    return str;

  const WebString& text = frame_->SelectionAsText();
  if (!text.IsNull())
    str = text.Utf16();

  return str;
}

CefString CefDOMDocumentImpl::GetBaseURL() {
  CefString str;
  if (!VerifyContext())
    return str;

  const WebDocument& document = frame_->GetDocument();
  const WebURL& url = document.BaseURL();
  if (!url.IsNull()) {
    GURL gurl = url;
    str = gurl.spec();
  }

  return str;
}

CefString CefDOMDocumentImpl::GetCompleteURL(const CefString& partialURL) {
  CefString str;
  if (!VerifyContext())
    return str;

  const WebDocument& document = frame_->GetDocument();
  const WebURL& url =
      document.CompleteURL(WebString::FromUTF16(partialURL.ToString16()));
  if (!url.IsNull()) {
    GURL gurl = url;
    str = gurl.spec();
  }

  return str;
}

CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetOrCreateNode(
    const blink::WebNode& node) {
  if (!VerifyContext())
    return nullptr;

  // Nodes may potentially be null.
  if (node.IsNull())
    return nullptr;

  if (!node_map_.empty()) {
    // Locate the existing node, if any.
    NodeMap::const_iterator it = node_map_.find(node);
    if (it != node_map_.end())
      return it->second;
  }

  // Create the new node object.
  CefRefPtr<CefDOMNode> nodeImpl(new CefDOMNodeImpl(this, node));
  node_map_.insert(std::make_pair(node, nodeImpl.get()));
  return nodeImpl;
}

void CefDOMDocumentImpl::RemoveNode(const blink::WebNode& node) {
  if (!VerifyContext())
    return;

  if (!node_map_.empty()) {
    NodeMap::iterator it = node_map_.find(node);
    if (it != node_map_.end())
      node_map_.erase(it);
  }
}

void CefDOMDocumentImpl::Detach() {
  if (!VerifyContext())
    return;

  // If you hit this assert it means that you are keeping references to node
  // objects beyond the valid scope.
  DCHECK(node_map_.empty());

  // If you hit this assert it means that you are keeping references to this
  // document object beyond the valid scope.
  DCHECK(HasOneRef());

  if (!node_map_.empty()) {
    NodeMap::const_iterator it = node_map_.begin();
    for (; it != node_map_.end(); ++it)
      static_cast<CefDOMNodeImpl*>(it->second)->Detach();
    node_map_.clear();
  }

  frame_ = nullptr;
}

bool CefDOMDocumentImpl::VerifyContext() {
  if (!CEF_CURRENTLY_ON_RT() || frame_ == nullptr) {
    NOTREACHED();
    return false;
  }
  return true;
}
