/**
 *
 *	Rotator								( 2010-10-01 ) 
 *
 *	Vstupni objekt:
 *
 *	config.cover						[HTMLElement] obalovy html element 
 *	config.tagName						[String] jmenu tagu pro vyber elementu 
 *	config.className                    [String] jmeno html tridy k aplikovani na objekty ( divy )
 *	config.simpleLogger					[SimpleLogger] SimpleLogger objekt 
 *	config.infinite						[bool] nekonecne smycka ( pro Prev & Next )
 *	config.fadeEffect					[bool] fade efekt
 *	config.fadeSpeed					[int] rychlost prechodu, 10 .. 10000
 *	config.random    					[bool] pouzivat random pri funkci pri prechodu mezi prvky 
 *	
 *  Metody:
 *	
 *	random								zobrazi random prvek
 *	my       							zobrazi prvek s indexem i
 *	    param i                         index do pole InDivs ( pole rotovanych elementu ) 
 *	next								zobrazi dalsi prvek
 *	prev								zobrazi predchzi prvek 
 *	startAuto							automaticka zmena v danem intervalu
 *		param delay						casova prodleva v milisec.
 *	stopAuto							zastaveni automaticke zmeny
 *	toggleAuto							prepinani mezi start a stop auto.
 *		param delay						casova prodleva v milisec.
 *	
 *  Settery / Gettery:
 *  
 *	isFadeFinished                      [bool] vraci, zda jiz byl fade efekt dokoncen.
 *  setFadeEffect                       nastavi fadeEffect
 *      param val                       [bool] nova hodnota
 *  setFadeSpeed                        nastavi rychlost fadeEffect
 *      param val                       [int] pocet milisekund
 *		
 *  Eventy:                             (pro prepsani, u instance nahradit vlastni funkci)
 *  
 *  onHideStart                         metoda volana pred schovanim elementu
 *      InDivs                          pole rotovanych elementu
 *      Index                           index do prechoziho pole, ukazuje na schovavany element   
 *  onShowStart                         metoda volana pred zobrazenim elementu
 *      InDivs                          pole rotovanych elementu
 *      Index                           index do prechoziho pole, ukazuje na zobrazovany element
 *  onHideFinished                      metoda volana po schovani elementu
 *      InDivs                          pole rotovanych elementu
 *      Index                           index do prechoziho pole, ukazuje na schovavany element   
 *  onShowFinished                      metoda volana po zobrazeni elementu
 *      InDivs                          pole rotovanych elementu
 *      Index                           index do prechoziho pole, ukazuje na zobrazovany element
 *
 */
 
