var getElementById = document.getElementById ? function(id) {
	return document.getElementById(id);
} : document.all ? function(id) {
	return document.all[id];
} : function(id) {
	return null;
};

var gui_util = {
	createDomElement : function(tagName, assocAttributeArray, textContent) {
		var domElement = document.createElement(tagName);
		if (assocAttributeArray != null) {
			for ( var key in assocAttributeArray) {
				domElement.setAttribute(key, assocAttributeArray[key]);
				if (key == "style") // Internet DExplorer hack
					domElement.style.cssText = assocAttributeArray[key];
			}
		}
		if (textContent != null) {
			domElement.appendChild(document.createTextNode(textContent));
		}
		return domElement;
	},
	cloneDomElement : function(sourceDomElement, assocAttributeArray,
			textContent, deepCopy) {
		var validDeepCopy = (deepCopy == null ? true : deepCopy);
		domElement = sourceDomElement.cloneNode(validDeepCopy);
		if (assocAttributeArray != null) {
			for (key in assocAttributeArray) {
				domElement.setAttribute(key, assocAttributeArray[key]);
				if (key == "style") // Internet DExplorer hack
					domElement.style.cssText = assocAttributeArray[key];
			}
		}
		if (textContent != null) {
			domElement.appendChild(document.createTextNode(textContent));
		}

		return domElement;
	},
	showChildren : function(obj, classFilter) {
		var children = obj.immediateDescendants();
		for ( var i = 0; i < children.length; i++) {
			if (children[i].hasClassName(classFilter))
				children[i].toggle();
		}
	},
	checkChildren : function checkChildren(obj, srcObj) {
		var children = obj.immediateDescendants();
		for ( var i = 0; i < children.length; i++) {
			if (children[i].tagName.toLowerCase() == 'input'
					&& children[i].type == 'checkbox' && children[i] != srcObj)
				children[i].checked = srcObj.checked;
			// recursive call
			checkChildren(children[i], srcObj);
		}
	},
	getChildElements : function(element) {
		if ((typeof element == "undefined") || element == null) {
			return [];
		}
		if (element.childNodes.length <= 0) {
			return [];
		}
		returnElements = new Array();
		for (iterIndex = 0; iterIndex < element.childNodes.length; iterIndex++) {
			if (element.childNodes[iterIndex]
					&& element.childNodes[iterIndex].nodeType == 1) {
				returnElements.push(element.childNodes[iterIndex]);
			}
		}
		return returnElements;
	}
};

