
var VnObject = require ('./object');

var regex = /{{\s*[\w_]+\s*(\.\s*[\w_]+\s*)?}}/g;

/**
 * Replaces all ocurrences of {{value}} by it's corresponding value in the
 * scope lot.
 */
module.exports = new Class
({
	Extends: VnObject

	,_lots: {}
	,_links: []

	,initialize: function (builder)
	{
		this._builder = builder;
		this.parent ();
	}
	
	,compile: function (objContext, data, string)
	{
		var matchs = string.match (regex);

		if (!matchs)
			return null;

		var lots = this._lots;
		var links = this._links;

		var regLots = {};
		var params = [];

		var context = {
			objContext: objContext,
			data: data,
			string: string,
			params: params
		};

		for (var i = 0; i < matchs.length; i++)
		{
			var match = matchs[i];
			match = matchs[i].substr (2, match.length - 4);
			match = match.split ('.');

			var lotId;
			var name;
			
			if (match.length > 1)
			{
				lotId = match[0].trim ();
				name = match[1].trim ();
			}
			else
			{
				lotId = null;
				name = match[0].trim ();
			}

			params.push ({
				lotId: lotId,
				name: name
			});

			if (regLots[lotId] === undefined)
			{
				if (!lots[lotId])
					lots[lotId] = [];

				lots[lotId].push (context);
				regLots[lotId] = 1;
			}
		}

		links.push (context);
		return context;
	}
	
	,interpolate: function (link, scope)
	{
		var i = 0;
		var params = link.params;
		var $ = scope.$;

		return link.string.replace (regex, function () {
			var param = params[i++];
			var lotId = param.lotId;
			var lot = lotId ? $[lotId] : scope.lot;
			var value = lot ? lot.$[param.name] : null;
			return value != null ? value : '';
		});
	}

	,preLink: function (scope)
	{
		this._link (this._links, scope);
	}

	,_link: function (links, scope)
	{
		for (var i = 0; i < links.length; i++)
		{
			var link = links[i];
			var string = this.interpolate (link, scope);
			var object = scope.objects[link.objContext.id];
			link.objContext.compiler.setProperty (object, link.data, string);
		}
	}

	,getLot: function (lotId, scope)
	{
		return lotId == 'null' ? scope.lot : scope.$[lotId];
	}

	,postLink: function (scope)
	{
		for (var lotId in this._lots)
		{
			var lot = this.getLot (lotId, scope);

			if (lot)
				lot.on ('change', this.onLotChange.bind (this, lotId, scope), scope);
		}
	}

	,free: function (scope)
	{
		for (var lotId in this._lots)
		{
			var lot = this.getLot (lotId, scope);

			if (lot)
				lot.disconnectByInstance (scope);
		}
	}

	,onLotChange: function (lotId, scope)
	{
		this._link (this._lots[lotId], scope);
	}
});