function Rotator(config) {
	if(config == null) {
		throw new Error("Rotator: Neni zadan config objekt!");
		return;
	}
	if(config.cover == null) {
		throw new Error("Rotator: Neni zadan obalovy element!");
	}
	
	var This = this;
	var Config = config;
	var InDivs = new Array();
	var Index = 0;
	var Logger = (config.simpleLogger) ? config.simpleLogger : (window.console) ? console : null;
	var Cover = config.cover;
	var TagName = (config.tagName) ? config.tagName : "div";
	var ClassName = (config.className != null) ? config.className : "rotator-item";
	var Infinite = (config.infinite) ? config.infinite : false;
	var FadeEffect = (config.fadeEffect != null && config.fadeEffect == true) ? true : false;
	var FadeSpeed = (config.fadeSpeed != null && config.fadeSpeed >= 10 && config.fadeSpeed <= 10000) ? config.fadeSpeed : 500;
	var FadeFinished = true; 
	var Random = config.random;
	var Timer = null;
	var CallPrevAfterFade = false;
	var CallNextAfterFade = false;
	var CallMyAfterFade = -1;
	
	function init() {
		var inDivs = Cover.getElementsByTagName(TagName);
		for(var i = 0; i < inDivs.length; i ++) {
			if((ClassName != "") ? (inDivs[i].className.indexOf(ClassName) != -1) : true) {
				InDivs[InDivs.length] = inDivs[i];
				inDivs[i].style.display = "none";
			}
		}
		Logger.info("Length: " + InDivs.length, 2);
		if(Random == false) {
            FadeEffect = false;
            showEl(0);
            FadeEffect = Config.fadeEffect;
		} else {
            This.random();
        }
	};
	
	this.next = function() {
		Logger.log("FadeFinished: " + FadeFinished, 2);
		if(FadeFinished) {
    		if(CallPrevAfterFade) {
    		    Logger.log("Post PREV call", 2);
                CallPrevAfterFade = false;
                This.prev();
                return;
            } else if(CallNextAfterFade) {
    		    Logger.log("Post NEXT call", 2);
                CallNextAfterFade = false;
                This.next();
                return;
            } else if(CallMyAfterFade != -1) {
    		    Logger.log("Post MY call", 2);
                This.my(CallMyAfterFade);
                CallMyAfterFade = -1;
                return;
            } else if((Infinite && InDivs.length == (Index + 1)) || InDivs.length > (Index + 1)) {
				hideEl(Index);
				if(InDivs.length > (Index + 1)) {
					Index ++;
				} else {
					Index = 0;
				}
				showEl(Index);
			}
		} else {
            CallNextAfterFade = true;
		    Logger.log("CallNextAfterFade setuped up", 2);
        }	
	};
	 	 	 	
	this.prev = function() {
		if(FadeFinished) {
			if((Infinite && Index == 0) || Index > 0) {
				hideEl(Index);
				if(Index > 0) {
					Index --;
				} else {
					Index = InDivs.length - 1;
				}
				showEl(Index);
			}
		} else {
            CallPrevAfterFade = true;
        }
	};
	
	this.random = function() {
		Logger.log("FadeFinished: " + FadeFinished, 2);
		if(FadeFinished) {
			hideEl(Index);
			do {
				i = Math.round(Math.random() * (InDivs.length - 1));
			} while(i == Index);
			Index = i;
			showEl(Index);
		}
	};
	
	this.my = function(index) {
	    if(index > -1 && index < InDivs.length) {
    		Logger.log("FadeFinished: " + FadeFinished, 2);
	       	if(FadeFinished) {
		      	hideEl(Index);
			    Index = index;
		  	    showEl(Index);
		    } else {
                CallMyAfterFade = index;
            }
        }
	};
	
	this.toggleAuto = function(delay) {
		if(Timer == null) {
			This.startAuto(delay);
		} else {
			This.stopAuto();
		}
	};
	
	this.startAuto = function(delay) {
        if(Random == false) {
            Timer = window.setInterval(This.next, delay);
        } else {
            Timer = window.setInterval(This.random, delay);
        }
	};
	
	this.stopAuto = function() {
		window.clearInterval(Timer);
		Timer = null;
	};
	
	
	this.onHideFinished = function(InDivs, Index) {
	   
    };
	
	
	this.onHideStart = function(InDivs, Index) {
	   
    };
	
	
	this.onShowFinished = function(InDivs, Index) {
	   
    };
	
	
	this.onShowStart = function(InDivs, Index) {
	   
    };
		 	 	
	function hideEl(index) {
	    This.onHideStart(InDivs, Index);
		Logger.info("Hide Index: " + Index, 1);
		if(FadeEffect) {
			FadeFinished = false;
			jQuery(InDivs[index]).fadeOut(FadeSpeed, function() {
				FadeFinished = true;
				This.onHideFinished(InDivs, Index);
			});
		} else {	
			InDivs[index].style.display = 'none';
		}
	};
	
	function showEl(index) {
	    This.onShowStart(InDivs, Index);
		Logger.info("Show Index: " + Index, 1);
		if(FadeEffect) {
			FadeFinished = false;
			jQuery(InDivs[index]).fadeIn(FadeSpeed, function() {
				FadeFinished = true;
				This.onShowFinished(InDivs, Index);
			});
		} else {
			InDivs[index].style.display = '';
		}
	};
	
	this.isFadeFinished = function() {
        return FadeFinished;
    };
    
    this.setFadeEffect = function(val) {
        if(val != null) {
            if(val == true) {
                FadeEffect = true;
            } else if(val == false) {
                FadeEffect = false;
            } else {
                throw new Error("[ROTATOR]: Incorrect value passed to 'setFadeEffect'!");
            }
        } else {
            throw new Error("[ROTATOR]: Incorrect value passed to 'setFadeEffect'!");
        }
    };
    
    this.setFadeSpeed = function(val) {
        if(val != null) {
            if(val >= 10 && val <= 10000) {
                FadeSpeed = val;
            } else {
                throw new Error("[ROTATOR]: Incorrect value passed to 'setFadeSpeed'!");
            }
        } else {
            throw new Error("[ROTATOR]: Incorrect value passed to 'setFadeSpeed'!");
        }
    };
	
	this.addEvent = function(obj, ev, func, b) {
      	if(obj.addEventListener) {
      	    obj.addEventListener(ev, func, b);
    	} else {
        	obj.attachEvent("on" + ev, func);
      	}
	};
	
	this.removeEvent = function(obj, ev, func, b) {
      	if(obj.addEventListener) {
  	        obj.removeEventListener(ev, func, b);
	    } else {
        	obj.detachEvent("on" + ev, func);
      	}
	};
	
	this.stopEvent = function (event) {
        if(navigator.appName != "Microsoft Internet Explorer") {
            event.stopPropagation();
            event.preventDefault();
        } else {
            event.cancelBubble = true;
            event.returnValue = false;
        }
    };
	
	init();
};

