/*
	var tpl = new HTpl
	(
			["div", {"htpl:t": "foo"}, {"id": "foo"}, {"class": "foo"}, [
				"FOO ",
				["div", {"htpl:t": "baz"}, {"class": "baz"}, {"style": "border: 1px solid {border-color}; margin: 16px; padding: 8px; background-color: cyan;"}, [
					"Name: {name}",
					["hr", {"class": "glorp"}],
					"Descr ({name}):",
					["span", "{descr}"]
				]],
				["hr"],
				"---"
			]]
	);
	
	var vals, baces =
	[
		{"name": "BAZ-A", "descr": "DESCRIPTION BAZ-A", "border-color": "green"},
		{"name": "BAZ-B", "descr": "DESCRIPTION BAZ-B", "border-color": "navy"},
		{"name": "BAZ-C", "descr": "DESCRIPTION BAZ-C", "border-color": "orange"}
	];
	vals = {"baz": null}
	tpl.sprintEach("baz", baces, vals);
	var baxter = document.getElementById("baxter");
	baxter.innerHTML(tpl.toDOM("foo", vals));
*/
if (!window.liltype)
{
	var liltype = {};
}

liltype.HTpl = function()
{
	if (arguments.length)
	{
		this.ns = arguments[1] ? arguments[1] : ["htpl", "http://liltype.com/HTpl"];
		this.stack = null;
		this.tpls = {};
		this.nsRegExp = new RegExp("^"+this.ns[0]+":");
		this.parse(arguments[0]);
	}
}
new liltype.HTpl();

liltype.HTpl.prototype =
{
	"valRegExp": /\{([a-z0-9\-_\.\!\/]+)\}/i,
	"nsRegExp": null,
	"isArray": function(obj)
	{
		return (obj[0] !== undefined) && (obj[0] !== null) && (""+obj[0]).length;
	},
	"getAtt": function(k, atts)
	{
		var i, c, v;
		for (i = 0, c = atts.length; i < c; i++)
		{
			if (((v = atts[i][k]) !== null) && (v !== undefined))
			{
				return v;
			}
		}
		return null;
	},
	"parse": function(n)
	{
		var len = n.length, atts = [], children = null, iu, nu, id, tpln, i, c;

		if (typeof n == "string")
		{
			if (this.stack !== null)
			{
				this.stack.node.children.push(n);
				return;
			}
		}
		else if (len == 0)
		{
			return;
		}
		else if (len == 1)
		{
			children = [];
		}
		else if (len == 2)
		{
			if (typeof n[1] == "string")
			{
				children = [n[1]];
			}
			else if (this.isArray(n[1]))
			{
				children = n[1];
			}
			else
			{
				atts = [n[1]];
				children = [];
			}
		}
		else
		{
			nu = n[(iu = len - 1)];
			if (typeof nu == "string")
			{
				atts = n.slice(1, iu);
				children = [nu];
			}
			else if (this.isArray(nu))
			{
				atts = n.slice(1, iu);
				children = nu;
			}
			else
			{
				atts = n.slice(1);
				children = [];
			}
		}
		
		tpln =
		{
			"tag": n[0],
			"atts": atts,
			"children": []
		}
		if ((id = this.getAtt(this.ns[0]+":t", atts)) !== null)
		{
			if (this.stack !== null)
			{
				this.stack.node.children.push({"subTpl": id});
			}
			this.tpls[id] = tpln;
		}
		else if (this.stack !== null)
		{
			this.stack.node.children.push(tpln);
		}
		
		this.stack =
		{
			"node": tpln,
			"next": this.stack
		};
		for (i = 0, c = children.length; i < c; i++)
		{
			this.parse(children[i]);
		}
		this.stack = this.stack.next;
	},
	"sprintStr": function(str, vals)
	{
		var m, v, i, c, ks;
		if ((str === undefined) || (str === null) || !str.length)
		{
			return "";
		}

		while (m = str.match(this.valRegExp))
		{
			ks = m[1].split(/\//);
			v = vals;
			for (i = 0, c = ks.length; i < c; i++)
			{
				if (((v = v[ks[i]]) === undefined) || (v === null) || (typeof v == "string") || (typeof v == "number") || (typeof v == "boolean"))
				{
					break;
				}
			}
			v = ""+(((v === null) || (v === undefined)) ? "" : v);
			str = str.replace(new RegExp("\\{"+m[1]+"\\}", "g"), v);
		}
		return str;
	},
	"sprintNode": function(n, vals)
	{
		var i, c, html = "", k;
		
		if (n === undefined)
		{
			alert("Foo");
			return "";
		}

		if (typeof n == "string")
		{
			return this.sprintStr(n, vals);
		}
		else if (n.subTpl)
		{
			return this.sprintStr("{"+n.subTpl+"}", vals);
		}

		html += "<"+n.tag;
		for (i = 0, c = n.atts.length; i < c; i++)
		{
			for (k in n.atts[i])
			{
				if (!k.match(this.nsRegExp))
				{
					html += (" "+k+"=\""+this.sprintStr(n.atts[i][k], vals).replace(/\"/g, "&quot;")+"\"");
				}
			}
		}
		if (c = n.children.length)
		{
			html += ">";
			for (i = 0; i < c; i++)
			{
				html += this.sprintNode(n.children[i], vals);
			}
			html += "<"+"/"+n.tag;
		}
		else
		{
			html += "/";
		}
		html += ">";
		return html;
	},
	"sprint": function(tplK)
	{
		var tpl, vals = arguments[1] ? arguments[1] : {}, html;
		if (tpl = this.tpls[tplK])
		{
			return this.sprintNode(tpl, vals);
		}
		return "";
	},
	"sprintEach": function(tplK, valsSrc, valsTgt)
	{
		var i, c, tpl;
		if (tpl = this.tpls[tplK])
		{
			if ((valsTgt[tplK] === null) || (valsTgt[tplK] === undefined))
			{
				valsTgt[tplK] = "";
			}

			if (this.isArray(valsSrc))
			{
				for (i = 0, c = valsSrc.length; i < c; i++)
				{
					valsTgt[tplK] += this.sprintNode(tpl, valsSrc[i]);
				}
			}
			else
			{
				valsTgt[tplK] += this.sprintNode(tpl, valsSrc);
			}
		}
	}
};
