/*
 ---
 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: 2000,
        duration: 10000,
        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: true,
        autoplay: true,
        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="#">' + parseInt(i + 1) + '</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]);
    }
});

