var MvpWebTemplate_Class = Class.create({
	initialize: function() {
		this.templates = Array();
		this.shownElements = Array();
	},
	
	loadTemplate: function(name, template) {
		this.templates[name] = template;
	},
	
	render: function(templateName, values, container, successFunction) {
		var logContainer = $('MvpWebTemplateErrorLog');
		if (logContainer != null) {
			logContainer.innerHTML = null;
		}
		if (this.templates[templateName] != null) {
			this.doRender(this.templates[templateName], values, container, successFunction);
		} else {
			path = MvpWebTemplate.getSelfPath() + '/jsTemplate/' + templateName;
			new Ajax.Request(path, {
				method: 'get',
				onSuccess: function(transport){
					template = transport.responseText.evalJSON(true);
					MvpWebTemplate.templates[templateName] = template;
					MvpWebTemplate.doRender(template, values, container, successFunction);
				}	
			});
		}
	},
	
	doRender: function(template, values, container, successFunction) {
		var renderer = new MvpWebTemplateRenderer_Class();
		renderer.render(template, values, container, successFunction);
	},

	getSelfPath: function() {
		var path = location.pathname;
		if (path.endsWith('/')) {
			path += 'index.xml';
		}
		return path;
	},
	
	doShowHide: function(show, hide) {
		if (show != undefined) {
			this.shownElements[show] = true;
			this.showElements(show, false);
		}
		if (hide != undefined) {
			this.shownElements[hide] = undefined;
			this.showElements(hide, true);
		}
	},
	
	showElements: function(name, hide) {
		var elements = $$('.CAF-show-' + name);
		for (var i = 0; i < elements.length; i++) {
			if (hide) {
				elements[i].removeClassName('show');
				elements[i].addClassName('hide');
			} else {
				elements[i].removeClassName('hide');
				elements[i].addClassName('show');
			}
		}
		var elements = $$('.CAF-hide-' + name);
		for (var i = 0; i < elements.length; i++) {
			if (hide) {
				elements[i].removeClassName('hide');
				elements[i].addClassName('show');
			} else {
				elements[i].removeClassName('show');
				elements[i].addClassName('hide');
			}
		}
	},
	
	log: function(message) {
		var logContainer = $('MvpWebTemplateErrorLog');
		if (logContainer != null) {
			Element.insert(logContainer, message + '<br/>');
		}
	},

	logError: function(message) {
		this.log('<strong style="color: #ff0000">' + message + '</strong>');
	},
	
	clearLog: function() {
		$('MvpWebTemplateErrorLog').innerHTML = '';
	}
});

