/*
 * 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.
 */

#ifndef COBALT_DOM_TESTING_HTML_COLLECTION_TESTING_H_
#define COBALT_DOM_TESTING_HTML_COLLECTION_TESTING_H_

#include "cobalt/dom/document.h"
#include "cobalt/dom/element.h"
#include "cobalt/dom/html_collection.h"
#include "cobalt/dom/html_element.h"
#include "cobalt/dom/html_element_factory.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace cobalt {
namespace dom {
namespace testing {

// Given an empty node of a type T, test the functionality of
// T::GetElementsByClassName.
template <typename T>
void TestGetElementsByClassName(const scoped_refptr<T>& node);

// Given an empty node of a type T, test the functionality of
// T::GetElementsByTagName.
template <typename T>
void TestGetElementsByTagName(const scoped_refptr<T>& node);

/////////////////////////////////////////////////////////////////////////////
// Implementation
/////////////////////////////////////////////////////////////////////////////

template <typename T>
void TestGetElementsByClassName(const scoped_refptr<T>& node) {
  const scoped_refptr<Node> kNullNode;
  const scoped_refptr<HTMLCollection> kNullCollection;

  Document* document = node->node_document();

  if (!document) {
    document = node->AsDocument();
    DCHECK(document);
  }

  // Construct a tree:
  // node
  //   a1
  //     b1
  //       c1
  //   a2
  //     d1
  //     d2
  scoped_refptr<Node> a1 =
      node->AppendChild(new Element(document, base::Token("a1")));
  scoped_refptr<Node> a2 =
      node->AppendChild(new Element(document, base::Token("a2")));
  scoped_refptr<Node> b1 =
      a1->AppendChild(new Element(document, base::Token("b1")));
  scoped_refptr<Node> c1 =
      b1->AppendChild(new Element(document, base::Token("c1")));
  scoped_refptr<Node> d1 =
      a2->AppendChild(new Element(document, base::Token("d1")));
  scoped_refptr<Node> d2 =
      a2->AppendChild(new Element(document, base::Token("d2")));

  scoped_refptr<HTMLCollection> collection =
      node->GetElementsByClassName("class");

  // Start with an empty class.
  EXPECT_EQ(0, collection->length());

  // Set the matching class on all elements.
  a1->AsElement()->set_class_name("class");
  a2->AsElement()->set_class_name("class");
  b1->AsElement()->set_class_name("class");
  c1->AsElement()->set_class_name("class");
  d1->AsElement()->set_class_name("class");
  d2->AsElement()->set_class_name("class");

  EXPECT_EQ(6, collection->length());
  EXPECT_EQ(a1, collection->Item(0));
  EXPECT_EQ(b1, collection->Item(1));
  EXPECT_EQ(c1, collection->Item(2));
  EXPECT_EQ(a2, collection->Item(3));
  EXPECT_EQ(d1, collection->Item(4));
  EXPECT_EQ(d2, collection->Item(5));
  EXPECT_EQ(kNullNode, collection->Item(6));
  EXPECT_EQ(a1, collection->Item(0));

  // Modify the class name on some elements.
  a1->AsElement()->set_class_name("other_class");
  a2->AsElement()->set_class_name("other_class");
  b1->AsElement()->set_class_name("other_class");
  d1->AsElement()->set_class_name("other_class");

  EXPECT_EQ(2, collection->length());
  EXPECT_EQ(c1, collection->Item(0));
  EXPECT_EQ(d2, collection->Item(1));
  EXPECT_EQ(kNullNode, collection->Item(2));
  EXPECT_EQ(c1, collection->Item(0));

  // d1 is not matched by the collection so adding the id shouldn't change
  // anything.
  d1->AsElement()->set_id("id");
  EXPECT_EQ(kNullNode, collection->NamedItem("id"));

  // d2 is matched by the collection so adding the id should work.
  d2->AsElement()->set_id("id");
  EXPECT_EQ(d2, collection->NamedItem("id"));

  // Removing a2 should also remove its children from the collection, including
  // d2.
  node->RemoveChild(a2);
  EXPECT_EQ(1, collection->length());
  EXPECT_EQ(c1, collection->Item(0));
  EXPECT_EQ(kNullNode, collection->Item(1));
  EXPECT_EQ(kNullNode, collection->NamedItem("id"));

  c1->AsElement()->set_class_name("other_class");
  EXPECT_EQ(0, collection->length());
  EXPECT_EQ(kNullNode, collection->Item(0));

  // Test elements with multiple classes
  a1->AsElement()->set_class_name("class other_class");
  b1->AsElement()->set_class_name("class yet_another_class");
  c1->AsElement()->set_class_name("other_class yet_another_class");
  EXPECT_EQ(2, collection->length());
  EXPECT_EQ(a1, collection->Item(0));
  EXPECT_EQ(b1, collection->Item(1));
}

template <typename T>
void TestGetElementsByTagName(const scoped_refptr<T>& node) {
  const scoped_refptr<Node> kNullNode;
  const scoped_refptr<HTMLCollection> kNullCollection;
  Document* document = node->node_document();

  if (!document) {
    document = node->AsDocument();
    DCHECK(document);
  }

  // Construct a tree:
  // node
  //   a1
  //     b1
  //       c1
  //   a3
  //     d1
  HTMLElementFactory html_element_factory;
  html_element_factory.CreateHTMLElement(document, base::Token("a1"));

  scoped_refptr<Node> a1 = node->AppendChild(
      html_element_factory.CreateHTMLElement(document, base::Token("a1")));

  scoped_refptr<Node> a3 = node->AppendChild(
      html_element_factory.CreateHTMLElement(document, base::Token("a2")));
  scoped_refptr<Node> b1 = a1->AppendChild(
      html_element_factory.CreateHTMLElement(document, base::Token("b1")));
  scoped_refptr<Node> c1 = b1->AppendChild(
      html_element_factory.CreateHTMLElement(document, base::Token("tag")));
  scoped_refptr<Node> d1 = a3->AppendChild(
      html_element_factory.CreateHTMLElement(document, base::Token("tag")));

  // GetElementsByTagName should return all elements when provided with
  // parameter "*".
  scoped_refptr<HTMLCollection> collection = node->GetElementsByTagName("*");
  EXPECT_EQ(5, collection->length());
  EXPECT_EQ(a1, collection->Item(0));
  EXPECT_EQ(b1, collection->Item(1));
  EXPECT_EQ(c1, collection->Item(2));
  EXPECT_EQ(a3, collection->Item(3));
  EXPECT_EQ(d1, collection->Item(4));
  EXPECT_EQ(kNullNode, collection->Item(5));

  // GetElementsByTagName should only return elements with the specific tag name
  // when that is provided.
  collection = node->GetElementsByTagName("tag");
  EXPECT_EQ(2, collection->length());
  EXPECT_EQ(c1, collection->Item(0));
  EXPECT_EQ(d1, collection->Item(1));
  EXPECT_EQ(kNullNode, collection->Item(2));

  // a3 is not matched by the collection so adding the id shouldn't change
  // anything.
  a3->AsElement()->set_id("id");
  EXPECT_EQ(kNullNode, collection->NamedItem("id"));

  // d1 is matched by the collection so adding the id should work.
  d1->AsElement()->set_id("id");
  EXPECT_EQ(d1, collection->NamedItem("id"));

  // Add a new node with a matching tag.
  scoped_refptr<Node> a2 = node->InsertBefore(
      html_element_factory.CreateHTMLElement(document, base::Token("tag")), a3);
  EXPECT_EQ(3, collection->length());
  EXPECT_EQ(c1, collection->Item(0));
  EXPECT_EQ(a2, collection->Item(1));
  EXPECT_EQ(d1, collection->Item(2));
  EXPECT_EQ(kNullNode, collection->Item(3));

  // Removing a3 should also remove its children from the collection.
  node->RemoveChild(a3);
  EXPECT_EQ(2, collection->length());
  EXPECT_EQ(c1, collection->Item(0));
  EXPECT_EQ(a2, collection->Item(1));
  EXPECT_EQ(kNullNode, collection->Item(2));
  EXPECT_EQ(kNullNode, collection->NamedItem("id"));
}

}  // namespace testing
}  // namespace dom
}  // namespace cobalt

#endif  // COBALT_DOM_TESTING_HTML_COLLECTION_TESTING_H_
