/*
---

script: slideGallery.js

description: Multifunctional gallery for MooTools

license: MIT-style license

authors:
- Sergii Kashcheiev

requires:
- core/1.2.4: Events
- core/1.2.4: Fx.Tween
- core/1.2.4: Fx.Transitions

provides: [slideGallery, fadeGallery]

...
*/
var slideGallery = new Class({
        Version: "1.3",
        Implements: [Options, Events],
        options: {
                holder: ".holder",
                elementsParent: "ul",
                elements: "li",
                nextItem: ".next",
                prevItem: ".prev",
                stop: ".stop",
                start: ".start",
                speed: 600,
                duration: 4000,
                steps: 1,
                current: 0,
                transition: "sine:in:out",
                direction: "horizontal",
                mode: "callback",
                currentClass: "current",
                nextDisableClass: "next-disable",
                prevDisableClass: "prev-disable",
                paging: false,
                pagingEvent: "click",
                pagingHolder: ".paging",
                random: false,
                autoplay: false,
                autoplayOpposite: false,
                stopOnHover: true
                /*
                onStart: $empty,
                onPlay: $empty,
                */
        },
        initialize: function(gallery, options) {
                if(gallery.length == null) this.gallery = gallery;
                else this.gallery = gallery[0];
                if(!this.gallery) return false;
                this.setOptions(options);
                this.holder = this.gallery.getElement(this.options.holder);
                this.itemsParent = this.holder.getElement(this.options.elementsParent);
                this.items = this.itemsParent.getElements(this.options.elements);
                this.next = this.gallery.getElement(this.options.nextItem);
                this.prev = this.gallery.getElement(this.options.prevItem);
                this.stop = this.gallery.getElement(this.options.stop);
                this.start = this.gallery.getElement(this.options.start);
                this.current = this.options.current;
                this.bound = {rotate: this.rotate.bind(this) }

                Fx.implement({
                        cancel: function() {
                                if(!this.callChain()) this.fireEvent('chainComplete', this.subject);
                                if(this.stopTimer()) this.onCancel();
                                return this;
                        }
                });

                if(this.options.direction == "horizontal") {
                        this.direction = "margin-left";
                        this.size = this.items[0].getWidth();
                        this.visible = Math.round(this.holder.getWidth()/this.size);
                }
                else {
                        this.direction = "margin-top";
                        this.size = this.items[0].getHeight();
                        this.visible = Math.round(this.holder.getHeight()/this.size);
                }

                if(this.items.length <= this.visible) {
                        if(this.next) this.next.addClass(this.options.nextDisableClass).addEvent("click", function() {return false;});
                        if(this.prev) this.prev.addClass(this.options.prevDisableClass).addEvent("click", function() {return false;});
                        if(this.stop) this.stop.addEvent("click", function() {return false;});
                        if(this.start) this.start.addEvent("click", function() {return false;});
                        this.gallery.addClass("stopped no-active");
                        this.fireEvent("start", this.current, this.visible, this.items.length, this.items[this.current]);
                        return false;
                }

                this.options.steps = this.options.steps > this.visible ? this.visible : this.options.steps;
                this.options.duration = this.options.duration < 1000 ? 1000 : this.options.duration;
                this.options.speed = this.options.speed > 6000 ? 6000 : this.options.speed;
                if(this.options.speed > this.options.duration) this.options.speed = this.options.duration;

                this.fx = new Fx.Tween(this.itemsParent, {
                        property: this.direction,
                        duration: this.options.speed,
                        transition: this.options.transition,
                        link: "cancel",
                        fps: 100
                });

                if(this.options.random) this.shuffle();
                this.getInitialCurrent();

                if(this.options.mode == "circle") {
                        while(this.items.length < this.options.steps+this.visible) {
                                this.itemsParent.innerHTML += this.itemsParent.innerHTML;
                                this.items = this.itemsParent.getElements(this.options.elements);
                        }
                        for(var i=0; i<this.current; i++) {
                                this.items[i].inject(this.itemsParent, "bottom");
                        }
                        this.options.paging = false;
                }
                else {
                        if(this.options.paging) this.createPaging();
                        this.play(false);
                }

                if(this.next) {
                        this.next.addEvent("click", function() {
                                this.nextSlide();
                                return false;
                        }.bind(this));
                }

                if(this.prev) {
                        this.prev.addEvent("click", function() {
                                this.prevSlide();
                                return false;
                        }.bind(this));
                }

                if(this.options.autoplay || this.options.autoplayOpposite) this.timer = this.bound.rotate.delay(this.options.duration);
                else this.gallery.addClass("stopped");

                if(this.start) {
                        this.start.addEvent("click", function() {
                                clearTimeout(this.timer);
                                this.gallery.removeClass("stopped");
                                this.timer = this.bound.rotate.delay(this.options.duration);
                                return false;
                        }.bind(this));
                }

                if(this.stop) {
                        this.stop.addEvent("click", function() {
                                this.gallery.addClass("stopped");
                                clearTimeout(this.timer);
                                return false;
                        }.bind(this));
                }

                if(this.options.stopOnHover) {
                        this.gallery.addEvent("mouseenter", function() {
                                clearTimeout(this.timer);
                        }.bind(this));
                        this.gallery.addEvent("mouseleave", function() {
                                if(!this.gallery.hasClass("stopped")) {
                                        clearTimeout(this.timer);
                                        this.timer = this.bound.rotate.delay(this.options.duration);
                                }
                        }.bind(this));
                }

                this.fireEvent("start", this.current, this.visible, this.items.length, this.items[this.current]);
        },
        getInitialCurrent: function() {
                var tempCurrent = this.items.get("class").indexOf(this.options.currentClass);
                if(tempCurrent != -1) this.current = tempCurrent;
                else {
                        if(this.current > this.items.length-1) this.current = this.items.length-1;
                        else        if(this.current < 0) this.current = 0;
                }
                if(this.options.mode != "circle" && this.visible+this.current >= this.items.length) this.current = this.items.length-this.visible;
                return this;
        },
        rotate: function() {
                if(!this.options.autoplayOpposite) this.nextSlide();
                else this.prevSlide();
                this.timer = this.bound.rotate.delay(this.options.duration);
                return this;
        },
        play: function(animate) {
                if(this.options.mode == "line") this.sidesChecking();
                if(animate) this.fx.start(-this.current*this.size);
                else this.fx.set(-this.current*this.size);
                if(this.options.paging) this.setActivePage();
                this.fireEvent("play", this.current, this.visible, this.items.length, this.items[this.current]);
                return this;
        },
        nextSlide: function() {
                if(this.options.mode != "circle") {
                        if(this.visible+this.current >= this.items.length) {
                                if(this.options.mode == "callback") this.current = 0;
                        }
                        else if(this.visible+this.current+this.options.steps >= this.items.length) {
                                this.current = this.items.length-this.visible;
                        }
                        else this.current += this.options.steps;
                        this.play(true);
                }
                else {
                        var temp = this.current;
                        if((this.current += this.options.steps) >= this.items.length) this.current -= this.items.length;
                        this.fx.start(-this.size*this.options.steps).chain(function() {
                                for(var i=0; i<this.options.steps; i++) {
                                        if(temp >= this.items.length) temp = 0;
                                        this.items[temp++].inject(this.itemsParent, "bottom");
                                }
                                this.fx.set(0);
                        }.bind(this));
                        this.fireEvent("play", this.current, this.visible, this.items.length, this.items[this.current]);
                }
                return this;
        },
        prevSlide: function() {
                if(this.options.mode != "circle") {
                        if(this.current <= 0) {
                                if(this.options.mode == "callback") this.current = this.items.length-this.visible;
                        }
                        else if(this.current-this.options.steps <= 0) {
                                this.current = 0;
                        }
                        else        this.current -= this.options.steps;
                        this.play(true);
                }
                else {
                        for(var i=0; i<this.options.steps; i++) {
                                if(this.current-1 < 0) this.current = this.items.length;
                                this.items[--this.current].inject(this.itemsParent, "top");
                        }
                        this.fx.set(-this.size*this.options.steps).start(0);
                        this.fireEvent("play", this.current, this.visible, this.items.length, this.items[this.current]);
                }
                return this;
        },
        sidesChecking: function() {
                this.next.removeClass(this.options.nextDisableClass);
                this.prev.removeClass(this.options.prevDisableClass);
                if(this.visible+this.current >= this.items.length) this.next.addClass(this.options.nextDisableClass)
                else if(this.current==0) this.prev.addClass(this.options.prevDisableClass);
                return this;
        },
        createPaging: function() {
                this.paging = new Element("ul");
                var pagingHold = this.gallery.getElement(this.options.pagingHolder);
                if(pagingHold != null) this.paging.injectInside(pagingHold);
                else this.paging.injectInside(this.gallery).addClass("paging");

                var length = Math.ceil((this.items.length-this.visible)/this.options.steps)+1;
                var str = "";
                for(var i=0; i<length; i++) {
                        str += '<li><a href="#" onclick="return(false)" >' + '&nbsp;</a></li>';
                }
                this.paging = this.paging.set("html", str).getElements("a");
                this.paging.each(function(el, i) {
                        el.addEvent(this.options.pagingEvent, function() {
                                if(i < length-1) this.current = i*this.options.steps;
                                else this.current = this.items.length-this.visible;
                                this.play(true);
                                return false;
                        }.bind(this));
                }.bind(this));
                return this;
        },
        setActivePage: function() {
                this.paging.removeClass("active")[Math.ceil(this.current/this.options.steps)].addClass("active");
                return this;
        },
        shuffle: function() {
                var str = "";
                this.items.sort(function(){return 0.5 - Math.random()}).each(function(el) {
                        str += new Element("div").adopt(el).get("html");
                });
                this.items = this.itemsParent.set("html", str).getElements(this.options.elements);
                return this;
        }
});
var fadeGallery = new Class({
        Extends: slideGallery,
        initialize: function(gallery, options) {
                if(options.mode == "circle") options.mode = "callback";
                this.parent(gallery, options);
                this.fxFade = [];
                this.items.each(function(el, i) {
                        this.fxFade[i] = new Fx.Tween(el, {
                                property: "opacity",
                                duration: this.options.speed,
                                transition: this.options.transition,
                                link: "cancel"
                        });
                        this.fxFade[i].set(0);
                }.bind(this));
                this.play(false);
        },
        play: function(animate) {
                if(this.previous == null) {
                        this.previous = 0;
                        return false;
                }
                if(this.options.mode == "line") this.sidesChecking();
                if(animate) {
                        this.fxFade[this.previous].start(0);
                        this.fxFade[this.current].start(1);
                }
                else {
                        this.fxFade[this.previous].set(0);
                        this.fxFade[this.current].set(1);
                }
                this.previous = this.current;
                if(this.options.paging) this.setActivePage();
                this.fireEvent("play", this.current, this.visible, this.items.length, this.items[this.current]);
        }
});
