/*
 * fx.js
 *
 * Copyright (C) 2006 - OS3 srl - http://www.os3.it
 *
 * Written by: Fabio Rotondo - fabio.rotondo@os3.it
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation;
 * version 2 of the License ONLY.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * NOTE: this is the GPL version of the library. If you want to include this 
 *       library inside a CLOSED SOURCE / PROPRIETARY software, you need 
 *       to purchase a COMMERCIAL LICENSE. See http://www.os3.it/license/
 *       for more info.
 */

// liwe.fx = {};	// Defined in liwe.js

liwe.fx.priv = {};	// Private methods

// PUBLIC: liwe.fx.set_opacity
//
// Setta la trasparenza dell'oggetto ``e``
// con il valore di alpha ``val``.
// ``val`` deve essere compreso tra 0 e 100
//
// Restituisce il valore di ``val`` assegnato all'oggetto
liwe.fx.set_opacity = function ( el, val )
{
	el = $el ( el );

	if ( val > 100 ) val = 100;
	if ( val < 0 ) val = 0;

	if ( el.filters )
	{
		if ( ! el.filters.alpha ) el.style.filter = "alpha(opacity=" + val + ")";
		el.filters.alpha.opacity = val;
	} else {
		el.style.MozOpacity = val / 100;
		el.style.opacity = val / 100;
	}

	return val;
};

/*
	FADE IN/OUT
*/

liwe.fx.fade_in = function ( el, cback, millis, timing )
{
	liwe.fx.animate ( el, { opacity: 1 }, cback, millis, timing );
};

liwe.fx.fade_out = function ( el, cback, millis, timing )
{
	liwe.fx.animate ( el, { opacity: 0 }, cback, millis, timing );
};

/*
	SLIDE IN/OUT
*/

liwe.fx._slide_init = function ( el, dir ) 
{
	el = $el ( el );
	// TODO: gestire position absolute/fixed e parametro per slide top-rel bottom-rel
	el.style.position = 'fixed';
	el.style [ dir ] = 0;
};

liwe.fx.slide_in = function ( el, dir, cback, millis, timing )
{
	liwe.fx._slide_init ( el, dir );
	liwe.fx.animate ( el, { translate: 0 }, cback, millis, timing );
};

liwe.fx.slide_out = function ( el, dir, cback, millis, timing )
{
	liwe.fx._slide_init ( el, dir );
	var xy = null;
	switch ( dir )
	{
		case 'left':
			xy = [ '-100%', '0' ];
			break;
		case 'right':
			xy = [ '100%', '0' ];
			break;
		case 'top':
			xy = [ '0', '-100%' ];
			break;
		case 'bottom':
			xy = [ '0', '100%' ];
			break;
	}
	liwe.fx.animate ( el, { translate: xy }, cback, millis, timing );
};

/*
	FLIP
*/

liwe.fx.flip = function ( el, back, cback, millis, timing )
{
	liwe.fx.animate ( el, { flip: ( back ? '180deg' : '0' ) }, cback, millis, timing );
};

/*
	RESIZE
*/

liwe.fx.resize = function ( el, width, height, cback, millis, timing )
{
	el = $el ( el );
	if ( ! el ) return;

	var size = liwe.dom.get_size ( el );
	if ( ! el.style.width ) el.style.width = size [ 0 ] + 'px';
	if ( ! el.style.height ) el.style.height = size [ 1 ] + 'px';
	
	liwe.fx.animate ( el, { width: width, height: height }, cback, millis, timing );
};

/*
	SCALE
*/

liwe.fx.scale = function ( el, val, cback, millis, timing )
{
	liwe.fx.animate ( el, { scale: val }, cback, millis, timing );
};

/*
	MOVE (movimenti relativi)
*/

liwe.fx.move = function ( el, deltax, deltay, cback, millis, timing )
{
	liwe.fx.animate ( el, { move: [ deltax, deltay ] }, cback, millis, timing );
};

/*
	TRANSLATE (movimenti assoluti)
*/

liwe.fx.translate = function ( el, left, top, cback, millis, timing )
{
	liwe.fx.animate ( el, { translate: [ left, top ] }, cback, millis, timing );
}

