/*
Brad's Super Fancy Slideshow


Usage:

    var slideshow = new bsfs(element, {
        // If the panels should automatically change at the switch delay interval.
        play: false,
        // Amount of time between panel changes.
        switchDelaySeconds: 5,
        // Area where the togglers are.
        togglersAreaClass: ".togglers",
        // Area where the panels are.
        panelsAreaClass: ".panels",
        // Area where the controller is.
        controllerAreaClass: ".controller",
        // Toggler element selector, if not immeadiat children of container.
        togglerSelector: "",
        // Panel element selector, if not immeadiat children of container.
        panelSelector: "",
        // Ctonrol element selector, if not immeadiat children of container.
        controllerSelector: "",
        // See FX types below.
        fxType: "scroll",
        // Specify in depth FX options for the FX type.
        fxOptions: {},
        // Disable changing of the panel height.
        disableHeight: false,
        // Use a predefined height to start when useing changing panel heights.
        startHeight: null
    });


fxTypes currently supported: "scroll", "fadeOut"
*/

var bsfs = new Class({

    Implements: [Events, Options],

    options: {
        togglersAreaClass: ".togglers",
        panelsAreaClass: ".panels",
        controllerAreaClass: ".controller",
        togglerSelector: "",
        panelSelector: "",
        controllerSelector: "",
        switchDelaySeconds: 5,
        play: false,
        fxOptions: {},
        fxType: "scroll",
        startHeight: null,
        disableHeight: false
    },
    
    initialize: function(element, options) {
        this.setOptions(options);
        
        //Set up element refrences
        this.container = $(element);
        
        this.configureSlideshowVariables();
        
		this.panelsContainer.store("currentPanel", this.panelElements[0]);
        
        if ($chk(this.controllerContainer)) {
            this.controllerElementsArray = ($chk(this.options.controllerSelector)) ? this.controllerContainer.getElements(this.options.controllerSelector) : this.controllerContainer.getChildren();

            //Set up controls
            this.controllerElements = new Hash();
            this.controllerElementsArray.each(function(item, index, array) {
                if (item.hasClass("play")) {
                    this.controllerElements.set("play", item);
                    item.addEvent("click", this.playClick.bind(this));
                    if (this.options.play) {
                        item.set("text", "Pause")
                        this.controllerContainer.addClass("playing");
                    } else {
                        item.set("text", "Play");
                    }
                } else if (item.hasClass("next")) {
                    this.controllerElements.set("next", item);
                    item.addEvent("click", this.nextClick.bind(this));
                } else if (item.hasClass("previous")) {
                    this.controllerElements.set("previous", item);
                    item.addEvent("click", this.previousClick.bind(this));
                }
                item.setStyle("cursor", "pointer");
            }, this);
        }
        
        //Set the switch event on the togglers
        if ($chk(this.togglersContainer)) {
			this.togglerElements.each(function(item, index) {
				item.store("corespondingPanel", this.panelElements[index]);
				this.panelElements[index].store("corespondingToggler", item);
				item.addEvent("click", this.togglerClick.bind(this));
				item.setStyle("cursor", "pointer");
			}, this);
		}
        
        this.container.addEvent("mouseenter", this.containerEnter.bind(this));
        this.container.addEvent("mouseleave", this.containerLeave.bind(this));
        
        switch (this.options.fxType) {
            case "scroll": default:
                //Set up scroll FX
                this.options.fxOptions.link = "cancel";
                this.scrollFx = new Fx.Scroll(this.panelsContainer, this.options.fxOptions);
                break;
            case "fadeOut":
                //Set up fadeOut FX
                this.options.fxOptions.link = "ignore";
                this.panelElements.each(function(item){
                    item.setStyles({ "z-index": 1, "position": "absolute", "top": 0, "left": 0});
                    item.fade("hide");
                });
                this.getCurrentPanel().setStyle("z-index", 2).fade("show");
                this.stopClicks = false;
                break;
        }
		
		if (!this.options.offload) { this.resetTimeout(); }
    },
    
    configureSlideshowVariables: function() {
        this.togglersContainer = this.container.getElement(this.options.togglersAreaClass);
        this.panelsContainer = this.container.getElement(this.options.panelsAreaClass);
        this.controllerContainer = this.container.getElement(this.options.controllerAreaClass);
        
        //If an selector is specifyed, use it to get the children, otherwise just get the first children
        this.togglerElements = ($chk(this.options.togglerSelector)) ? this.togglersContainer.getElements(this.options.togglerSelector) : this.togglersContainer.getChildren();
        this.panelElements = ($chk(this.options.panelSelector)) ? this.panelsContainer.getElements(this.options.panelSelector) : this.panelsContainer.getChildren();
        
        //Insert the container and styles to do the sliding
        this.panelWidth = this.panelsContainer.getSize().x;
        this.firstElementHeight = this.panelElements[0].getSize().y;
        this.panelsContainer.setStyles({
            "overflow": "hidden",
            "position": "relative",
            "width": this.panelWidth
        });
        if ($chk(this.options.startHeight) && (!this.options.disableHeight)) {
			this.panelsContainer.setStyle("height", this.options.startHeight);
		} else {
			this.panelsContainer.setStyle("height", this.firstElementHeight);
		}
		if (!$chk(this.wrapperDiv)) {
		    this.wrapperDiv = new Element("div", {
                styles: {
                    "display": "block",
                    "width": (this.panelWidth * this.panelElements.length),
                    "height": "100%",
                    "overflow": "hidden"
                }
            }).inject(this.panelsContainer, "top").adopt(this.panelElements);
        } else {
            this.wrapperDiv.setStyle("width", (this.panelWidth * this.panelElements.length));
        }
        this.panelElements.each(function(item){
            item.setStyles({
                "width": this.panelWidth,
                "float": "left"
            });
        }, this);
    },
    
    //Accepts an element or index
    changePanel: function(newPanel) {
        if ($type(newPanel) == "number") {
            newPanel = this.panelElements[newPanel];
        }
        if (!this.options.disableHeight) { this.panelsContainer.tween("height", newPanel.getSize().y); }
        this.resetTimeout();
        switch (this.options.fxType) {
            case "scroll": default:
                this.scrollFx.toElement(newPanel);
                break;
            case "fadeOut":
                var currentPanel = this.getCurrentPanel();
                if (currentPanel != newPanel) {
                    this.stopClicks = true;
                    currentPanel.setStyles({ "z-index": 3 });
                    var newPanelShown = function() {
                        var fadeComplete = function() {
                            currentPanel.setStyles({ "z-index": 1 });
                            this.stopClicks = false;
                        }
                        this.options.fxOptions.onComplete = fadeComplete.bind(this);
                        currentPanel.set('tween', this.options.fxOptions).fade("out");
                    }
                    newPanel.setStyles({ "z-index": 2 }).get("tween").set("onComplete", newPanelShown.bind(this));
                    newPanel.fade("show");
                }
                break;
        }
        
        this.panelsContainer.store("currentPanel", newPanel);
    },
    
    //Helpers
    getDelaySeconds: function() {
        return this.options.switchDelaySeconds * 1000;
    },
    
    getCurrentPanel: function() {
        return this.panelsContainer.retrieve("currentPanel");
    },
    
    getPanelIndex: function(panel) {
        return this.panelElements.indexOf(panel);
    },
    
    //Slide player functions
    resetTimeout: function() {
        clearTimeout(this.switchIteration);
        if (this.options.play) {
            this.switchIteration = setTimeout(this.switchTimeFunction.bind(this), this.getDelaySeconds());
        }
    },
    
    switchTimeFunction: function() {
        var newIndex = this.panelElements.indexOf(this.getCurrentPanel()) + 1;
        if (newIndex == this.panelElements.length) { newIndex = 0; }
        this.changePanel(newIndex);
        this.resetTimeout();
    },
    
    stopPlay: function() {
        if ($chk(this.controllerContainer)) { this.controllerContainer.removeClass("playing"); }
        clearTimeout(this.switchIteration);
    },
    
    startPlay: function() {
        if ($chk(this.controllerContainer)) { this.controllerContainer.addClass("playing"); }
        this.resetTimeout();
    },
    
    //Events
    togglerClick: function(event) {
        if (!this.stopClicks) {
            var element = $(event.target);
            var recursePanel = function(i, newPanel, element, context) {
                if (newPanel) {
                    context.changePanel(newPanel);
                } else if (i < 7) {
                    element = element.getParent();
                    newPanel = element.retrieve("corespondingPanel");
                    recursePanel(i, newPanel, element, context);
                }
            }
            var context = this;
            var newPanel = element.retrieve("corespondingPanel");
            recursePanel(0, newPanel, element, context);
        }
        event.stop();
    },
    
    containerEnter: function(event) {
        this.stopPlay();
    },
    
    containerLeave: function(event) {
        if (this.options.play) {
            this.startPlay();
        }
    },
    
    playClick: function(event) {
        if (!this.stopClicks) {
			var element = event.target;
			if (this.options.play) {
				this.stopPlay();
				this.options.play = false;
				element.set("text", "Play").removeClass("playing");
			} else {
				this.startPlay();
				this.options.play = true;
				element.set("text", "Pause").addClass("playing");
			}
		}
        event.stop();
    },
    
    nextClick: function(event) {
        if (!this.stopClicks) {
			var element = event.target;
			this.resetTimeout();
			var newIndex = this.panelElements.indexOf(this.getCurrentPanel()) + 1;
			if (newIndex == this.panelElements.length) { newIndex = 0; }
			this.changePanel(newIndex);
		}
        event.stop();
    },
    
    previousClick: function(event) {
        if (!this.stopClicks) {
			var element = event.target;
			this.resetTimeout();
			clearTimeout(this.switchIteration);
			var newIndex = this.panelElements.indexOf(this.getCurrentPanel()) - 1;
			if (newIndex == -1) { newIndex = (this.panelElements.length - 1); }
			this.changePanel(newIndex);
		}
        event.stop();
    }

});
