/* 
 * Buffalo Web Remoting, An amowa infrastructure facility, a web remoting library.
 * 
 * Author: Michael Chen (mechiland AT gmail DoT com, http://michael.nona.name)
 * 
 * Version: 1.0
 *
 */

/** 
 * @fileoverview buffalo-bind.js is the bind library for binding the remote call
 * reply to the html elements.
 *
 * @author Michael Chen mechiland@gmail.com http://michael.nona.name
 * @version 1.0
 */

/**
 * Invoke the remote service directly, and bind the reply to 
 * the specified element. 
 * 
 * @param {String} service the remote service, such as serviceName.methodName
 * @param {Array} params The parameters. if none, use <code>[]</code> and don't use <code>null</code>
 * @param {String} bindElemId The element id in the page.
 */
Buffalo.prototype.bindReply = function(service, params, bindElemId) {
	this.remoteCall(service, params, function(reply) {
		Buffalo.bind(bindElemId, reply.getResult());
	});	
}

/**
 * Bind the value to the specified elementId.
 * 
 * @param {String} elementId The element id
 * @param {varient} bindValue The binded value. 
 */
Buffalo.bind = function(elementId, bindValue) {
	var elem = Buffalo.getElementById(elementId);
	switch(elem.tagName) {
		case "INPUT": 
			switch (elem.type.toLowerCase()) {
				
				case "text": ;
				case "hidden": ;
				case "password": BindFactory.bindText(elem, bindValue); break;

				case "checkbox": ;
				case "radio": BindFactory.bindRadioOrCheckbox(elem, bindValue); break;
			}
			break;
		case "TEXTAREA":
			BindFactory.bindText(elem, bindValue);
			break; 
		case "TABLE": 
			BindFactory.bindTable(elem, bindValue);
			break; 
		case "SELECT": 
			BindFactory.bindSelect(elem, bindValue);
			break; 
		//TODO: add more bindings here for 
	}
}

/**
 * Factory method. Do not call it directly.
 */
function BindFactory(){}

/**
 * Report the error.
 * @param {HTMLDOMElement} elem the html element
 * @param {varient} the value to be binded
 * @param {String} msg the error message
 */
BindFactory.reportError = function(elem, value, msg) { 
	throw "Data bind failed: "+msg;
}

/**
 * Bind value to the text-like element, such as input, textarea
 * @param {HTMLDOMElement} elem the html element
 * @param {varient} value the value to bind
 */
BindFactory.bindText = function(elem, value) { 
	elem.value = value;
}

/**
 * Bind value to the radiobox oo checkbox.
 * @param {HTMLDOMElement} elem the html element
 * @param {varient} value the value to bind
 */
BindFactory.bindRadioOrCheckbox = function(elem, value) {
	var ret = false;
	switch (typeof(value)) {
		case 'boolean': ret = value; break;
		case 'string': ret = (value == "1" || value == "true" || value == "yes"); break;
		case 'number': ret = (parseInt(value) == 1); break;
		default: ret = false;
	}
	elem.checked = ret;
}

/**
 * Bind value to select/list element.
 *
 * @param {HTMLDOMElement} elem the html element
 * @param {varient} value the value to bind
 */
BindFactory.bindSelect = function(elem, value) {
	//TODO: Check the data type
	if (typeof(value) != "object" || value.constructor != Array) {
		BindFactory.reportError(elem,value,"error!");
	}
	// delete all the nodes.
	while (elem.childNodes.length > 0) {
		elem.removeChild(elem.childNodes[0]);
	}

	// bind data
	for (var i = 0; i < value.length; i++) {
		var data = value[i];
		//TODO: add data type check
		var option = document.createElement("OPTION");
		option.value = data[elem.getAttribute("jvalue")];
		option.text = data[elem.getAttribute("jtext")];
		elem.options.add(option);
	}
}

/**
 * Bind value to a html table.
 * @param {HTMLDOMElement} elem the html element
 * @param {varient} value the value to bind
 */
BindFactory.bindTable = function(elem, value) {
	var jHeight = parseInt(elem.getAttribute("jheight"));
	var dataHeader = [];
	var tBody = elem.getElementsByTagName("TBODY")[0];
	
	// clear the generated rows
	if (elem.getElementsByTagName("TBODY").length > 0) {
		while (tBody.rows.length > jHeight) {
				tBody.deleteRow(jHeight);
		}
	}

	if (jHeight == 0) { // if table is null, push the data to the tables.

		for (x in value[0] ) {
			dataHeader[dataHeader.length] = x;
		}

		var hTr = elem.insertRow(elem.rows.length);
		for (var i = 0; i < dataHeader.length; i++) {
			var td = hTr.insertCell(hTr.cells.length);
			td.innerHTML = dataHeader[i];
		}
		
		for (var i = 0; i < value.length; i++) {
			var tr = elem.insertRow(elem.rows.length);
			var data = value[i];
			for (x in data ) {
				var td = tr.insertCell(tr.cells.length);
				td.innerHTML = data[x];
			}
		}	
	}
	
	if (jHeight == 1) { // )
		var headerTR = tBody.rows[0];

		for (var i = 0; i < headerTR.cells.length ; i++ ) {
			dataHeader[dataHeader.length] = headerTR.cells[i].getAttribute("jtext");
		}
		
		for (var i = 0; i < value.length; i++) {
			var tr = tBody.insertRow(tBody.rows.length);
			var data = value[i];
			for (var j = 0; j < dataHeader.length; j++ ) {
				var td = tr.insertCell(tr.cells.length);
				td.innerHTML = data[dataHeader[j]];
			}
		}	
	}

	if (jHeight == 2) { //

		var headerTR = tBody.rows[0];

		for (var i = 0; i < headerTR.cells.length ; i++ ) {
			dataHeader[dataHeader.length] = headerTR.cells[i].getAttribute("jtext");
		}

		for (var i = 0; i < value.length; i++) {
			
			var tr;
			
			if (i == 0) { //
				tr = elem.rows[1];
			} else { // 
				tr = elem.rows[1].cloneNode(true);
			}

			var data = value[i];
			for (var j = 0; j < tr.cells.length; j++ ) {
				var td = tr.cells[j];
				
				td.innerHTML = data[dataHeader[j]];
			}

			if (i > 0) 	{
				tBody.appendChild(tr);
			}
			
		}	
	}

	if (jHeight >= 3) { //
		var headerTR = tBody.rows[0];
		for (var i = 0; i < headerTR.cells.length ; i++ ) {
			dataHeader[dataHeader.length] = headerTR.cells[i].getAttribute("jtext");
		}
		for (var i = 0; i < value.length; i++) {
			
			var tr;
			
			if (i == 0) { // 
				tr = tBody.rows[1];
			} else if (i == 1) 	{ //
				tr = tBody.rows[2];
			} else if ( i % 2 == 0) { // 
				tr = tBody.rows[1].cloneNode(true);
			} else if (i % 2 == 1) { // 
				tr = tBody.rows[2].cloneNode(true);
			}

			var data = value[i];
			for (var j = 0; j < tr.cells.length; j++ ) {
				var td = tr.cells[j];	
				td.innerHTML = data[dataHeader[j]];
			}
			if (i > 1) 	{
				tBody.appendChild(tr);
			}
		}	
	}
	
}

/**
 * Bind value to a repeater(under considering.)
 * @param {HTMLDOMElement} elem the html element
 * @param {varient} value the value to bind
 */
BindFactory.bindRepeater = function(elem, value) {
	//TODO: implementation will be added.
}

