/**
*
* JavaScript knihovna pro efekty
*
* @package		sllibs3
* @subpackage	jslibs
* @version		$Id: sl.effect.js 16668 2010-04-29 12:32:23Z michal $
* @encoding		UTF-8
* @author		Filip Zach <filip.zach@e4you.cz>
* @copyright	(c) e4you spol. s r.o. 2002-2010, <design@e4you.cz>
*
* Obsah tohoto souboru je majetkem e4you spol. s r.o. Jeho kopírování,
* pozměňování, šíření a jakékoli další využití je možné výhradně
* se souhlasem e4you spol. s r.o.
*
*/

/// pokud není knihovna označena jako natažená, načteme ji
if(!sl.loaded['sl.effect.js']) {

	/// vložíme potřebné knihovny
	sl.require('sl.dom.js');
	sl.require('sl.event.js');

	/// definujeme modul a jeho metody
	sl.effect = {

		/**
		* Defaultní čas (v milisekundách), po kterém proběhne ztmavení mizejícího obrázku
		* @var integer
		*/
		default_opacity_time: 30,

		/**
		* Defaultní krok o který bude ztmaven, mizející obrázek
		* @var float
		*/
		default_opacity_step: 0.2,

		/**
		*
		* @var integer
		*/
		default_opacity_length: 2000,

		/**
		* Defaultní čas (v milisekundách), po kterém proběhne změna velikosti obrázku
		* @var integer
		*/
		default_resize_time: 10,

		/**
		* Defaultní krok o který bude ztmaven, mizející obrázek
		* @var float
		*/
		default_resize_step: 40,

		/**
		 * Offset x objektu od myši pro funkci followMouse
		 */
		follow_mouse_offset_x: 5,

		/**
		 * Offset x objektu od myši pro funkci followMouse
		 */
		follow_mouse_offset_y: 20,

		/**
		* Zobrazí animovaný prvek prvek indikující, že probíhá nějaká akce
		*/
		_showProcessingInfo: function() {
			try {
				sl.dom.addClass(this.target_object,'sl_effect_processing_info');
			} catch (e) {
				/// alert (e);
			}
		},

		/**
		* Skryje animovaný prvek indikující, že probíhá nějaká akce
		*/
		_hideProcessingInfo: function() {
			try {
				sl.dom.removeClass(this.target_object,'sl_effect_processing_info');
			} catch (e) {}
		},

		/**
		 * Vycentruje objekt vertikálně a horizontálně vůči oknu se zohledněním aktuálního offsetu okna
		 */
		_center : function () {
			if (this.target_object) {
				this.target_object.effect_factory.centerVerticaly();
				this.target_object.effect_factory.centerHorizontaly();
			}
		},

		/**
		 * Vycentruje objekt horizontálně vůči oknu se zohledněním aktuálního offsetu okna
		 */
		_centerHorizontaly : function () {
			if (this.target_object) {
				var window_size = sl.getBrowserWindowSize();
				var scroll_position = sl.getBrowserScrollPosition();
				var left_position = ( (window_size.width/2) - (this.target_object.offsetWidth/2) ) + scroll_position.x;
				left_position = left_position>=0 ? left_position : 0;
				this.target_object.style.left = left_position+"px";
			}
		},

		/**
		 * Vycentruje objekt vertikálně vůči oknu se zohledněním aktuálního offsetu okna
		 */
		_centerVerticaly : function () {
			if (this.target_object) {
				var _element = this.target_object;
				var _position_fixed = false;
				while (_element) {
					if (_element.parentNode) {
						_element = _element.parentNode;
						try {
							/// zjistíme, jestli má rodič nastaven CSS styl position na fixed
							if (sl.dom.getCSSProperty(_element, 'position') == 'fixed') {
								_position_fixed = true;
								break;
							}
						} catch(exception) {}
					} else {
						break;
					}
				}

				var window_size = sl.getBrowserWindowSize();
				var scroll_position = sl.getBrowserScrollPosition();
				/// pokud má nějaký předek objektu který vertikálně centrujeme CSS style position fixed, tak nastaváme y-vou pozici na 0
				if (_position_fixed) {
					 scroll_position.y = 0;
				}
				var top_position = ( (window_size.height/2) - (this.target_object.offsetHeight/2) ) + scroll_position.y - 20;
				top_position = top_position>=0 ? top_position : 0;
				this.target_object.style.top = top_position+"px";
			}
		},

		/**
		 * Vrátí hodnotu kroku pro změnu rozměru prvku
		 * Mění se dynamicky, podle toho, v jaké fázi změny velikosti se rozměr nachází - ke konci zpomaluje
		 *
		 * @param integer final_size Cílový rozměr
		 * @param integer current_size Aktuální rozměr
		 * @param integer start_range Počáteční rozdíl mezi aktuálním a cílovým rozměrem
		 *
		 * @todo Implementovat minimální velikost kroku
		 */
		getResizeStep :  function(final_size,current_size,start_range) {
			/// ???
			if ( start_range == 0 ) {
				return sl.effect.default_resize_step / 2;
			}
			/// zjistíme rozdíl mezi aktuálním a cílovým rozměrem
			/// a z něj v jaké fázi se změna rozměru nachází
			/// vypočítáme velikost kroku
			var resize_step =  Math.ceil( Math.abs(current_size - final_size) / start_range * 100  );
			/// je-li větší než výchozí velikosti kroku, použijeme výchozí
			if (resize_step > sl.effect.default_resize_step ) {
				resize_step = sl.effect.default_resize_step;
			}
			return resize_step;
		},


		/**
		 * Plynule změní šříku prvku
		 *
		 * @param Integer new_width Nová šířka prvku
		 * @param boolean center Má-li se objekt při změně velikosti zároveň centrovat
		 * @param function callback_function Funkce, která se zavolá po ukončení akce
		 *
		 * @todo Sloučit kod funkce _resizeWidth s funkcí _resizeHeight
		 */
		_resizeWidth : function (final_width, center, callback_function, effect_resize_step, effect_resize_time) {

			var center_object_on_page = center || false;
			var resize_step = effect_resize_step || sl.effect.default_resize_step;
			var resize_time = effect_resize_time || sl.effect.default_resize_time;
			var target_object = this.target_object;
			var current_width = target_object.offsetWidth;
			/// detekujeme jestli budeme rozměr zvětšovat, nebo zmenšovat
			var scale_up = final_width > current_width;

			var start_range = Math.abs(current_width  - final_width);

			/// definujeme interval, který zajistí plynulou změnu velikosti prvku
			var width_resize_interval = setInterval( function() {

				/// detekujeme, jestli jsme již nedosáhli požadovaného rozměru
				/// detekce je odlišná pokud rozměr zvětšujeme, nebo zmenšujeme
				if (	( scale_up && (current_width >= final_width) )
						||
						( !scale_up && (current_width <= final_width) )
					) {
					/// vyčištěním intervalu zastavíme vykonávání cyklu
					clearInterval(width_resize_interval);
					/// je-li definována návratová funkce, vykonáme ji
					if (callback_function) {
						callback_function();
					}
				}

				resize_step = sl.effect.getResizeStep(final_width,current_width,start_range);

				/// úprava rozměru prvku o zadaný krok
				/// pokud rozměr zvětšujeme
				if ( scale_up ) {
					current_width = current_width + resize_step;
					/// pokud je vypočítaná velikost větší než cílová velikost, použijeme cílovou velikost
					if (current_width > final_width) {
						current_width = final_width;
					}
				/// pokud rozměr zmenšujeme
				} else {
					current_width = current_width - resize_step;
					/// pokud je vypočítaná velikost menší než cílová velikost, použijeme cílovou velikost
					if (current_width < final_width) {
						current_width = final_width;
					}
				}

				/// nastavíme nový rozměr
				target_object.style.width = current_width+'px';

				/// pokud je zapnuto centrování, objekt vycentrujeme
				if (center_object_on_page) {
					target_object.effect_factory.centerHorizontaly();
				}

			}, resize_time);

		},

		/**
		 * Plynule změní výšku prvku
		 *
		 * @param Integer new_height Nová výška prvku
		 * @param function callback_function Funkce, která se zavolá po ukončení akce
		 *
		 * @todo Sloučit kod funkce _resizeWidth s funkcí _resizeHeight
		 *
		 */
		_resizeHeight : function (final_height,center,callback_function, effect_resize_step, effect_resize_time) {

			var center_object_on_page = center || false;
			var resize_step = effect_resize_step || sl.effect.default_resize_step;
			var resize_time = effect_resize_time || sl.effect.default_resize_time;
			var target_object = this.target_object;
			var current_height = target_object.offsetHeight;
			/// detekujeme jestli budeme rozměr zvětšovat, nebo zmenšovat
			var scale_up = final_height > current_height;

			var start_range = Math.abs(current_height - final_height);

			/// definujeme interval, který zajistí plynulou změnu velikosti prvku
			var height_resize_interval = setInterval( function() {

				/// detekujeme, jestli jsme již nedosáhli požadovaného rozměru
				/// detekce je odlišná pokud rozměr zvětšujeme, nebo zmenšujeme
				if ( 	( scale_up && (current_height >= final_height) )
						||
						( ! scale_up && (current_height <= final_height) )
					) {
					/// vyčištěním intervalu zastavíme vykonávání cyklu
					clearInterval(height_resize_interval);
					/// je-li definována návratová funkce, vykonáme ji
					if (callback_function) {
						callback_function();
					}
				}

				resize_step = sl.effect.getResizeStep(final_height,current_height,start_range);

				/// úprava rozměru prvku o zadaný krok
				/// pokud rozměr zvětšujeme
				if ( scale_up ) {
					current_height = current_height + resize_step;
					/// pokud je vypočítaná velikost větší než cílová velikost, použijeme cílovou velikost
					if (current_height > final_height) {
						current_height = final_height;
					}
				} else {
					current_height = current_height - resize_step;
					/// pokud je vypočítaná velikost menší než cílová velikost, použijeme cílovou velikost
					if (current_height < final_height) {
						current_height = final_height;
					}
				}

				/// nastavíme nový rozměr
				target_object.style.height = current_height+'px';

				/// pokud je zapnuto centrování, objekt vycentrujeme
				if (center_object_on_page) {
					target_object.effect_factory.centerVerticaly();
				}

			}, resize_time);

		},

		/**
		 * Nastaví průhlednost
		*/
		_setOpacity : function(new_opacity) {
			/// pro IE
			if (this.opacity_filter) {
				this.target_object.style.filter = 'alpha(opacity=' + (new_opacity * 100) + ')';
				/// pro slušné prohlížeče
			} else {
				this.target_object.style.opacity =  new_opacity ;
			}
		},


		/**
		 * Skryje objekt postupným snížením průhlednosti
		 *
		 * @param Float diming_step Nepovinný argument, určující velikost kroku při nastavení průhlednosti
		 * @param Float diming_time Nepovinný argument, určující rychlost nastavení průhlednosti
		 * @param function callback_function Funkce, která se zavolá po ukončení akce
		 *
		 * @todo Sloučit kód s funkcí _appear
		 */
		_dim : function (opacity_step, opacity_time, callback_function) {

			opacity_step = opacity_step || sl.effect.default_opacity_step;
			opacity_time = opacity_time || sl.effect.default_opacity_time;
			var target_object = this.target_object;

			/// aktuální průhlednost
			var current_opacity = 1;
			target_object.effect_factory.setOpacity(current_opacity);

			clearInterval(this.appearing_interval);
			clearInterval(this.dimming_interval);

			var dimming_interval = setInterval( function() {

				/// pokud je prvek již zcela skrytý
				if ( current_opacity<=0 ) {
					/// zastavíme provádění funkce
					clearInterval(dimming_interval);
					target_object.style.visibility = 'hidden';
					/// je-li definována návratová funkce, vykonáme ji
					if (callback_function) {
						callback_function();
					}
				}

				target_object.effect_factory.setOpacity(current_opacity);
				current_opacity = (current_opacity-opacity_step).toFixed(2);

			}, opacity_time);

			this.dimming_interval = dimming_interval;

		},


		/**
		 * Zobrazí objekt postupným zvýšením průhlednosti
		 *
		 * @param Float diming_step Nepovinný argument, určující velikost kroku při nastavení průhlednosti
		 * @param Float diming_time Nepovinný argument, určující rychlost nastavení průhlednosti
		 * @param function callback_function Funkce, která se zavolá po ukončení akce
		 *
		 * @todo Sloučit kód s funkcí _dim
		 */
		_appear : function (opacity_step, opacity_time, callback_function) {

			this.target_object.style.visibility = 'visible';

			opacity_step = opacity_step || sl.effect.default_opacity_step;
			opacity_time = opacity_time || sl.effect.default_opacity_time;
			var target_object = this.target_object;

			/// aktuální průhlednost
			var current_opacity = 0;
			target_object.effect_factory.setOpacity(current_opacity);

			clearInterval(this.appearing_interval);
			clearInterval(this.dimming_interval);

			/// spustíme anonymní funkci, která zajistí přechod od nulové do plné průhlednosti
			var appearing_interval = setInterval(function() {

				/// pokud jsme dosáhli plné viditelnosti
				if (current_opacity >= 1) {
					/// zastavíme provádění funkce
					clearInterval(appearing_interval);
					/// je-li definována návratová funkce, vykonáme ji
					if (callback_function) {
						callback_function();
					}
				}

				target_object.effect_factory.setOpacity(current_opacity);
				current_opacity = (current_opacity+opacity_step);

			}, opacity_time);

			this.appearing_interval = appearing_interval;

		},

		/**
		 * Nastaví html prvkům s předanou css třídou efekt kulatých rohů
		 *
		 * @param string Css třída prvků, není-li zadána, použíje se třída sl_shaddow_box
		 * @param document _document objekt dokumentu v němž id hledáme (není-li zadán použije se aktuální document)
		 */
		_addRoundCorners: function() {
			// try {
				var top_shaddow = document.createElement('SPAN');
				/// nefunguje v IE7
				/// top_shaddow.setAttribute('class', 'top_shaddow');
				top_shaddow.className = 'sl_effect_top_shaddow';
				this.target_object.parentNode.insertBefore(top_shaddow,this.target_object);

				var top_left_shaddow = document.createElement('SPAN');
				top_left_shaddow.className = 'sl_effect_top_left_shaddow';
				top_shaddow.appendChild(top_left_shaddow);

				var left_shaddow = document.createElement('SPAN');
				left_shaddow.className = 'sl_effect_left_shaddow';
				this.target_object.parentNode.insertBefore(left_shaddow,this.target_object);

				var right_shaddow = document.createElement('SPAN');
				right_shaddow.className = 'sl_effect_right_shaddow';
				left_shaddow.appendChild(right_shaddow);

				var bottom_shaddow = document.createElement('SPAN');
				bottom_shaddow.className = 'sl_effect_bottom_shaddow';
				this.target_object.parentNode.appendChild(bottom_shaddow);

				var left_bottom_shaddow = document.createElement('SPAN');
				left_bottom_shaddow.className = 'sl_effect_left_bottom_shaddow';
				bottom_shaddow.appendChild(left_bottom_shaddow);

				right_shaddow.appendChild(this.target_object);

			// } catch (e) {};
		},


		/**
		* Pozicuje objekt podle polohy ukazatele myši
		*
		* @param _object objekt, kterému přiřazujeme ovladač události
		* @param _event_name jméno události, pro kterou přiřazujeme ovladač
		*
		* @todo provést refaktoring funkce this.mouse_follow_handler
		*/
		_followMouse: function(event_object,event_name) {

			/// není-li předán objekt, nad kterým se vyvolá událost, nastavíme celý dokument
			/// pozor - nejedná se o objekt, který se pohybuje, ale o objekt, nad nějž když umístíme myš, vyvolá se handler
			event_object = event_object || document;
			/// není-li definováno jméno události, nastavíme pohyb myši
			event_name = event_name || 'mousemove';

			var target_object = this.target_object;

			/// definujeme handler pro pozicování myši
			/// @todo Přesunout handler this.mouse_follow_handler do samostatné prototypové funkce tak, aby nebyla definována pro každý handler zvlášť
			this.mouse_follow_handler= function (e) {

				/// detekujeme objekt s událostí
				var event = sl.event.getEvent(e);

				/// zjistíme aktuální polohu myši na stránce
				var cursor_x=event.clientX + sl.dom.getPageXOffset();
				var cursor_y=event.clientY + sl.dom.getPageYOffset();

				/// vzdalenost od ukazatele mysi k okraji obrazovky
				var rightedge = sl.dom.getWindowInnerWidth()-event.clientX-sl.effect.follow_mouse_offset_x;
				var bottomedge = sl.dom.getWindowInnerHeight()-event.clientY-sl.effect.follow_mouse_offset_y;

				/// ????
				var leftedge=(sl.effect.follow_mouse_offset_x<0)? sl.effect.follow_mouse_offset_x*(-1) : -1000;

				// pokud je vzdalenost okraj - ukazatel mensi nez div, posuneme ho o jeho sirku doleva
				if (rightedge<target_object.offsetWidth) {
					target_object.style.left=sl.dom.getPageXOffset()+event.clientX-target_object.offsetWidth+"px";
				} else if (cursor_x<leftedge) {
					target_object.style.left='5px';
				} else {
					target_object.style.left=cursor_x+sl.effect.follow_mouse_offset_x+'px';
				}

				// pokud je vzdalenost okraj - ukazatel mensi nez div, posuneme ho o jeho vysku
				if (bottomedge<target_object.offsetHeight) {
					target_object.style.top = sl.dom.getPageYOffset()+event.clientY-target_object.offsetHeight+"px";
				} else {
					target_object.style.top=cursor_y+sl.effect.follow_mouse_offset_y+"px";
				}
			}

			/// nastavíme handler objektu
			sl.event.addHandler(event_object, event_name, this.mouse_follow_handler);

		},


		/**
		* Zastaví pozicování objektu podle polohy ukazatele myši
		*
		* @param _object objekt, kterému přiřazujeme ovladač události
		* @param _event_name jméno události, pro kterou přiřazujeme ovladač
		*/
		_stopFollowingMouse: function (event_object,event_name) {

			/// není-li předán objekt, nad kterým se vyvolá událost, nastavíme celý dokument
			event_object = event_object || document;
			/// není-li definováno jméno události, nastavíme pohyb myši
			event_name = event_name || 'mousemove';

			sl.event.removeHandler(event_object, event_name, this.mouse_follow_handler);
		}


	}


	/**
	* Konstruktor objektu sl.effect_factory
	*
	* @param Object target_object Objekt, na který budou aplikovány efekty
	*
	* @todo vzhledem k tomu ze nejde o vzor Factory ale o Decorator - stalo by za zvazeni prejmenovani tohoto objektu
	*/
	sl.effect_factory = function(target_object) {

		/**
		 * Uložíme si cílový objekt
		 */
		this.target_object = target_object;

		/**
		 * Inicializujeme mu vlastnost effect_factory, obsahující metody pro práci s efekty
		 */
		this.target_object.effect_factory = this;

		/**
		 * Odkaz na handler pro funkci followMouse
		 */
		this.mouse_follow_handler = null;

		/**
		 * Identifikátor intervalu pro nastavení průhlednosti objektu
		 */
		this.appearing_interval = null;

		/**
		 * Identifikátor intervalu pro nastavení průhlednosti objektu
		 */
		this.dimming_interval = null;

		/// cachujeme informaci o způsobu nastavení průhlednosti (kvůli IE)
		/// @todo - zjistit, jestli opravdu zrychlí běh v ie
		this.opacity_filter = this.target_object.style.filter!=undefined;

	}

	/**
	 * Inicializace prototypových funkcí objektu sl.efect_factory
	 */
	sl.effect_factory.prototype.dim = sl.effect._dim;
	sl.effect_factory.prototype.appear = sl.effect._appear;
	sl.effect_factory.prototype.center = sl.effect._center;
	sl.effect_factory.prototype.centerHorizontaly = sl.effect._centerHorizontaly;
	sl.effect_factory.prototype.centerVerticaly = sl.effect._centerVerticaly;
	sl.effect_factory.prototype.resizeWidth = sl.effect._resizeWidth;
	sl.effect_factory.prototype.resizeHeight = sl.effect._resizeHeight;
	sl.effect_factory.prototype.addRoundCorners = sl.effect._addRoundCorners;
	sl.effect_factory.prototype.showProcessingInfo = sl.effect._showProcessingInfo;
	sl.effect_factory.prototype.hideProcessingInfo = sl.effect._hideProcessingInfo;
	sl.effect_factory.prototype.setOpacity = sl.effect._setOpacity;
	sl.effect_factory.prototype.followMouse = sl.effect._followMouse;
	sl.effect_factory.prototype.stopFollowingMouse = sl.effect._stopFollowingMouse;

	/// označíme knihovnu jako načtenou
	sl.loaded['sl.effect.js'] = true;
}
