/**
 * @author Iris Associates Ltd.
 * @version 2.2
 */

var Carousel = Class.create({
    elem: null,
    items: 0,
    currentItem: 0,
    running: false,
    options: {
        buildQuickJump: false,
        leftControl: null,
        rightControl: null,
        quickJumpImageOn: "bullet-carousel-on.png",
        quickJumpImageOff: "bullet-carousel-off.png"
    },

    initialize: function(elem, options)
    {
        this.elem = $(elem);
        if(!this.elem)
        {
            throw "Unable to bind to element";
        }

        // ensure the container is properly notified
        this.elem.up().addClassName("scripted");

        this.items = this.elem.childElements().size();
        this.options = Object.extend(this.options, options);

        if(this.options.buildQuickJump)
        {
            this.build();
        }

        if(this.options.leftControl)
        {
            this.options.leftControl.observe("click", this.moveLeft.bindAsEventListener(this, 1));
        }

        if(this.options.rightControl)
        {
            this.options.rightControl.observe("click", this.moveRight.bindAsEventListener(this, 1));
        }
    },

    build: function()
    {
        var ulElem = document.createElement("ul");
        Element.extend(ulElem);
        ulElem.writeAttribute({"id": "carouselNavigation"});

        var liElem, imgElem;
        for(i = 1; i <= this.items; i++)
        {
            liElem = document.createElement("li");
            Element.extend(liElem);
            liElem.observe("click", this.navigate.bindAsEventListener(this));

            imgElem = document.createElement("img");
            Element.extend(imgElem);
            imgElem.writeAttribute({
                src: ((i == 1) ? this.options.quickJumpImageOn : this.options.quickJumpImageOff ),
                width: 6, height: 6, alt: i
            }).addClassName("dot");

            ulElem.insert(liElem.insert(imgElem));
        }

        this.elem.insert({after: ulElem});
    },

    navigate: function(evt)
    {
        evt.stop();
        var targetItem = evt.findElement("li").previousSiblings().size();

        if(targetItem != this.currentItem)
        {
            var diff = (targetItem - this.currentItem);
            var normalisedDiff = (diff < 0) ? (diff * -1) : diff;
            var newDiff = diff;

            // if we're moving GREATER than HALF the items, doing it wrong and need to go the other way
            if(normalisedDiff > Math.round(this.items / 2))
            {
                newDiff = normalisedDiff - this.items;
                newDiff *= (diff < 0) ? -1 : 1;
            }

            if(newDiff > 0)
            {
                this.moveRight(null, newDiff);
            }
            else
            {
                this.moveLeft(null, (newDiff * -1));
            }
        }
    },

    /**
     * Move left works like this:
     * 1. takes the last group from the end
     * 2. sets the first element of that group to have a negative margin
     * 3. appends that group to the beginning of the container element
     * 4. tweens the first group element from negative margin to 0, essentially "pushing" the strip along
     */
    moveLeft: function(evt, count)
    {
        count = (typeof count == "undefined") ? 1 : count;
        if(evt)
        {
            evt.stop();
        }

        if(!this.running)
        {
            this.running = true;
            var e = this.elem.childElements().last();

            e.setStyle({ "marginLeft": (-1 * e.getWidth())+"px" });

            this.elem.insert({
                top: e.remove()
            });

            new Effect.Tween(e, (-1 * e.getWidth()), 0, {
                duration: 0.6,
                transition: Effect.Transitions.EaseFromTo,
                afterFinish: function(count, effect)
                {
                    this.running = false;
                    if(count > 1)
                    {
                        this.moveLeft(null, --count);
                    }
                }.bind(this, count)
            }, function(p) {
                this.setStyle({"marginLeft": p+"px"});
            });

            this.currentItem--;
            this.currentItem = (this.currentItem < 0) ? (this.items - 1) : this.currentItem;

            if(this.options.buildQuickJump)
            {
                var cn = $("carouselNavigation");
                cn.select("img").invoke("writeAttribute", {src: this.options.quickJumpImageOff}).
                    toArray()[this.currentItem].writeAttribute({src: this.options.quickJumpImageOn});
            }
        }
    },

    /**
     * Move right works as such:
     * 1. gets the very first element of the container
     * 2. tweens that element from 0 to negative margin, essentially "pulling" the strip along
     * 3. once that has been done, takes the first group (now hidden) and appends it to the container
     * 4. resets the margin on the first element
     */
    moveRight: function(evt, count)
    {
        count = (typeof count == "undefined") ? 1 : count;
        if(evt)
        {
            evt.stop();
        }

        if(!this.running)
        {
            this.running = true;
            var e = this.elem.childElements().first();

            new Effect.Tween(e, 0, (-1 * e.getWidth()), {
                duration: 0.6,
                transition: Effect.Transitions.EaseFromTo,
                afterFinish: function(count, effect)
                {
                    this.elem.insert(this.elem.childElements().first().remove().setStyle({"marginLeft": 0}));
                    this.running = false;

                    if(count > 1)
                    {
                        this.moveRight(null, --count);
                    }
                }.bind(this, count)
            }, function(p) {
                this.setStyle({"marginLeft": p+"px"});
            });

            this.currentItem++;
            this.currentItem = (this.currentItem > (this.items - 1)) ? 0 : this.currentItem;

            if(this.options.buildQuickJump)
            {
                var cn = $("carouselNavigation");
                cn.select("img").invoke("writeAttribute", {src: this.options.quickJumpImageOff}).
                    toArray()[this.currentItem].writeAttribute({src: this.options.quickJumpImageOn});
            }
        }
    }
});

/*
Based on Easing Equations v2.0
(c) 2003 Robert Penner, all rights reserved.
This work is subject to the terms in http://www.robertpenner.com/easing_terms_of_use.html

Adapted for Scriptaculous by Ken Snyder (kendsnyder ~at~ gmail ~dot~ com) June 2006
*/
//EaseFromTo (adapted from "Quart.EaseInOut")
Effect.Transitions.EaseFromTo = function(pos) {
    if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,4);
    return -0.5 * ((pos-=2)*Math.pow(pos,3) - 2);
}; 