/*
	PUSH (push a div against another)
*/
liwe.fx.push = function ( el_from, el_to, dir, cback, millis, timing )
{
	if ( ! liwe.utils.supports ( 'transition' ) )
	{
		liwe.fx.set_opacity ( el_from, 0 );
		liwe.fx.set_opacity ( el_to, 1 );
		return;
	}
	var xy_from = null;
	var xy_to = null;
	switch ( dir )
	{
		case 'left':
			xy_from = [ '100%', '0' ];
			xy_to = [ '-100%', '0' ];
			break;
		case 'right':
			xy_from = [ '-100%', '0' ];
			xy_to = [ '100%', '0' ];
			break;
		case 'top':
			xy_from = [ '0', '100%' ];
			xy_to = [ '0', '-100%' ];
			break;
		case 'bottom':
			xy_from = [ '0', '-100%' ];
			xy_to = [ '0', '100%' ];
			break;
	}
	liwe.fx.animate ( el_to, { opacity: 0 }, function () { 
		liwe.fx.animate ( el_to, { translate: xy_to }, function () { 
			liwe.fx.animate ( el_to, { opacity: 1 }, function () { 
				liwe.fx.animate ( el_to, { translate: 0 }, null, millis, timing );
				liwe.fx.animate ( el_from, { translate: xy_from  }, cback, millis, timing );
			}, 1 );
		}, 1 );
	}, 1 );
};

liwe.fx.scrolltouch = function ( el, container, left, top, cback, millis, timing )
{
	function callback ()
	{
		el = $el ( el );
		container = $el ( container );
		var size = liwe.dom.get_size ( el );
		var size_container = liwe.dom.get_size ( container );
		//var height = document.defaultView.getComputedStyle ( el ).height;
		//var height_container = document.defaultView.getComputedStyle ( container ).height;
		var max_x = size_container [ 0 ] - size [ 0 ];
		var max_y = size_container [ 1 ] - size [ 1 ];
		var current_x = el.get ( '_pos_x', 0 )
		var current_y = el.get ( '_pos_y', 0 );
		//var max_delta = parseInt ( height_container, 10 ) - parseInt ( height, 10 );
		//var cur_delta = el.get ( '_pos_y', 0 );
		var need_correct = false;
		
		var delta = [];
		delta [ 0 ] = current_x;
		delta [ 1 ] = current_y;
		
		if ( current_x < max_x )
		{
			need_correct = true;
			delta [ 0 ] = max_x;
			el [ '_pos_x' ] = max_x;
		}
		else if ( current_x > 0 )
		{
			need_correct = true;
			delta [ 0 ] = 0;
			el [ '_pos_x' ] = 0;
		}
		
		if ( current_y < max_y )
		{
			need_correct = true;
			delta [ 1 ] = max_y;
			el [ '_pos_y' ] = max_y;
		}
		else if ( current_y > 0 )
		{
			need_correct = true;
			delta [ 1 ] = 0;
			el [ '_pos_y' ] = 0;
		}


		if ( need_correct )
			liwe.fx.animate ( el, { translate: delta }, cback, millis, timing );
		else if ( cback ) cback ();
	};

	liwe.fx.move ( el, left, top, callback, millis, timing );
};

/*
	ABSOLUTIZE
*/

liwe.fx.absolutize = function ( el )
{
	el = $el ( el );
	if ( el.style.position == 'absolute' ) return;
	el.style.left = liwe.dom.get_offset_left ( el ) + 'px';
	el.style.top = liwe.dom.get_offset_top ( el ) + 'px';
	el.style.position = 'absolute';
};

/*
	ANIMATE
*/

liwe.fx.default_millis = 500;
liwe.fx.default_timing = 'linear';
liwe.fx._suffix_re = /[^\d]+$/;

liwe.fx.animate = function ( el, attributes, cback, millis, timing )
{
	el = $el ( el );
	if ( ! el ) return;
	setTimeout ( function () { liwe.fx._animate ( el, attributes, cback, millis, timing ); }, 0 );
};

