/*
 * Copyright 2006 Takahiro Nakamura.
 *
 * 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.
 */
package woolpack.html;

import java.util.Arrays;

import junit.framework.TestCase;

import org.w3c.dom.Node;

import woolpack.adapter.JXP;
import woolpack.el.PathEL;
import woolpack.fn.Fn;
import woolpack.fn.FnUtils;
import woolpack.fn.NullFn;
import woolpack.utils.Utils;
import woolpack.xml.MapNodeContext;
import woolpack.xml.NodeContext;
import woolpack.xml.SimpleNodeContext;
import woolpack.xml.XmlUtils;

public class HtmlUtilsTest extends TestCase {
	
	public void testBranchPropertyCount() {
		final Fn<NodeContext, Void> expression = XmlUtils.findNode(
				new JXP("//*[@id]"),
				HtmlUtils.branchPropertyCount(
					new PathEL("map.tmpCounter"),
					Arrays.asList("id"),
					XmlUtils.replaceTextToChild(FnUtils.fix("0")),
					XmlUtils.replaceTextToChild(FnUtils.fix("1"))));
		final MapNodeContext context = new MapNodeContext();
		context.setNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SPAN id=\"name0\">value00</SPAN>"
				+ "<SPAN id=\"name1\">value10</SPAN>"
				+ "<SPAN id=\"name0\">value01</SPAN>"
				+ "</BODY></HTML>"));
		context.setMap(Utils.map("map0", Utils.linkedMap("v0", "l0").map("v1", "l1")));
		
		expression.exec(context);
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SPAN id=\"name0\">0</SPAN>"
				+ "<SPAN id=\"name1\">0</SPAN>"
				+ "<SPAN id=\"name0\">1</SPAN>"
				+ "</BODY></HTML>"), context.getNode()));
	}

	public void testConvertRowAttr() {
		final Node node = XmlUtils.convert(
				"<HTML><BODY>"
				+ "<TABLE>"
				+ "<TR><TD>0-0</TD><TD>0-1</TD><TD>0-2</TD></TR>"
				+ "<TR><TD>1-0</TD><TD>1-1</TD><TD>1-2</TD></TR>"
				+ "<TR><TD>2-0</TD><TD>2-1</TD><TD>2-2</TD></TR>"
				+ "<TR><TD>3-0</TD><TD>3-1</TD><TD>3-2</TD></TR>"
				+ "</TABLE>"
				+ "</BODY></HTML>");
		final NodeContext context = new SimpleNodeContext();
		context.setNode(node.getFirstChild().getFirstChild().getFirstChild());
		HtmlUtils.convertRowAttr("class", new String[]{"a", "b", "c"}).exec(context);
		node.normalize();
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<TABLE>"
				+ "<TR class=\"a\"><TD>0-0</TD><TD>0-1</TD><TD>0-2</TD></TR>"
				+ "<TR class=\"b\"><TD>1-0</TD><TD>1-1</TD><TD>1-2</TD></TR>"
				+ "<TR class=\"c\"><TD>2-0</TD><TD>2-1</TD><TD>2-2</TD></TR>"
				+ "<TR class=\"a\"><TD>3-0</TD><TD>3-1</TD><TD>3-2</TD></TR>"
				+ "</TABLE>"
				+ "</BODY></HTML>"), node));
	}

	public void testNormalizeCase() {
		final NodeContext context = new SimpleNodeContext();
		context.setNode(XmlUtils.convert(
				"<html><BODY>"
				+ "<sPaN attra=\"valuea\" ATTRB=\"VALUEB\" attrC=\"valueC\" attrd=\"valued\" ATTRE=\"VALUEE\" attrF=\"valueF\">aBcD</sPaN>"
				+ "<SPAN attrg=\"valueg\" ATTRH=\"VALUEH\" attrI=\"valueI\" attrj=\"valuej\" ATTRK=\"VALUEK\" attrL=\"valueL\">aBcD</SPAN>"
				+ "</BODY></html>"));
		
		HtmlUtils.NORMALIZE_CASE.exec(context);
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SPAN attra=\"valuea\" attrb=\"VALUEB\" attrc=\"valueC\" attrd=\"valued\" attre=\"VALUEE\" attrf=\"valueF\">aBcD</SPAN>"
				+ "<SPAN attrg=\"valueg\" attrh=\"VALUEH\" attri=\"valueI\" attrj=\"valuej\" attrk=\"VALUEK\" attrl=\"valueL\">aBcD</SPAN>"
				+ "</BODY></HTML>"), context.getNode()));
	}

	public void testRemoveComment() {
		final NodeContext context = new SimpleNodeContext();
		context.setNode(XmlUtils.convert(
				"<HTML><BODY><SCRIPT><!-- var a = 1;  --></SCRIPT>hoge<!-- naru -->piyo</BODY></HTML>"));
		
		HtmlUtils.REMOVE_COMMENT.exec(context);
		context.getNode().normalize();
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY><SCRIPT><!-- var a = 1;  --></SCRIPT>hogepiyo</BODY></HTML>"), context.getNode()));
	}

	public void testCompressSpace() {
		final NodeContext context = new SimpleNodeContext();
		context.setNode(XmlUtils.convert(
				"<HTML><BODY><SCRIPT><!--   --></SCRIPT> \t\r\nhoge\t\r\n piyo\r\n \tnaru\n  \t\t</BODY></HTML>"));
		
		HtmlUtils.COMPRESS_SPACE.exec(context);
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY><SCRIPT><!--   --></SCRIPT> hoge piyo naru </BODY></HTML>"), context.getNode()));
	}
	
	public void testHiddenAllToChild() {
		final Fn<NodeContext, Void> expression = HtmlUtils.hiddenAllToChild(new PathEL("map"), Arrays.asList("name2"));
		final MapNodeContext context = new MapNodeContext();
		final Node node = XmlUtils.convert("<HTML><BODY><FORM>"+ "</FORM></BODY></HTML>");
		context.setNode(node.getFirstChild().getFirstChild().getFirstChild());
		context.setMap(Utils
				.map("name0", (Object) "value0")
				.map("name1", Arrays.asList("value10", "value11"))
				.map("name2", "value2"));
		expression.exec(context);
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY><FORM>"
				+ "<INPUT type=\"hidden\" name=\"name0\" value=\"value0\" />"
				+ "<INPUT type=\"hidden\" name=\"name1\" value=\"value10\" />"
				+ "<INPUT type=\"hidden\" name=\"name1\" value=\"value11\" />"
				+ "</FORM></BODY></HTML>"), node));
	}

	public void testInsertRowIndex() {
		final Node node = XmlUtils.convert(
				"<HTML><BODY>"
				+ "<TABLE>"
				+ "<TR><TD>0-0</TD><TD>0-1</TD><TD>0-2</TD></TR>"
				+ "<TR><TD>1-0</TD><TD>1-1</TD><TD>1-2</TD></TR>"
				+ "<TR><TD>2-0</TD><TD>2-1</TD><TD>2-2</TD></TR>"
				+ "<TR><TD>3-0</TD><TD>3-1</TD><TD>3-2</TD></TR>"
				+ "</TABLE>"
				+ "</BODY></HTML>");
		final NodeContext context = new SimpleNodeContext();
		context.setNode(node.getFirstChild().getFirstChild().getFirstChild());
		HtmlUtils.insertRowIndex("#").exec(context);
		node.normalize();
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<TABLE>"
				+ "<TR><TD>#</TD><TD>0-0</TD><TD>0-1</TD><TD>0-2</TD></TR>"
				+ "<TR><TD>1</TD><TD>1-0</TD><TD>1-1</TD><TD>1-2</TD></TR>"
				+ "<TR><TD>2</TD><TD>2-0</TD><TD>2-1</TD><TD>2-2</TD></TR>"
				+ "<TR><TD>3</TD><TD>3-0</TD><TD>3-1</TD><TD>3-2</TD></TR>"
				+ "</TABLE>"
				+ "</BODY></HTML>"), node));
	}

	public void testMakeRadio() {
		final Fn<NodeContext, Void> expression = XmlUtils.findNode(
				new JXP("name", "name1"),
				HtmlUtils.makeRadio(new PathEL("map.map0")));
		final MapNodeContext context = new MapNodeContext();
		context.setNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SPAN>"
				+ "<INPUT type=\"radio\" name=\"name1\" value=\"value\" />label"
				+ "</SPAN>"
				+ "</BODY></HTML>"));
		context.setMap(Utils.map("map0", Utils.linkedMap("v0", "l0").map("v1", "l1")));
		
		expression.exec(context);
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SPAN>"
				+ "<INPUT type=\"radio\" name=\"name1\" value=\"v0\" />l0"
				+ "<INPUT type=\"radio\" name=\"name1\" value=\"v1\" />l1"
				+ "</SPAN>"
				+ "</BODY></HTML>"), context.getNode()));
	}

	public void testMakeRadioNotFound() {
		final Fn<NodeContext, Void> expression = XmlUtils.findNode(
				new JXP("name", "name1"),
				HtmlUtils.makeRadio(new PathEL("map.map0")));
		final MapNodeContext context = new MapNodeContext();
		context.setNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SPAN>"
				+ "<INPUT type=\"radio\" name=\"name1\" value=\"value\" />label"
				+ "</SPAN>"
				+ "</BODY></HTML>"));
		context.setMap(Utils.map("map1", Utils.map("v0", "l0").map("v1", "l1")));
		
		expression.exec(context);
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SPAN>"
				+ "<INPUT type=\"radio\" name=\"name1\" value=\"value\" />label"
				+ "</SPAN>"
				+ "</BODY></HTML>"), context.getNode()));
	}

	public void testMakeSelectChild() {
		final Fn<NodeContext, Void> expression = XmlUtils.findNode(
				new JXP("name", "name1"),
				HtmlUtils.makeSelect(new PathEL("map.map0")));
		final MapNodeContext context = new MapNodeContext();
		context.setNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SELECT name=\"name1\" >"
				+ "<OPTION value=\"value0\">label0</OPTION>"
				+ "<OPTION value=\"value1\" />label1"
				+ "<OPTION value=\"value2\">label2</OPTION>"
				+ "</SELECT>"
				+ "</BODY></HTML>"));
		context.setMap(Utils.map("map0", Utils.linkedMap("v0", "l0").map("v1", "l1")));
		
		expression.exec(context);
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SELECT name=\"name1\" >"
				+ "<OPTION value=\"v0\">l0</OPTION>"
				+ "<OPTION value=\"v1\">l1</OPTION>"
				+ "</SELECT>"
				+ "</BODY></HTML>"), context.getNode()));
	}

	public void testMakeSelectNotFound() {
		final Fn<NodeContext, Void> expression = XmlUtils.findNode(
				new JXP("name", "name1"),
				HtmlUtils.makeSelect(new PathEL("map.map0")));
		final MapNodeContext context = new MapNodeContext();
		context.setNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SELECT name=\"name1\" >"
				+ "<OPTION value=\"value0\">label0</OPTION>"
				+ "<OPTION value=\"value1\" />label1"
				+ "<OPTION value=\"value2\">label2</OPTION>"
				+ "</SELECT>"
				+ "</BODY></HTML>"));
		context.setMap(Utils.map("map1", Utils.linkedMap("v0", "l0").map("v1", "l1")));
		
		expression.exec(context);
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SELECT name=\"name1\" >"
				+ "<OPTION value=\"value0\">label0</OPTION>"
				+ "<OPTION value=\"value1\" />label1"
				+ "<OPTION value=\"value2\">label2</OPTION>"
				+ "</SELECT>"
				+ "</BODY></HTML>"), context.getNode()));
	}

	public void testMakeSelectSibling() {
		final Fn<NodeContext, Void> expression = XmlUtils.findNode(
				new JXP("name", "name1"),
				HtmlUtils.makeSelect(new PathEL("map.map0")));
		final MapNodeContext context = new MapNodeContext();
		context.setNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SELECT name=\"name1\" >"
				+ "<OPTION value=\"value0\" />label0"
				+ "<OPTION value=\"value1\">label1</OPTION>"
				+ "<OPTION value=\"value2\" />label2"
				+ "</SELECT>"
				+ "</BODY></HTML>"));
		context.setMap(Utils.map("map0", Utils.linkedMap("v0", "l0").map("v1", "l1")));
		
		expression.exec(context);
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SELECT name=\"name1\" >"
				+ "<OPTION value=\"v0\">l0</OPTION>"
				+ "<OPTION value=\"v1\">l1</OPTION>"
				+ "</SELECT>"
				+ "</BODY></HTML>"), context.getNode()));
	}

	public void testMergeCellAll0() {
		final Node node = XmlUtils.convert(
				"<HTML><BODY>"
				+ "<TABLE>"
				+ "<TR><TD>0-0</TD><TD>0-1</TD><TD>0-2</TD></TR>"
				+ "<TR><TD>1-0</TD><TD>1-1</TD><TD>1-2</TD></TR>"
				+ "<TR><TD>2-0</TD><TD>2-1</TD><TD>2-2</TD></TR>"
				+ "<TR><TD>3-0</TD><TD>3-1</TD><TD>3-2</TD></TR>"
				+ "</TABLE>"
				+ "</BODY></HTML>");
		final NodeContext context = new SimpleNodeContext();
		context.setNode(node.getFirstChild().getFirstChild().getFirstChild());
		HtmlUtils.MERGE_CELL_ALL.exec(context);
		node.normalize();
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<TABLE>"
				+ "<TR><TD>0-0</TD><TD>0-1</TD><TD>0-2</TD></TR>"
				+ "<TR><TD>1-0</TD><TD>1-1</TD><TD>1-2</TD></TR>"
				+ "<TR><TD>2-0</TD><TD>2-1</TD><TD>2-2</TD></TR>"
				+ "<TR><TD>3-0</TD><TD>3-1</TD><TD>3-2</TD></TR>"
				+ "</TABLE>"
				+ "</BODY></HTML>"), node));
	}
	
	public void testMergeCellAll1() {
		final Node node = XmlUtils.convert(
				"<HTML><BODY>"
				+ "<TABLE>"
				+ "<TR><TD>0-0</TD><TD>0-1</TD><TD>0-2</TD></TR>"
				+ "<TR><TD>1-0</TD><TD>1-1</TD><TD>1-2</TD></TR>"
				+ "<TR><TD>2-0</TD><TD>1-1</TD><TD>2-2</TD></TR>"
				+ "<TR><TD>3-0</TD><TD>3-1</TD><TD>3-2</TD></TR>"
				+ "</TABLE>"
				+ "</BODY></HTML>");
		final NodeContext context = new SimpleNodeContext();
		context.setNode(node.getFirstChild().getFirstChild().getFirstChild());
		HtmlUtils.MERGE_CELL_ALL.exec(context);
		node.normalize();
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<TABLE>"
				+ "<TR><TD>0-0</TD><TD>0-1</TD><TD>0-2</TD></TR>"
				+ "<TR><TD>1-0</TD><TD rowspan=\"2\">1-1</TD><TD>1-2</TD></TR>"
				+ "<TR><TD>2-0</TD><TD>2-2</TD></TR>"
				+ "<TR><TD>3-0</TD><TD>3-1</TD><TD>3-2</TD></TR>"
				+ "</TABLE>"
				+ "</BODY></HTML>"), node));
	}
	
	public void testMergeCellAll2() {
		final Node node = XmlUtils.convert(
				"<HTML><BODY>"
				+ "<TABLE>"
				+ "<TR><TD>0-0</TD><TD>0-1</TD><TD>0-2</TD></TR>"
				+ "<TR><TD>0-0</TD><TD>1-1</TD><TD>0-2</TD></TR>"
				+ "<TR><TD>2-0</TD><TD>1-1</TD><TD>2-2</TD></TR>"
				+ "<TR><TD>2-0</TD><TD>3-1</TD><TD>2-2</TD></TR>"
				+ "</TABLE>"
				+ "</BODY></HTML>");
		final NodeContext context = new SimpleNodeContext();
		context.setNode(node.getFirstChild().getFirstChild().getFirstChild());
		HtmlUtils.MERGE_CELL_ALL.exec(context);
		node.normalize();
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<TABLE>"
				+ "<TR><TD rowspan=\"2\">0-0</TD><TD>0-1</TD><TD rowspan=\"2\">0-2</TD></TR>"
				+ "<TR><TD rowspan=\"2\">1-1</TD></TR>"
				+ "<TR><TD rowspan=\"2\">2-0</TD><TD rowspan=\"2\">2-2</TD></TR>"
				+ "<TR><TD>3-1</TD></TR>"
				+ "</TABLE>"
				+ "</BODY></HTML>"), node));
	}
	
	public void testMergeCellAll3() {
		final Node node = XmlUtils.convert(
				"<HTML><BODY>"
				+ "<TABLE>"
				+ "<TR><TD>0-0</TD><TD>0-1</TD><TD>0-2</TD></TR>"
				+ "<TR><TD>0-0</TD><TD>1-1</TD><TD>0-2</TD></TR>"
				+ "</TABLE>"
				+ "</BODY></HTML>");
		final NodeContext context = new SimpleNodeContext();
		context.setNode(node.getFirstChild().getFirstChild().getFirstChild());
		HtmlUtils.MERGE_CELL_ALL.exec(context);
		node.normalize();
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<TABLE>"
				+ "<TR><TD rowspan=\"2\">0-0</TD><TD>0-1</TD><TD rowspan=\"2\">0-2</TD></TR>"
				+ "<TR><TD>1-1</TD></TR>"
				+ "</TABLE>"
				+ "</BODY></HTML>"), node));
	}
	
	public void testMergeCell() {
		final Node node = XmlUtils.convert(
				"<HTML><BODY>"
				+ "<TABLE>"
				+ "<TR><TD>0-0</TD><TD>0-1</TD><TD>0-2</TD></TR>"
				+ "<TR><TD>1-0</TD><TD>0-1</TD><TD>1-2</TD></TR>"
				+ "<TR><TD>2-0</TD><TD>2-1</TD><TD>2-2</TD></TR>"
				+ "<TR><TD>3-0</TD><TD>2-1</TD><TD>3-2</TD></TR>"
				+ "</TABLE>"
				+ "</BODY></HTML>");
		final NodeContext context = new SimpleNodeContext();
		context.setNode(node.getFirstChild().getFirstChild().getFirstChild());
		HtmlUtils.mergeCell(1).exec(context);
		node.normalize();
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<TABLE>"
				+ "<TR><TD>0-0</TD><TD rowspan=\"2\">0-1</TD><TD>0-2</TD></TR>"
				+ "<TR><TD>1-0</TD><TD>1-2</TD></TR>"
				+ "<TR><TD>2-0</TD><TD rowspan=\"2\">2-1</TD><TD>2-2</TD></TR>"
				+ "<TR><TD>3-0</TD><TD>3-2</TD></TR>"
				+ "</TABLE>"
				+ "</BODY></HTML>"), node));
	}

	public void testUpdateToSelectedValue() {
		final Fn<NodeContext, Void> expression = XmlUtils.findNode(
				new JXP("id", "id0"),
				HtmlUtils.updateToSelectedValue(new PathEL("map.value0"), new PathEL("map.list0")));
		final MapNodeContext context = new MapNodeContext();
		context.setNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SPAN id=\"id0\" />"
				+ "</BODY></HTML>"));
		context.setMap(Utils
				.map("list0", (Object) Utils.map("v0", "l0").map("v1", "l1"))
				.map("value0", "v1"));
		expression.exec(context);
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SPAN id=\"id0\">l1</SPAN>"
				+ "</BODY></HTML>"), context.getNode()));
	}

	public void testUpdateToSelectedValueNull() {
		final Fn<NodeContext, Void> expression = XmlUtils.findNode(
				new JXP("id", "id0"),
				HtmlUtils.updateToSelectedValue(new PathEL("map.value0"), new PathEL("map.list0")));
		final MapNodeContext context = new MapNodeContext();
		context.setNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SPAN id=\"id0\" />"
				+ "</BODY></HTML>"));
		context.setMap(Utils
				.map("list0", (Object) Utils.map("v0", "l0").map("v1", "l1")));
		expression.exec(context);
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "</BODY></HTML>"), context.getNode()));
	}

	public void testRemoveThidAndText() {
		final Fn<NodeContext, Void> expression = XmlUtils.findNode(
				new JXP("name", "name1"),
				HtmlUtils.REMOVE_THIS_AND_TEXTS,
				new NullFn<NodeContext, Void>());
		final MapNodeContext context = new MapNodeContext();
		context.setNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SPAN>"
				+ "<INPUT type=\"radio\" name=\"name1\" value=\"v0\" />l0"
				+ "<INPUT type=\"radio\" name=\"name1\" value=\"v1\" />l1"
				+ "</SPAN>"
				+ "</BODY></HTML>"));
		context.setMap(Utils.map("map0", Utils.linkedMap("v0", "l0").map("v1", "l1")));
		
		expression.exec(context);
		assertTrue(XmlUtils.equalsNode(XmlUtils.convert(
				"<HTML><BODY>"
				+ "<SPAN>"
				+ "<INPUT type=\"radio\" name=\"name1\" value=\"v1\" />l1"
				+ "</SPAN>"
				+ "</BODY></HTML>"), context.getNode()));
	}
}
