/*
Brad's Super Fancy Slideshow

fxTypes currently supported: "scroll", "fadeOut".
Offload types:
    [null = Won't offload],
    ["maskTogglers" = Mask togglers until main image loaded], 
    ["hideTogglers" = Hide togglers until main image loaded],
    ["maskAll" = Mask panels and togglers until loaded]
*/

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,
        loadImage: null,
        offload: null,
        disableHeight: false
    },
    
    initialize: function(element, options) {
        this.setOptions(options);
        
        //Set up element refrences
        this.container = $(element);
        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
        if ($chk(this.togglersContainer)) { 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();

		this.panelsContainer.store("currentPanel", this.panelElements[0]);
        
        //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);
		}
        new Element("div", {
            styles: {
                "display": "block",
                "width": (this.panelWidth * this.panelElements.length),
                "height": "100%",
                "overflow": "hidden"
            }
        }).inject(this.panelsContainer, "top").adopt(this.panelElements);
        this.panelElements.each(function(item){
            item.setStyles({
                "width": this.panelWidth,
                "float": "left"
            });
        }, this);
        
        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").addClass("playing");
                        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));
		
		this.panelsLoaded = 0;
		
		var imageLoad = function(item, index, type){
			if ($type(item) == "array") {
				index = item[1];
				item = item[0];
			}
			var totalImagesLoaded = item.retrieve("totalImagesLoaded") + 1;
			item.store("totalImagesLoaded", (totalImagesLoaded));
			if (totalImagesLoaded == item.retrieve("totalImages")) {
				if (type == "panel") {
					if (this.options.offload == "maskTogglers") {
						this.togglerElements[index].retrieve("mask").hide();
					} else if (this.options.offload == "hideTogglers") {
						this.togglerElements[index].fade("in");
					} else if (this.options.offload == "maskAll") {
						this.panelElements[index].retrieve("mask").hide();
					}
					this.panelsLoaded++;
					if (this.panelsLoaded == this.panelElements.length-1) {
						if (!this.options.disableHeight) { this.panelsContainer.tween("height", this.getCurrentPanel().getSize().y); }
						this.resetTimeout();
					}
				} else if (type == "toggler") {
					if (this.options.offload == "maskAll") {
						this.togglerElements[index].retrieve("mask").hide();
					}
				}
			}
		}
        
        var checkPreload = function(image) {
            var isPreloaded = false;
            image = $(image);
            var computedSize = image.getComputedSize();
            var originalSize = {x: computedSize.width, y: computedSize.height};
            if (originalSize.x != 0 && originalSize.y != 0) {
                image.setStyles({
                    'width': 'auto',
                    'height': 'auto'
                });
                var currentSize = image.getComputedSize();
                if (currentSize.x > 1 || currentSize.y > 1) {
                    isPreloaded = true;
                }
                image.setStyles({
                    'width': originalSize.x,
                    'height': originalSize.y
                });
            }
            return isPreloaded;
        }
        
        var offloadedImages = [];
        
        this.panelElements.each(function(item, index){
            if ((index == 0 && this.options.offload == "maskAll") || index != 0) {
                var panelImages = item.getElements("img");
                item.store("totalImagesLoaded", 0);
                item.store("totalImages", panelImages.length);
                if (this.options.offload == "maskTogglers" || this.options.offload == "maskAll") {
                    var loadImage = new Image();
                    loadImage.src = this.options.loadImage;
                }
                if (this.options.offload) {
                    panelImages.each(function(image){
                        if (!checkPreload(image)) {
                            if ((index == 0 && this.options.offload == "maskAll") || index != 0) { image.set("source", image.get("src")).erase("src"); }
                            image.addEvent("load", imageLoad.bind(this, [item, index, "panel"]));
                            offloadedImages.push(image);
                        } else {
                            item.store("totalImagesLoaded", (item.retrieve("totalImagesLoaded") + 1));
                        }
                    }, this);
                }
            }
            if (item.retrieve("totalImagesLoaded") != item.retrieve("totalImages")) {
                if (this.options.offload == "maskTogglers" && index != 0) {
                    var mask = new Mask(this.togglerElements[index], { destroyOnHide: true }).show();
                    this.togglerElements[index].store("mask", mask);
                } else if (this.options.offload == "hideTogglers" && index != 0)  {
                    this.togglerElements[index].fade("hide");
                } else if (this.options.offload == "maskAll") {
                    var panelMask = new Mask(this.panelElements[index], { destroyOnHide: true }).show();
                    this.panelElements[index].store("mask", panelMask);
                }
            }
        }, this);
        if (this.options.offload == "maskAll") {
            this.togglerElements.each(function(item, index){
                var togglerImages = item.getElements("img");
                item.store("totalImagesLoaded", 0);
                item.store("totalImages", togglerImages.length);
                togglerImages.each(function(image){
                    if (!checkPreload(image)) {
                        if ((index == 0 && this.options.offload == "maskAll") || index != 0) { image.set("source", image.get("src")).erase("src"); }
                        image.addEvent("load", imageLoad.bind(this, [item, index, "toggler"]));
                        offloadedImages.push(image);
                    } else {
                        item.store("totalImagesLoaded", (item.retrieve("totalImagesLoaded") + 1));
                    }
                }, this);
                if (item.retrieve("totalImagesLoaded") != item.retrieve("totalImages")) {
                    var togglerMask = new Mask(this.togglerElements[index], { destroyOnHide: true }).show();
                    this.togglerElements[index].store("mask", togglerMask);
                }
            }, 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;
        }
        
        offloadedImages.each(function(image) {
            image.set("src", image.get("source")).erase("source");
        });
		
		if (!this.options.offload) { this.resetTimeout(); }
    },
    
    //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); }
        
        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();
    }

});
