package eu.ydp.empiria.player.client.module.object;

import static org.mockito.Mockito.*;

import java.util.Map;

import com.google.common.collect.Maps;
import com.google.gwt.thirdparty.guava.common.base.Optional;
import com.google.gwt.xml.client.Element;
import com.google.gwt.xml.client.Node;
import com.google.gwt.xml.client.NodeList;

class MockElementFluentBuilder {
	private static final NodeList EMPTY_LIST;
	
	static {
		EMPTY_LIST = mock(NodeList.class);
		when(EMPTY_LIST.getLength()).thenReturn(0);
	}
	
	private Short nodeType;
	private Optional<String> value = Optional.absent();
	private Optional<NodeList> children = Optional.absent();
	private Optional<String> nodeTag = Optional.absent();
	private final Map<String, String> attributes = Maps.newHashMap();
	private final Map<String, NodeList> tagChildren = Maps.newHashMap();

	private MockElementFluentBuilder() {}

	public static MockElementFluentBuilder newElement() {
		return new MockElementFluentBuilder();
	}
	
	public static MockElementFluentBuilder newNode() {
		return newElement().ofType(Node.ELEMENT_NODE);
	}

	public static MockElementFluentBuilder newText(String text) {
		return newElement().ofType(Node.TEXT_NODE).withValue(text);
	}
	
	public static MockElementFluentBuilder newComment() {
		return newElement().ofType(Node.COMMENT_NODE);
	}

	public MockElementFluentBuilder ofType(short nodeType) {
		this.nodeType = nodeType;
		return this;
	}

	public MockElementFluentBuilder withTag(String nodeTag) {
		this.nodeTag = Optional.of(nodeTag);
		
		return this;
	}
	
	public MockElementFluentBuilder withAttribute(String attributeName, String attributeValue) {
		this.attributes.put(attributeName, attributeValue);
		return this;
	}

	public MockElementFluentBuilder withValue(String value) {
		this.value = Optional.of(value);
		return this;
	}

	public MockElementFluentBuilder withChildren(Element... children) {
		NodeList nodeList = buildNodeListFromElements(children);
		this.children = Optional.of(nodeList);
		
		return this;
	}

	public MockElementFluentBuilder withChildrenTags(String tag, Element... children) {
		NodeList nodeList = buildNodeListFromElements(children);
		tagChildren.put(tag, nodeList);

		return this;
	}

	private NodeList buildNodeListFromElements(Element... children) {
		NodeList nodeList = mock(NodeList.class);

		for (int i = 0; i < children.length; i++) {
			when(nodeList.item(i)).thenReturn(children[i]);
		}

		when(nodeList.getLength()).thenReturn(children.length);
		return nodeList;
	}

	public Element build() {
		Element result = mock(Element.class);

		when(result.getNodeType()).thenReturn(nodeType);
		
		if (value.isPresent()) {
			when(result.getNodeValue()).thenReturn(value.get());
		}

		if (nodeTag.isPresent()) {
			when(result.getTagName()).thenReturn(nodeTag.get());
		}
		
		if (children.isPresent()) {
			when(result.getChildNodes()).thenReturn(children.get());
		} else {
			when(result.getChildNodes()).thenReturn(EMPTY_LIST);
		}

		for (Map.Entry<String, String> attr : attributes.entrySet()) {
			when(result.getAttribute(attr.getKey())).thenReturn(attr.getValue());
		}

		for (Map.Entry<String, NodeList> tC : tagChildren.entrySet()) {
			when(result.getElementsByTagName(tC.getKey())).thenReturn(tC.getValue());
		}

		return result;
	}

}
@@ -408,18 +408,17 @@
 Y_LIST;%0A
-%09
 %0A
+
 %09static 
@@ -505,18 +505,17 @@
 (0);%0A%09%7D%0A
-%09
 %0A
+
 %09private
@@ -872,16 +872,18 @@
 lder() %7B
+%0A%09
 %7D%0A%0A%09publ
@@ -972,26 +972,25 @@
 ilder();%0A%09%7D%0A
-%09
 %0A
+
 %09public stat
@@ -1206,26 +1206,25 @@
 e(text);%0A%09%7D%0A
-%09
 %0A
+
 %09public stat
@@ -1522,19 +1522,17 @@
 deTag);%0A
-%09%09
 %0A
+
 %09%09return
@@ -1541,18 +1541,17 @@
 his;%0A%09%7D%0A
-%09
 %0A
+
 %09public 
@@ -1991,19 +1991,17 @@
 eList);%0A
-%09%09
 %0A
+
 %09%09return
@@ -2622,19 +2622,17 @@
 eType);%0A
-%09%09
 %0A
+
 %09%09if (va
@@ -2804,42 +2804,9 @@
 %09%09%7D%0A
-%09%09%0A%09%09if (children.isPresent()) %7B%0A%09
+%0A
 %09%09wh
@@ -2856,69 +2856,10 @@
 ren.
-get());%0A%09%09%7D else %7B%0A%09%09%09when(result.getChildNodes()).thenReturn
+or
 (EMP
@@ -2866,21 +2866,18 @@
 TY_LIST)
+)
 ;
-%0A%09%09%7D
 %0A%0A%09%09for 

Change attaching child nodes (Optional.or)