liwe.fx._animate = function ( el, attributes, cback, millis, timing )
{
	if ( millis === undefined ) millis = liwe.fx.default_millis;
	if ( ! timing ) timing = liwe.fx.default_timing;

	var styles = {};
	var properties = [];
	var transform = [];
	var need_anim = false;
	var engine = liwe.fx._get_engine ( el );

	attributes.iterate ( function ( value, property )
	{
		if ( typeof ( value ) != 'object' )
			value = [ value ];

		switch ( property )
		{
			// casi "speciali"
			case 'flip':
				transform.push ( 'rotate3d(0, 1, 0, ' + value + ')' );
				break;
			// casi generici di transform
			case 'move':
			case 'rotate':
			case 'translate':
			case 'scale':
			case 'skew':
				if ( value.length == 1 )
					value [ 1 ] = value [ 0 ];

				var suffix = [];
				suffix [ 0 ] = String ( value [ 0 ] ).match ( liwe.fx._suffix_re  ) || '';
				suffix [ 1 ] = String ( value [ 1 ] ).match ( liwe.fx._suffix_re  ) || '';

				value [ 0 ] = parseFloat ( value [ 0 ] );
				value [ 1 ] = parseFloat ( value [ 1 ] );

				switch ( property )
				{
					case "move":
						value [ 0 ] += el.get ( '_pos_x', 0 );
						value [ 1 ] += el.get ( '_pos_y', 0 );
						// NO BREAK HERE!! :-)
					case "translate":
						el [ '_pos_x' ] = value [ 0 ];
						el [ '_pos_y' ] = value [ 1 ];
						
						property = 'translate';
						break;
				}
				
				if ( property != 'scale' )
				{
					if(suffix [ 0 ] == '' )
						suffix [ 0 ] = ( property == 'rotate' || property == 'skew' ) ? 'deg' : 'px';
					if(suffix [ 1 ] == '' )
						suffix [ 1 ] = ( property == 'rotate' || property == 'skew' ) ? 'deg' : 'px';
				}

				if ( engine.is_3d && ( property == 'rotate' || property == 'translate' ) )
				{
					property += '3d';
					value [ 2 ] = 0;
				}

				value [ 0 ] += suffix [ 0 ];
				value [ 1 ] += suffix [ 1 ];
				
				
				value = value.join ( ', ' );
				transform.push ( property + '(' + value + ')' );
				break;
			// tutti gli altri css
			case 'left':
			case 'right':
			case 'top':
			case 'bottom':
				if ( el.style [ property ] == '' )
				{
					el.style [ property ] = liwe.dom.get_style ( el, property );
				}
				//liwe.fx.absolutize ( el );
			default:
				value = value.join ( ', ' );
				styles [ property ] = value;
				properties.push ( property );
				if ( el.style [ property ] !== value ) need_anim = true;
				break;
		}
	} );

	if ( transform.length > 0 )
	{
		styles [ engine.js_transform ] = transform.join ( ' ' );
		properties.push ( engine.css_transform );
		if ( el.style [ engine.js_transform ] != styles [ engine.js_transform ] ) need_anim = true;
	}

	if ( ! need_anim )
	{
		if ( cback ) cback ();
		return;
	}

	if ( engine.transition && millis > 0 )
	{
		el.style [ engine.js_transition + 'Property' ] = properties.join ( ', ' );
		el.style [ engine.js_transition + 'Duration' ] = millis + 'ms';
		el.style [ engine.js_transition + 'TimingFunction' ] = timing;

		var evthandler = function ( event )
		{
			this.style [ engine.js_transition + 'Property' ] = '';
			this.style [ engine.js_transition + 'Duration' ] = '';
			this.style [ engine.js_transition + 'TimingFunction' ] = '';
			this.removeEventListener ( engine.transition, evthandler );
			
			if ( cback ) cback ();
		};

		el.addEventListener ( engine.transition, evthandler, false );
	}

	styles.iterate ( function ( value, property ) 
	{
		el.style [ property ] = value;
	});

	if ( ! engine.transition && cback )
	{
		cback ();
	}
};

liwe.fx._get_engine = function ( el )
{
	var engine = {};
	engine.is_3d = false;

	if ( el.style.WebkitTransform !== undefined )
	{
		engine.css_transform = '-webkit-transform';
		engine.js_transform = 'WebkitTransform';
		engine.js_transition = 'WebkitTransition';
		engine.transition = 'webkitTransitionEnd';
		engine.is_3d = true;
	}
	else if ( el.style.MozTransform !== undefined )
	{
		engine.css_transform = '-moz-transform';
		engine.js_transform = 'MozTransform';
		engine.js_transition = 'MozTransition';
		engine.transition = 'transitionend';
	}
	else if ( el.style.OTransform !== undefined )
	{
		engine.css_transform = '-o-transform';
		engine.js_transform = 'OTransform';
		engine.js_transition = 'OTransition';
		engine.transition = 'oTransitionEnd';
	}
	else if ( el.style.msTransform !== undefined )
	{
		engine.css_transform = '-ms-transform';
		engine.js_transform = 'msTransform';
		engine.js_transition = '';
		engine.transition = '';
	}
	else if ( liwe.utils.supports ( 'transform' ) )
	{
		engine.css_transform = 'transform';
		engine.js_transform = 'transform';
		engine.js_transition = 'transition';
		engine.transition = 'transitionEnd';
	}
	
	return engine;
};