var MvpWebTemplateRenderer_Class = Class.create({

	render: function(template, data, container, successFunction) {
		this.func('render');
		
		MvpWebTemplate.log('<h5>Error log:</h5>');
		this.values = Array();
		this.values.push(data);
		content = this.renderNode(template.template);
		MvpWebTemplate.log('<h5>Debug:</h5>');
		MvpWebTemplate.log(Object.toJSON(data));
		MvpWebTemplate.log('');
		MvpWebTemplate.log(content.escapeHTML());
		MvpWebTemplate.log('');
		MvpWebTemplate.log(Object.toJSON(template));
		container.innerHTML = content;
		successFunction();
		this.func('');
	},

	renderNode: function(node) {
		this.func('renderNode');
		if (Object.isArray(node)) {
			return this.renderArray(node);
		}
		switch (node.type) {
			case 'regular':
				return this.renderRegularNode(node, false);
			case 'text':
				return node.contents;
			case 'pluginValue':
				return this.renderPluginValueNode(node);
			case 'pluginList':
				return this.renderPluginListNode(node);
			case 'pluginSubstitution':
				return this.renderRegularNode(node, true);
			case 'pluginConditional':
				return this.renderPluginConditionalNode(node);
			case 'pluginSwitch':
				return this.renderPluginSwitchNode(node);
			case 'pluginFormInputText':
				return this.renderPluginFormInputTextNode(node);
			case 'pluginFormTextArea':
				return this.renderPluginFormTextAreaNode(node);
		}
		MvpWebTemplate.logError('Unknown node type: ' + node.type);
		return '';
	},
	
	renderArray: function(node) {
		this.func('renderArray');
		var str = '';
		for (var i = 0; i < node.length; i++) {
			str += this.renderNode(node[i]);
		}
		return str;
	},
	
	renderRegularNode: function(node, doSubstitution) {
		this.func('renderRegularNode');
		var str = '<' + node.name;
		str += this.buildNodeAttributes(node, doSubstitution);
		if (node.isExpanded) {
			str += '>';
			str += this.renderArray(node.children);
			str += '</' + node.name + '>';
		} else {
			str += '/>';
		}
		return str;
	},
	
	renderPluginValueNode: function (node) {
		this.func('renderPluginValueNode');
		var value = this.getValue(node.key);
		if ((value == null) || (value.value == null)) {
			return '';
		}
		if (node.format == null) {
			return value.value;
		}
		if (value.type == 'Date') {
			var date = new Date(value.value);
			return date.toString(node.format);
		} else if (value.type == 'String') {
			return this.doStringFormats(value.value, node.format);
		} else {
			MvpWebTemplate.logError('Unknown formatted type: ' + value.type);
			return value.value;
		}
	},
	
	renderPluginListNode: function(node) {
		this.func('renderPluginListNode');
		var list = this.getActualValue(node.key);
		if (list == null) {
			return '';
		}
		if (! Object.isArray(list)) {
			MvpWebTemplate.logError('Non-list: ' + node.key);
			return '';
		}
		var str = '';
		for (var i = 0; i < list.length; i++) {
			var value = list[i];
			value.hasNext = (i + 1 < list.length);
			value.hasPrev = (i > 0);
			this.values.push(value);
			str += this.renderArray(node.children);
			this.values.pop();
		}
		return str;
	},
	
	renderPluginConditionalNode: function(node) {
		this.func('renderPluginConditionalNode');
		var result = true;
		var value = this.getActualValue(node.key);
		if ((value == null) || (value.type == 'null')) {
			result = false;
		} else {
			if (value.value != null) {
				value = value.value;
			} else if (value.defaultValue != null) {
				value = value.defaultValue;
			}
			if ('boolean' == typeof value) {
				result = value;
			}
			if (Object.isArray(value)) {
				if (value.length == 0) {
					result = false;
				}
			}
			if (node.compareValue != null) {
				if (value != node.compareValue) {
					result = false;
				}
			}
		}
		if (result != node.desiredResult) {
			return '';
		}
		return this.renderArray(node.children);
	},
	
	renderPluginSwitchNode: function(node) {
		this.func('renderPluginSwitchNode');
		var value = this.getStringValue(node.key, false);
		var caseNode = node.cases[value];
		if (caseNode == null) {
			caseNode = node.defaultCase;
		}
		if (caseNode != null) {
			return this.renderNode(caseNode);
		}
		return '';
	},
	
	renderPluginFormInputTextNode: function(node) {
		this.func('renderPluginFormInputTextNode');
		var newNode = Object.clone(node);
		var key = node.attributes['name'];
		var value = this.getValue(key);
		if ((value != null) && (value.value != null) && (String(value.value).length > 0)) {
			newNode.attributes['value'] = value.value;
		}
		return this.renderRegularNode(newNode);
	},
	
	renderPluginFormInputTextNode: function(node) {
		this.func('renderPluginFormInputTextNode');
		var newNode = Object.clone(node);
		var key = node.attributes['name'];
		var value = this.getValue(key);
		if ((value != null) && (value.value != null) && (value.value.toString().length > 0)) {
			newNode.attributes['value'] = value.value;
		}
		return this.renderRegularNode(newNode);
	},
	
	renderPluginFormTextAreaNode: function(node) {
		this.func('renderPluginFormTextAreaNode');
		var newNode = Object.clone(node);
		var key = node.attributes['name'];
		var value = this.getValue(key);
		if ((value != null) && (value.value != null) && (value.value.toString().length > 0)) {
			newNode.children = new Array();
			var text = new Object();
			text.type = 'text';
			text.contents = value.value.toString().escapeHTML();
			newNode.children.push(text);
		}
		return this.renderRegularNode(newNode);
	},
	
	buildNodeAttributes: function(node, doSubstitution) {
		this.func('buildNodeAttributes');
		var str = '';
		var attrs = $H(node.attributes);
		var keys = attrs.keys();
			for (var i = 0; i < keys.length; i++) {
			var value = attrs.get(keys[i]);
			if (doSubstitution) {
				value = this.doSubstitution(value);
			}
			str += ' ' + keys[i] + '="' + value + '"';
		}
		return str;
	},
	
	doSubstitution: function(str) {
		this.func('doSubstitution');
		var index = str.indexOf('${');
		while (index >= 0) {
			if (str.indexOf('}', index) == -1) {
				break;
			}
			var endIndex = str.indexOf('}', index);
			var key = str.substring(index+2, endIndex);
			var value = this.getValue(key);
			if (value == null) {
				value = '';
			}
			if ((value != null) && (value.value != null)) {
				value = value.value;
			} else {
				value = '';
			}
			var tag = '${' + key + '}';
			str = str.replace(tag, value);
			index = str.indexOf('${');
		}
		return str;
	},
	
	getValue: function(key) {
		this.func('getValue');
		if (key.startsWith('show-') || key.startsWith('hide-')) {
			return this.getShownElementClass(key);
		}
		var value = this.getActualValue(key);
		if (value == null) {
			return undefined;
		}
		if (value.value == null) {
			if (value.defaultValue != null) {
				return value.defaultValue;
			}
			return undefined;
		}
		return value;
	},
	
	getActualValue: function(key) {
		this.func('getActualValue: ' + key);
		var index = key.indexOf('-');
		if (index >= 0) {
			var subkey1 = key.substr(0, index);
			var subkey2 = key.substr(index + 1);
			var parent = this.getActualValue(subkey1);
			if (parent != undefined) {
				this.values.push(parent);
				var value = this.getActualValue(subkey2);
				this.values.pop();
				return value;
			}
			return undefined;
		}
		for (var i = this.values.length - 1; i >= 0; i--) {
			if (this.values[i].fields == undefined) {
				continue;
			}
			var value = this.values[i].fields[key];
			if (! (value === undefined)) {
				return value;
			}
		}
		MvpWebTemplate.logError('Undefined value: ' + key);
		return undefined;
	},
	
	getShownElementClass: function(key) {
		this.func('getShownElementClass');
		var opposite = false;
		if (key.startsWith('hide-')) {
			opposite = true;
		}
		var show;
		if (MvpWebTemplate.shownElements[key.substr(5)] != undefined) {
			show = true;
		} else {
			show = false;
		}
		if (opposite) {
			show = ! show;
		}
		var result = Object();
		result.type = 'String';
		if (show) {
			result.value = 'show ' + 'CAF-' + key;
		} else {
			result.value = 'hide ' + 'CAF-' + key;
		}
		return result;
	},
	
	doStringFormats: function(value, format) {
		var index = format.lastIndexOf(',');
		if (index >= 0) {
			value = this.doStringFormats(value, format.substr(0, index));
			format = format.substr(index + 1);
		}
		if (format.startsWith("abbr:")) {
			var length = format.substr(5);
			if (value.length <= length) {
				return value;
			}
			var title = value.replace('/\n/g', '  ');
			return '<abbr title="' + title + '">' + value.substr(0, length) + '...</abbr>';
		}
		MvpWebTemplate.logError("Unknown String format: " + format);
	},
	
	func: function(func) {
		var last = $('lastFunction');
		if (last != undefined) {
			$('lastFunction').innerHTML=func;
		}
	}
});

MvpWebTemplate = new MvpWebTemplate_Class();
