// Copyright 2015 Google Inc. 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_parser/html_decoder.h"

#include "cobalt/csp/content_security_policy.h"
#include "cobalt/dom/csp_delegate.h"
#include "cobalt/dom_parser/libxml_html_parser_wrapper.h"
#include "cobalt/loader/net_fetcher.h"

namespace cobalt {
namespace dom_parser {

HTMLDecoder::HTMLDecoder(
    const scoped_refptr<dom::Document>& document,
    const scoped_refptr<dom::Node>& parent_node,
    const scoped_refptr<dom::Node>& reference_node,
    const int dom_max_element_depth, const base::SourceLocation& input_location,
    const base::Closure& done_callback,
    const base::Callback<void(const std::string&)>& error_callback,
    const bool should_run_scripts)
    : libxml_html_parser_wrapper_(new LibxmlHTMLParserWrapper(
          document, parent_node, reference_node, dom_max_element_depth,
          input_location, error_callback, should_run_scripts)),
      document_(document),
      done_callback_(done_callback),
      should_run_scripts_(should_run_scripts) {}

HTMLDecoder::~HTMLDecoder() {}

loader::LoadResponseType HTMLDecoder::OnResponseStarted(
    loader::Fetcher* fetcher,
    const scoped_refptr<net::HttpResponseHeaders>& headers) {
  DCHECK(headers);
  // Only NetFetchers can call this, since only they have
  // the response headers.
  loader::NetFetcher* net_fetcher =
      base::polymorphic_downcast<loader::NetFetcher*>(fetcher);
  net::URLFetcher* url_fetcher = net_fetcher->url_fetcher();
  if (url_fetcher->GetURL() != url_fetcher->GetOriginalURL()) {
    document_->NotifyUrlChanged(url_fetcher->GetURL());
  }

  if (headers->HasHeaderValue("cobalt-jit", "disable")) {
    document_->DisableJit();
  } else if (headers->HasHeader("cobalt-jit")) {
    std::string value;
    headers->GetNormalizedHeader("cobalt-jit", &value);
    LOG(WARNING) << "Invalid value for \"cobalt-jit\" header: " << value;
  }

  csp::ResponseHeaders csp_headers(headers);
  if (document_->csp_delegate()->OnReceiveHeaders(csp_headers)) {
    return loader::kLoadResponseContinue;
  } else {
    DLOG(ERROR) << "Failure receiving Content Security Policy headers";
    return loader::kLoadResponseAbort;
  }
}

void HTMLDecoder::DecodeChunk(const char* data, size_t size) {
  DCHECK(thread_checker_.CalledOnValidThread());
  libxml_html_parser_wrapper_->DecodeChunk(data, size);
}

void HTMLDecoder::Finish() {
  DCHECK(thread_checker_.CalledOnValidThread());
  libxml_html_parser_wrapper_->Finish();
  if (!done_callback_.is_null()) {
    done_callback_.Run();
  }
}

}  // namespace dom_parser
}  // namespace cobalt
