$data = (function(){

	function create_callback_onload($key)
	{
		return function(){ data_onload($key) };
	}

	function create_callback_fileOnLoad($key)
	{
		return function(){ data_file_onload($key) };
	}

	function data_onload($key)
	{
		for(key in arrDatas[$key].onload)
		{
			arrDatas[$key].onload[key]();
		}
	}

	function data_convert_value($value, $type)
	{
		var rtn;
		switch($type)
		{
			case "number":
				rtn = parseFloat($value);
				break;
			case "php_mktime":
				var dt = new Date(parseFloat($value) * 1000);
				var year = "" + dt.getFullYear();
				var month = "" + (dt.getMonth()+1);
				if(month.length < 2)
					month = "0" + month;
				var day = "" + dt.getDate();
				if(day.length < 2)
					day = "0" + day;
				rtn = year + "-" + month + "-" + day;
				break;
			default:
				rtn = $value;
				break;
		}
		return rtn;
	}

	function data_dom_get_value($dom, $key, $type)
	{
		var v = null;
		var node;
		switch($key.charAt(0))
		{
			case "$":
				break;
			case "@":
				if($dom)
					v = data_convert_value($dom.attributes.getNamedItem($key.substr(1)).value, $type);
				else
					v = "--";
				break;
			default:
				if($dom)
				{
					node = $dom.selectSingleNode($key).firstChild;
					if(node)
						v = data_convert_value($dom.selectSingleNode($key).firstChild.nodeValue, $type);
					else
						v = "--";
				}
				else
					v = "--";
				break;
		}
		return v;
	}

	function data_group_order($arrNodes, $groupConfig)
	{
		if($arrNodes.length <= 0)
			return null;

		var fValue = null;
		var fSelectValue = null, idxSelect = -1;
		for(var i=0;i<$arrNodes.length;i++)
		{
			fValue = data_dom_get_value($arrNodes[i], $groupConfig.orderfield, $groupConfig.type);
			if(fSelectValue == null)
			{
				fSelectValue = fValue;
				idxSelect = i;
			}
			else
			{
				switch($groupConfig.order)
				{
					case "asc":
						if(fSelectValue > fValue)
						{
							fSelectValue = fValue;
							idxSelect = i;
						}
						break;
					default: // "desc"
						if(fSelectValue < fValue)
						{
							fSelectValue = fValue;
							idxSelect = i;
						}
						break;
				}
			}

		}

		return $arrNodes[idxSelect];
	}

	function data_group_load($key)
	{
		var config = $config.data[$key];
		var dom = $file.getDom(config.file);
		var rs = arrDatas[$key].recordset;
		var map = $config.map[$config.data[$key].group.map];
		var arrNodes;
		for(var i=0;i<map.length;i++)
		{
			if(map[i].index == -1)
				arrNodes = dom.selectNodes(config.xpath);
			else
				arrNodes = dom.selectNodes(config.group.xpath.replace(/\{0\}/ig, map[i].index));

			rs[i] = {
				index : i
				,group : {
					name : map[i].name
					,index : map[i].index
					,count : arrNodes.length
				}
				,fields : {}
			};

			var node = data_group_order(arrNodes, config.group);
			var fKey;
			for(var j=0;j<config.fields.length;j++)
			{
				fKey = config.fields[j].tag;
				fValue = data_dom_get_value(node, fKey, config.fields[j].type);
				if(fValue)
					rs[i].fields[fKey] = fValue;
			}
		}
	}

	function data_load($key, $xpath)
	{
		var config = $config.data[$key];
		$xpath = $xpath || config.xpath;
		var dom = $file.getDom(config.file);
		// For IE 
		dom.setProperty("SelectionLanguage", "XPath");  
		dom.setProperty("SelectionNamespaces", "xmlns:xhtml='http://www.w3.org/1999/xhtml'");  
		dom.setProperty("SelectionNamespaces", "xmlns:xhtml='http://www.w3.org/1999/xhtml' xmlns:cwdg='http://cwowaddon.com'"); 
		//
		var arrNodes = dom.selectNodes($xpath);
		var rs = arrDatas[$key].recordset;
		var fKey, fValue;
		for(var i=0;i<arrNodes.length;i++)
		{
			rs[i] = { index : i, fields : {} };
			for(var j=0;j<config.fields.length;j++)
			{
				fKey = config.fields[j].tag;
				fValue = data_dom_get_value(arrNodes[i], fKey, config.fields[j].type);
				if(fValue)
					rs[i].fields[fKey] = fValue;
			}
		}
	}

	function data_field_index($key, field)
	{
		var config = $config.data[$key];
		for(var i=0;i<config.fields.length;i++)
		{
			if(config.fields[i].tag == field)
				return i;
		}
		return -1;
	}

	function data_filter($key, $param)
	{
		var config = $config.data[$key];
		var xpath_exp = [];
		var fIdx;
		var charUpper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
		var charLower = "abcdefghijklmnopqrstuvwxyz";
		for(field in $param)
		{
			fIdx = data_field_index($key, field);
			if(fIdx >= 0)
			{
				switch(config.fields[fIdx].type)
				{
					case "map":
						if($param[field] != -1)
							xpath_exp[xpath_exp.length] = config.fields[fIdx].tag + "=" + $param[field];
						break;
					case "string":
						if($param[field] == "")
							delete $param[field]
						else
							xpath_exp[xpath_exp.length] = "contains(translate(" + config.fields[fIdx].tag + ", '" + charUpper + "', '" + charLower + "') ,'" + $param[field].toLowerCase() + "')";
						break;
					default:
						break;
				}
			}
		}

		var xpath = config.xpath;
		if(xpath_exp.length > 0)
			xpath += "[" + xpath_exp.join(" and ") + "]";
		arrDatas[$key].recordset = [];
		data_load($key, xpath);
		setTimeout(arrDatas[$key].callback, 1);
	}

	function data_map_value($map, $index)
	{
		for(var i=0;i<$map.length;i++)
		{
			if($map[i].index == $index)
				return $map[i].name;
		}
		return null;
	}

	function data_field_value($key, $field, $index)
	{
		var config = $config.data[$key];
		var arrRS = arrDatas[$key].recordset;
		if(arrRS == null || arrRS.length <= $index)
			return null;
		var rs = arrRS[$index];
		var fIdx = data_field_index($key, $field);
		if(fIdx < 0)
			return null;
		switch(config.fields[fIdx].type)
		{
			case "map":
				if(config.fields[fIdx].map)
					return data_map_value($config.map[config.fields[fIdx].map], rs.fields[$field]);
				else
					return rs.fields[$field];
				break;
		}
		return rs.fields[$field];
	}

	function data_group_value($key, $field, $index)
	{
		var config = $config.data[$key];
		var arrRS = arrDatas[$key].recordset;
		if(arrRS == null || arrRS.length <= $index)
			return null;
		var rs = arrRS[$index];
		switch($field)
		{
			case "name":
				return rs.group.name;
				break;
			case "count":
				return rs.group.count;
				break;
		}
		return null;
	}

	function data_record_count($key)
	{
		if(arrDatas[$key].recordset)
			return arrDatas[$key].recordset.length;
		else
			return 0;
	}

	function data_file_onload($key)
	{
		var config = $config.data[$key];
		if(config.group)
			data_group_load($key);
		else
			data_load($key);
		setTimeout(arrDatas[$key].callback, 1);
	}

	function data_register_onload($srcKey, $destKey, $destCallback)
	{
		if(!arrDatas[$srcKey])
			return;
		arrDatas[$srcKey].onload[$destKey] = $destCallback;
	}

	function data_getData($key)
	{
		if(arrDatas[$key])
			return arrDatas[$key].recordset;
		return null;
	}

	var arrDatas = {};
	for(key in $config.data)
	{
		arrDatas[key] = {
			onload : {}
			,recordset : []
			,callback : create_callback_onload(key)
		};
		$file.registerOnLoad($config.data[key].file, key, create_callback_fileOnLoad(key));
	}

	return {
		registerOnLoad : data_register_onload
		,getData : data_getData
		,filter : data_filter
		,getRecordCount : data_record_count
		,getFieldValue : data_field_value
		,getGroupValue : data_group_value
	};

})();
