/*
 * Copyright 2016 Google Inc.
 *
 * 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.
 */

// Author: morlovich@google.com (Maksim Orlovich)
//
// Contains special slots that help rewrite images inside srcset attributes.

#include "net/instaweb/rewriter/public/srcset_slot.h"

#include <vector>

#include "net/instaweb/rewriter/public/common_filter.h"
#include "net/instaweb/rewriter/public/resource.h"
#include "net/instaweb/rewriter/public/resource_slot.h"
#include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "pagespeed/kernel/base/ref_counted_ptr.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/html/html_element.h"
#include "pagespeed/kernel/http/google_url.h"

namespace net_instaweb {

SrcSetSlotCollection::SrcSetSlotCollection(
    RewriteDriver* driver, HtmlElement* element,
    HtmlElement::Attribute* attribute)
    : driver_(driver), element_(element), attribute_(attribute),
      filter_(nullptr),
      // Note: these need to be deep-copied in case we run as a detached
      // rewrite, in which case element_ may be dead.
      begin_line_number_(element->begin_line_number()),
      end_line_number_(element->end_line_number()) {
}

void SrcSetSlotCollection::Initialize(CommonFilter* filter) {
  filter_ = filter;

  StringPiece input(attribute_->DecodedValueOrNull());
  ParseSrcSet(input, &candidates_);

  for (int i = 0, n = candidates_.size(); i < n; ++i) {
    GoogleString url = candidates_[i].url;
    if (!url.empty()) {
      // TODO(morlovich): Different filters may different policy wrt to
      // inlining unknown; make it explicit somewhere that this relies on
      // them being consistent about it if shared between filters.
      ResourcePtr resource(filter->CreateInputResourceOrInsertDebugComment(
          candidates_[i].url, RewriteDriver::InputRole::kImg, element_));
      if (resource.get() != nullptr) {
        candidates_[i].slot.reset(new SrcSetSlot(resource, this, i));
      }
    }
  }
}

void SrcSetSlotCollection::ParseSrcSet(
    StringPiece input, std::vector<ImageCandidate>* out) {
  out->clear();

  // ref: https://html.spec.whatwg.org/multipage/embedded-content.html#parse-a-srcset-attribute
  while (true) {
    // Strip leading whitespace, commas.
    while (!input.empty() &&
           (IsHtmlSpace(input[0]) || input[0] == ',')) {
      input.remove_prefix(1);
    }

    if (input.empty()) {
      break;
    }

    // Find where the URL ends --- it's WS terminated.
    stringpiece_ssize_type url_end = input.find_first_of(" \f\n\r\t");
    StringPiece url;

    if (url_end == StringPiece::npos) {
      url = input;
      input = StringPiece();
    } else {
      url = input.substr(0, url_end);
      input = input.substr(url_end);
    }

    // URL may have trailing commas, which also means there is no
    // descriptor.
    bool expect_descriptor = true;
    while (url.ends_with(",")) {
      url.remove_suffix(1);
      expect_descriptor = false;
    }

    StringPiece descriptor;
    if (expect_descriptor) {
      bool inside_paren = false;
      int pos, n;
      for (pos = 0, n = input.size(); pos < n; ++pos) {
        if (input[pos] == '(') {
          inside_paren = true;
        } else if (input[pos] == ')' && inside_paren) {
          inside_paren = false;
        } else if (input[pos] == ',' && !inside_paren) {
          break;
        }
      }
      descriptor = input.substr(0, pos);
      input = input.substr(pos);
      TrimWhitespace(&descriptor);
    }

    ImageCandidate cand;
    url.CopyToString(&cand.url);
    descriptor.CopyToString(&cand.descriptor);
    out->push_back(cand);
  }
}

GoogleString SrcSetSlotCollection::Serialize(
    const std::vector<ImageCandidate>& in) {
  GoogleString result;
  for (int i = 0, n = in.size(); i < n; ++i) {
    if (i != 0) {
      StrAppend(&result, ", ");
    }
    StrAppend(&result, in[i].url);
    if (!in[i].descriptor.empty()) {
      StrAppend(&result, " ", in[i].descriptor);
    }
  }
  return result;
}

void SrcSetSlotCollection::Commit() {
  // Note that if slots don't want to render, they simply end up not changing
  // things in candidates_
  attribute_->SetValue(Serialize(candidates_));
}

SrcSetSlot::SrcSetSlot(const ResourcePtr& resource,
                       SrcSetSlotCollection* parent,
                       int index)
    : ResourceSlot(resource), parent_(parent), index_(index),
      url_relativity_(
          GoogleUrl::FindRelativity(parent_->url(index))) {
}

SrcSetSlot::~SrcSetSlot() {}

void SrcSetSlot::Render() {
  if (disable_rendering() || preserve_urls()) {
    return;
  }

  parent_->set_url(
      index_,
      RelativizeOrPassthrough(
          parent_->driver()->options(), resource()->url(),
          url_relativity_, parent_->driver()->base_url()));
  parent_->Commit();
}

GoogleString SrcSetSlot::LocationString() const {
  GoogleString loc = StrCat(parent_->driver()->id(), ":",
                            IntegerToString(parent_->begin_line_number()));
  if (parent_->end_line_number() != parent_->begin_line_number()) {
    StrAppend(&loc, "-", IntegerToString(parent_->end_line_number()));
  }

  StrAppend(&loc, " srcset entry for ", parent_->descriptor(index_));
  return loc;
}

bool SrcSetSlotCollectionComparator::operator()(
    const SrcSetSlotCollectionPtr& p, const SrcSetSlotCollectionPtr& q) const {
  // Note: The ordering depends on pointer comparison and so is arbitrary
  // and non-deterministic.
  if (p->element() < q->element()) {
    return true;
  } else if (p->element() > q->element()) {
    return false;
  }
  return (p->attribute() < q->attribute());
}

}  // namespace net_instaweb
