/**
 * Fx.Morpher - Extended Fx.Morph plugin
 *
 * Dependencies: MooTools 1.2 [Core]
 *
 * @version			0.5 (20081024)
 *
 * @license			MIT-style license
 * @author			Ivanicus <ivannpaz [at] gmail.com>
 * @copyright		Author???
 * @documentation	{coming soon}
 *
 * Big thanks for your help:
 *
 * > Rajeev J Sebastian
 * > johnwait
 */


/*
Hash: Fx.RegPoint
	Common Regpoints 'Constant' used
*/
Fx.RegPoint = {
	'TopLeft':		{x:0, 	y:0},
	'Top': 			{x:0.5, y:0},
	'TopRight':		{x:1, 	y:0},
	'Left':			{x:0, 	y:0.5},
	'Center': 		{x:0.5, y:0.5},
	'Right': 		{x:1, 	y:0.5},
	'BottomLeft': 	{x:0, 	y:1},
	'Bottom': 		{x:0.5, y:1},
	'BottomRight': 	{x:1, 	y:1}
};

/*
Class: Fx.Morpher
	Fx.Morph extended

Arguments:
	Same as Fx.Morph with the addition of extra options:
	- path: pathClass
	- usepath: array of properties that will use the path ['top', 'left']
	- regpoint: A Fx.RegPoint.* value, defines the registration point.
	* more to come
*/
Fx.Morpher = new Class({

	Extends: Fx.CSS,

	options: {
		path: null,
		regpoint: Fx.RegPoint.TopLeft,
		usepath: ['top', 'left']
	},

	//directly copied from mootools core (Fx.Morph)
	initialize: function(element, options){
		this.element = this.subject = $(element);
		this.parent(options);
	},

	//directly copied from mootools core (Fx.Morph)
	set: function(now){
		if (typeof now == 'string') now = this.search(now);
		for (var p in now) this.render(this.element, p, now[p], this.options.unit);
		return this;
	},

	getRegistration: function(val, axis){
		//var prop = (axis == 'x' ? 'width' : 'height');
		//parseInt(this.element.getStyle('left'))
	},

	//translates value using RegPoint
	translate: function(value, axis, from){
		//[0, 0.5, 1]
		//var value 	= ((typeof val) == 'object') ? (val[0]).value : val;
		//var parser 	= ((typeof val) == 'object') ? (val[0]).parser : parser;
		//console.log(value);
		var prop = (axis == 'x' ? 'width' : 'height');
		var result = parseInt((value - (parseInt(this.element.getStyle(prop)) * this.options.regpoint[axis])));

		var computed = [{value: result, parser: from[0].parser}];
		computed.$family = {name: 'fx:css:value'};
		return computed;
	},

	//called at intervals to compute the current css values
	compute: function(from, to, delta){
		var now = {};
		var x, y;

		//check if we have a motion path
		var path = (this.options.path ? this.options.path : false);

		//if(!DEBUGGED) console.dir(from);

		for (var p in from)
		{
			//Only calc coords if there's a path
			//and only do it for the axis that can be morphes [x || y]
			if(path && this.options.usepath.contains(p)) {
				var coords = path.getCoordinates(1 - delta);
				//TODO: make it work with usepath[] and avoid that if/then crap...
				if(p == 'left') x =coords.x;
				if(p == 'top') y = coords.y;
			}

			switch(p) {
				case 'left':
						now[p] = (path ?  this.translate(x, 'x', from[p]) : this.parent(from[p], to[p], delta));
						break;

				case 'top':
						now[p] = (path ? this.translate(y, 'y', from[p]) : this.parent(from[p], to[p], delta));
						break;

				case 'width':
						now[p] = this.parent(from[p], to[p], delta);
						//if we do not calc left motion, then do it here
						/*
						if(!$defined(from['left'])) {
							var regx = this.element.retrieve('regx', parseInt(this.element.getStyle('left')));
							now['left'] = this.translate(regx, 'x', from[p]);
						}
						*/
						break;

				case 'height':
						now[p] = this.parent(from[p], to[p], delta);
						/*
						if(!$defined(from['top'])) {
							var regy = this.element.retrieve('regy', parseInt(this.element.getStyle('top')));
							now['top'] = this.translate(regy, 'y', from[p]);
						}
						break;
						*/
				default:
					//standard mootools calculation
					now[p] = this.parent(from[p], to[p], delta);
			}
		}

		//stop debugging
		//if(!DEBUGGED) DEBUGGED = true;

		return now;
	},

	//Modded from mootools core (Fx.Morph)
	//TODO: cleanup, optimization and some rewrite
	start: function(properties, paused){
		//quick check to allow start with no args and motionpath
		if(!properties) properties = {};

		if (!this.check(arguments.callee, properties)) return this;
		if (typeof properties == 'string') properties = this.search(properties);

		//add a dummy 'top', 'left', 'whatever' in order to trigger compute
		var usepath = this.options.usepath;
		if(this.options.path && usepath.length) {
			//TODO: make it work with usepath[] and avoid that if/then crap...
			//add dummy values to trigger compute
			if(usepath.contains('top')) $extend(properties, {top:[0,1]});
			if(usepath.contains('left')) $extend(properties, {left:[0,1]});
		}

		var from = {}, to = {};
		for (var p in properties){
			var parsed = this.prepare(this.element, p, properties[p]);
			from[p] = parsed.from;
			to[p] = parsed.to;
		}
		return this.parent(from, to);
	}

});

Element.Properties.morpher = {

	set: function(options){
		var morph = this.retrieve('morpher');
		if (morph) morph.cancel();
		return this.eliminate('morpher').store('morpher:options', $extend({link: 'cancel'}, options));
	},

	get: function(options){
		if (options || !this.retrieve('morpher')){
			if (options || !this.retrieve('morpher:options')) this.set('morpher', options);
			this.store('morpher', new Fx.Morpher(this, this.retrieve('morpher:options')));
		}
		return this.retrieve('morpher');
	}

};

Element.implement({

	morpher: function(props, paused){
		this.get('morpher').start(props, paused);
		return this;
	}

});