GuiComposer = {
	_searchController : null,
	_templateNodeDomElement : null,
	_tempTreeDepth : 0,
	// separete logic to render the tempalte
	autoExpander : {
		_autoExpandNodes : [],
		/** @constructor */
		addNode : function(id) {
			this._autoExpandNodes[this._autoExpandNodes.length] = id;
		},
		/** @constructor */
		expandAndClear : function() {
			if (this._autoExpandNodes.length <= 0) {
				return;
			}
			for ( var index = 0, len = this._autoExpandNodes.length; index < len; ++index) {
				GuiComposer.treeTemplate
						.onExpandNode(this._autoExpandNodes[index]);
			}
			this._autoExpandNodes.clear();
		}
	},
	queryTerms : {
		termArea : null,
		termTemplate : null,
		forwardCloseEvent : null,
		/** @constructor */
		init : function(termAreaDomId, termTemplateDomId, onClickCloseCallback) {
			this.termArea = document.getElementById(termAreaDomId);
			this.termTemplate = document.getElementById(termTemplateDomId);
			this._onClickCloseCallback = onClickCloseCallback;
		},
		/** @constructor */
		onAddTerm : function(id) {
			if (this.termArea == null) {
				return;
			}
			termData = GuiComposer._searchController.getQueryTerms(id, null);
			termNode = gui_util.cloneDomElement(this.termTemplate, {
				id : termData.id + "_qt",
				style : "display:block;"
			}, null, true);

			if (termNode != null) {
				var content = termNode.childNodes[0].childNodes[0].innerHTML;
				content = content + termData.label;
				termNode.childNodes[0].childNodes[0].innerHTML = content;
				termNode.childNodes[0].childNodes[0].setAttribute('class',
						termData.id);
				aDomElmnt = termNode.childNodes[0].childNodes[0].childNodes[0];
				aDomElmnt.className = termData.id;
				Event.observe(aDomElmnt, "click", this._onClickCloseCallback);
				this.termArea.appendChild(termNode);

				// alert(this.termArea.lastChild.id);
			}
		},
		/** @constructor */
		onDropTerm : function(id) {
			if (this.termArea == null) {
				return;
			}
			this._onDropTerm(id, null);
		},
		/** @constructor */
		_onDropTerm : function(id) {
			if (this.termArea == null) {
				return;
			}
			tmpelmnt = $(id + "_qt");
			if (tmpelmnt != null) {
				tmpelmnt.remove();
			}
		},
		/** @constructor */
		forwardCloseEvent : function(element) {
			if (this.termArea == null) {
				return;
			}
			return this._onClickCloseCallback(element);
		}
	},
	treeTemplate : {
		// CONSTANTS
		EXPAND_AFFIX : "_x",
		ADVNCD_SUBFIX : "_a",
		ONTO_CLASS_PREFIX : "onto_",
		IS_ADVNC_FILTER : "isTermAdvnc",
		ADVNC_CLSS_AND : "queryIcon_and",
		// DOM REFERENCES
		treeDomElement : null,
		nodeDomElement : null,
		// CALLBACKS
		_onClickTermHrefCallback : null,
		// LOGIC
		/** @constructor */
		init : function(templateDefinition, onClickTermHrefCallback) {
			if (templateDefinition == null) {
				return;
			}
			this.treeDomElement = document
					.getElementById(templateDefinition['tree']);
			this.nodeDomElement = document
					.getElementById(templateDefinition['node']);
			this._onClickTermHrefCallback = onClickTermHrefCallback;
		},
		/** @constructor */
		renderNodeElement : function(node, isExpandable) {
			nodeElement = gui_util.cloneDomElement(this.nodeDomElement, {
				'id' : node.id,
				'class' : 'treeNode ' + node.classid
			}, null);

			childElements = gui_util.getChildElements(nodeElement);

			var expandHref = childElements[0];
			expandHref.firstChild.setAttribute('id', node.id
					+ this.EXPAND_AFFIX);
			termHref = childElements[2];
			// inductionCountrElmnt = childElements[4];
			// termIconDom = nodeElement.childElements()[1];
			// termIconDom.addClassName(this.ONTO_CLASS_PREFIX + node.ontoid);
			advancedStateDom = childElements[1];
			Element.Methods.addClassName(advancedStateDom, node.classid
					+ this.ADVNCD_SUBFIX);
			if (node.state != null && node.state.advancedState == "REQUIRED") {
				Element.Methods.addClassName(advancedStateDom,
						this.ADVNC_CLSS_AND);
				Element.Methods.addClassName(nodeElement, this.IS_ADVNC_FILTER);
			}
			if (!isExpandable) {
				expandHref.firstChild.className = 'nullExpand';
			} else {
				expandHref.setAttribute('href', 'javascript:void(0);');
				Event.observe(expandHref, 'click', function() {
					expandDomElement = GuiComposer.treeTemplate
							.onExpandNode(this.parentNode.id);
					window.SearchController
							.treeNodeEvent(this.parentNode.id, null,
									expandDomElement
											.hasClassName('collapseIcon'));
				});
				if (node.state != null && node.state.expanded == false) {
					GuiComposer.autoExpander.addNode(expandHref.parentNode.id);
				}
			}
			Event.observe(termHref, 'click', this._onClickTermHrefCallback);
			termHref.insert(node.inductionlabel);
			// inductionCountrElmnt.insert(node.labelcount);
			return {
				'node' : nodeElement,
				'termHref' : termHref,
				'expandHref' : expandHref
			};
		},
		/** @constructor */
		renderTreeElement : function(isVisible) {
			return gui_util.cloneDomElement(this.treeDomElement, {
				'style' : 'display: ' + (isVisible == true ? 'block' : 'none')
						+ ';'
			}, null, false);
		},
		/** @constructor */
		onExpandNode : function(parentNodeId) {
			expandDomElement = $(parentNodeId + this.EXPAND_AFFIX);
			expandDomElement.toggleClassName('collapseIcon');
			gui_util.showChildren($(parentNodeId), "treeNodeRoot");
			return expandDomElement;
		},
		/** @constructor */
		onFilterNode : function(parentNodeId) {
			prntNodeDom = $(parentNodeId);
			if(prntNodeDom == null){
				return "NONE";
			}
			prntNodeDom.toggleClassName(this.IS_ADVNC_FILTER);
			return prntNodeDom.hasClassName(this.IS_ADVNC_FILTER) ? "REQUIRED"
					: "NONE";
			// "NONE", "REQUIRED", "FORBIDDEN", "USED"
		}
	},
	//
	// Public function to be called in the template
	//
	// @param searchController
	// @param domElementId
	// @param templateDefinition
	// @returns
	//
	/** @constructor */
	renderOntologyTree : function(searchController, domElementId,
			templateDefinition, onClickTermHrefCallback, initialTreeNodes) {
		if (searchController.searchContext.ontology != null && initialTreeNodes == null) {
			initialTreeNodes = searchController.searchContext.ontology;
		}

		this._searchController = searchController;

		GuiComposer.treeTemplate.init(templateDefinition,
				onClickTermHrefCallback);

		this._renderOntologyTree(initialTreeNodes, document
				.getElementById(domElementId));
		this.autoExpander.expandAndClear();
	},
	//
	//
	// @param nodeList
	// ARRAY((NODE INFORMATIONS),(NODE INFORMATIONS),....)
	// @param parentDomElement -
	// DOM ELEMENT, USUAL LI-DOM-ELEMENT
	// @returns
	//
	/** @constructor */
	_renderOntologyTree : function(nodeList, parentDomElement) {
		if (nodeList == null) {
			return;
		}
		for ( var iterNode = 0; iterNode < nodeList.length; iterNode++) {
			currentNodeElement = this._renderOntologyTreeNode(
					nodeList[iterNode],
					// direct reload
					function(node, parentNodeElement) {
						treeDomElement = GuiComposer.treeTemplate
								.renderTreeElement(true);
						parentNodeElement.appendChild(treeDomElement);
						GuiComposer._renderOntologyTree(node.children,
								treeDomElement);
					},
					// 'onclick' reload
					function(node, parentNodeElement, aDomElement) {
						// HAS CHRILDREN + LOAD DYNAMIC
						Event.observe(aDomElement, 'click', function() {
							treeDomElement = GuiComposer.treeTemplate
									.renderTreeElement(true);
							parentNodeElement.appendChild(treeDomElement);
							GuiComposer._renderOntologyTree(
									GuiComposer._searchController
											.fetchTermNodes(node['id']),
									treeDomElement);
							this.stopObserving('click');
							Event.observe(this, 'click', function() {
								$(this.parentNode.id + "_xpndNd")
										.toggleClassName('collapseIcon');
								gui_util.showChildren($(this.parentNode.id),
										"treeNodeRoot");
							});
						});
					});
			parentDomElement.appendChild(currentNodeElement);
		}

	},
	//
	//
	// @param node -
	// ARRAY WITH NODE INFORMATIONS
	// @param loadChildrenCallback -
	// DEFAULT SUB-TREE CREATION METHOD / EVENT-HANDLER
	// @param loadChildrenDynamicCallback -
	// DYNAMIC SUB-TREE CREATION METHOD / EVENT-HANDLER
	// @returns LI-DOM ELEMENT
	//
	/** @constructor */
	_renderOntologyTreeNode : function(node, loadChildrenCallback,
			loadChildrenDynamicCallback) {
		// (node['children'] instanceof Object) || (node['children'] instanceof
		// Arrays)
		// console.log(node);
		var nodeElement = this.treeTemplate.renderNodeElement(node,
				node.children.length > 0);
		if (node.isParent == true) {
			if (node.children == "reload") {
				loadChildrenDynamicCallback(node, nodeElement.node,
						nodeElement.expandHref);
			} else {
				loadChildrenCallback(node, nodeElement.node);
			}
		}
		// padding-right
		// this._tempTreeDepth
		return nodeElement.node;
	}

};
