// Copyright 2015 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/cssom/selector_tree.h"

#include <set>

#include "cobalt/base/version_compatibility.h"
#include "cobalt/cssom/complex_selector.h"
#include "cobalt/cssom/compound_selector.h"
#include "cobalt/cssom/css_style_rule.h"

namespace cobalt {
namespace cssom {

bool SelectorTree::CompoundNodeLessThan::operator()(
    const CompoundSelector* lhs, const CompoundSelector* rhs) const {
  return *lhs < *rhs;
}

SelectorTree::Node::Node()
    : combinator_mask_(0),
      compound_selector_(NULL),
      selector_mask_(0),
      pseudo_class_mask_(0) {}

SelectorTree::Node::Node(CompoundSelector* compound_selector,
                         Specificity parent_specificity)
    : combinator_mask_(0),
      compound_selector_(compound_selector),
      cumulative_specificity_(parent_specificity),
      selector_mask_(0),
      pseudo_class_mask_(0) {
  cumulative_specificity_.AddFrom(compound_selector_->GetSpecificity());
}

void SelectorTree::AppendRule(CSSStyleRule* rule) {
  for (Selectors::const_iterator it = rule->selectors().begin();
       it != rule->selectors().end(); ++it) {
    DCHECK((*it)->AsComplexSelector());
    Node* node = GetOrCreateNodeForComplexSelector((*it)->AsComplexSelector());
    node->rules().push_back(base::AsWeakPtr(rule));
  }
}

void SelectorTree::RemoveRule(CSSStyleRule* rule) {
  for (Selectors::const_iterator it = rule->selectors().begin();
       it != rule->selectors().end(); ++it) {
    DCHECK((*it)->AsComplexSelector());
    Node* node = GetOrCreateNodeForComplexSelector((*it)->AsComplexSelector());
    for (Rules::iterator remove_it = node->rules().begin();
         remove_it != node->rules().end(); ++remove_it) {
      if (*remove_it == rule) {
        node->rules().erase(remove_it);
        break;
      }
    }
  }
}

const SelectorTree::OwnedNodes& SelectorTree::children(
    const Node* node, CombinatorType combinator) {
  return owned_nodes_map_[std::make_pair(node, combinator)];
}

namespace {

// This uses the old CompoundSelector compare logic that had a bug where 'not'
// pseudo classes with the same prefix would be treated as matching, regardless
// of their arguments.
struct PreVersion16CompoundSelectorLessThan {
  bool operator()(const CompoundSelector* lhs,
                  const CompoundSelector* rhs) const {
    const CompoundSelector::SimpleSelectors& lhs_simple_selectors =
        lhs->simple_selectors();
    const CompoundSelector::SimpleSelectors& rhs_simple_selectors =
        rhs->simple_selectors();
    if (lhs_simple_selectors.size() < rhs_simple_selectors.size()) {
      return true;
    }
    if (lhs_simple_selectors.size() > rhs_simple_selectors.size()) {
      return false;
    }

    for (size_t i = 0; i < lhs_simple_selectors.size(); ++i) {
      if (lhs_simple_selectors[i]->type() < rhs_simple_selectors[i]->type()) {
        return true;
      }
      if (lhs_simple_selectors[i]->type() > rhs_simple_selectors[i]->type()) {
        return false;
      }
      if (lhs_simple_selectors[i]->prefix() <
          rhs_simple_selectors[i]->prefix()) {
        return true;
      }
      if (lhs_simple_selectors[i]->prefix() >
          rhs_simple_selectors[i]->prefix()) {
        return false;
      }
      if (lhs_simple_selectors[i]->text() < rhs_simple_selectors[i]->text()) {
        return true;
      }
      if (lhs_simple_selectors[i]->text() > rhs_simple_selectors[i]->text()) {
        return false;
      }
    }

    return false;
  }
};

bool HasNotPseudoClassCompatibilityViolations(
    const SelectorTree::OwnedNodesMap& owned_nodes_map) {
  constexpr int kNotPseudoClassCobaltVersionFix = 16;
  if (base::VersionCompatibility::GetInstance()->GetMinimumVersion() >=
      kNotPseudoClassCobaltVersionFix) {
    return false;
  }

  typedef std::set<CompoundSelector*, PreVersion16CompoundSelectorLessThan>
      PreVersion16CompoundSelectorLessThanSet;

  // Walk all of the owned nodes looking for multiple compound selectors within
  // them that are treated as duplicates using the pre-version 16 compound
  // selector less than logic.
  PreVersion16CompoundSelectorLessThanSet unsupported_usage_set;
  for (const auto& owned_nodes_iterator : owned_nodes_map) {
    PreVersion16CompoundSelectorLessThanSet encountered_set;
    for (const auto& node_info : owned_nodes_iterator.second) {
      if (!encountered_set.insert(node_info.first).second) {
        unsupported_usage_set.insert(node_info.first);
      }
    }
  }

  // Log the cases of unsupported usage.
  for (const auto& unsupported_usage_iterator : unsupported_usage_set) {
    const std::string kUnsupportedNotUsageString =
        "Unsupported :not() pseudo class usage found. Multiple negation pseudo "
        "classes with the same prefix but different arguments are not "
        "supported in versions of Cobalt <= 15. Offending selectors: '";

    std::string selectors_string;
    const CompoundSelector::SimpleSelectors& simple_selectors =
        unsupported_usage_iterator->simple_selectors();
    for (const auto& simple_selector : simple_selectors) {
      selectors_string += simple_selector->prefix().c_str();
      if (simple_selector->type() == kPseudoClass &&
          simple_selector->GetContainedCompoundSelector() != NULL) {
        selectors_string += "not(...)";
      } else {
        selectors_string += simple_selector->text().c_str();
      }
    }

    base::VersionCompatibility::GetInstance()->ReportViolation(
        kUnsupportedNotUsageString + selectors_string);
  }
  return !unsupported_usage_set.empty();
}

}  // namespace

bool SelectorTree::ValidateVersionCompatibility() const {
  return !HasNotPseudoClassCompatibilityViolations(owned_nodes_map_);
}

SelectorTree::Node* SelectorTree::GetOrCreateNodeForComplexSelector(
    ComplexSelector* complex_selector) {
  CompoundSelector* selector = complex_selector->first_selector();
  Node* node = GetOrCreateNodeForCompoundSelector(selector, &root_node_,
                                                  kDescendantCombinator);

  while (selector->right_combinator()) {
    Combinator* combinator = selector->right_combinator();
    selector = combinator->right_selector();
    node = GetOrCreateNodeForCompoundSelector(selector, node,
                                              combinator->GetCombinatorType());
  }

  return node;
}

SelectorTree::Node* SelectorTree::GetOrCreateNodeForCompoundSelector(
    CompoundSelector* compound_selector, Node* parent_node,
    CombinatorType combinator) {
  if (combinator == kNextSiblingCombinator ||
      combinator == kFollowingSiblingCombinator) {
    has_sibling_combinators_ = true;
  }

  OwnedNodes& owned_nodes =
      owned_nodes_map_[std::make_pair(parent_node, combinator)];
  OwnedNodes::iterator child_node_it = owned_nodes.find(compound_selector);
  if (child_node_it != owned_nodes.end()) {
    return child_node_it->second;
  }
  Node* child_node =
      new Node(compound_selector, parent_node->cumulative_specificity());
  parent_node->combinator_mask_ |= (1 << combinator);
  owned_nodes[compound_selector] = child_node;

  (*compound_selector->simple_selectors().begin())
      ->IndexSelectorTreeNode(parent_node, child_node, combinator);
  return child_node;
}

}  // namespace cssom
}  // namespace cobalt
