// Copyright 2014 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/cssom/css_rule_list.h"

#include <limits>

#include "base/logging.h"
#include "cobalt/cssom/css_parser.h"
#include "cobalt/cssom/css_rule.h"
#include "cobalt/cssom/css_rule_visitor.h"
#include "cobalt/cssom/css_style_rule.h"
#include "cobalt/cssom/css_style_sheet.h"

namespace cobalt {
namespace cssom {

CSSRuleList::CSSRuleList() : parent_css_style_sheet_(NULL) {}

unsigned int CSSRuleList::length() const {
  CHECK_LE(css_rules_.size(), std::numeric_limits<unsigned int>::max());
  return static_cast<unsigned int>(css_rules_.size());
}

scoped_refptr<CSSRule> CSSRuleList::Item(unsigned int index) const {
  return index < css_rules_.size() ? css_rules_[index] : NULL;
}

unsigned int CSSRuleList::InsertRule(const std::string& rule,
                                     unsigned int index) {
  // TODO: Currently we only support appending rule to the end of the rule
  // list. Properly implement insertion if necessary.
  DCHECK(parent_css_style_sheet_);
  scoped_refptr<CSSRule> css_rule =
      parent_css_style_sheet_->css_parser()->ParseRule(
          rule, GetInlineSourceLocation());

  if (css_rule == NULL) {
    // TODO: Throw a SyntaxError exception instead of logging.
    LOG(ERROR) << "SyntaxError";
    return 0;
  }

  if (index > css_rules_.size()) {
    // TODO: Throw a IndexSizeError exception instead of logging.
    LOG(ERROR) << "IndexSizeError";
    return 0;
  }

  if (index != css_rules_.size()) {
    LOG(WARNING) << "InsertRule will always append the rule to the end of the "
                    "rule list.";
  }

  AppendCSSRule(css_rule);
  return index;
}

void CSSRuleList::AttachToCSSStyleSheet(CSSStyleSheet* style_sheet) {
  DCHECK(style_sheet);
  parent_css_style_sheet_ = style_sheet;
  for (CSSRules::iterator it = css_rules_.begin(); it != css_rules_.end();
       ++it) {
    DCHECK(*it);
    (*it)->AttachToCSSStyleSheet(style_sheet);
  }
}

void CSSRuleList::AppendCSSRule(const scoped_refptr<CSSRule>& css_rule) {
  if (parent_css_style_sheet_) {
    css_rule->AttachToCSSStyleSheet(parent_css_style_sheet_);
    parent_css_style_sheet_->OnCSSMutation();
  }
  css_rule->set_index(static_cast<int>(css_rules_.size()));
  css_rules_.push_back(css_rule);
}

void CSSRuleList::Accept(CSSRuleVisitor* visitor) {
  for (CSSRules::const_iterator it = css_rules_.begin(); it != css_rules_.end();
       ++it) {
    (*it)->Accept(visitor);
  }
}

CSSRuleList::~CSSRuleList() {}

}  // namespace cssom
}  // namespace cobalt
