var PanelCarousel = new Class({
    Implements: [Options, Events],

    options: {
        // base options
        stylesheet: "/javascripts/libs/classes/PanelCarousel.css",
        panelClass: ".panel",
        showIndicators: true,
        showNextPreviousButtons: true,
        cancelLoopOnIndicatorClick: false,
        cancelLoopOnButtonClick: false,
        animationStyle: "slider", // slider, fader

        // Slider config options
        sliderId: "slider",
        sliderClass: "slider",
        sliderDirection: "top-down", // left-right, right-left, top-down, bottom-up
        sliderTransition: Fx.Transitions.Expo.easeOut,
        sliderDuration: 500,

        // Animation Stuff
        slideDuration: 5000,

        // Event Stuff
        animationComplete: function () { },
        indicatorClick: function (indicatorIndex, panelElementFrom, panelElementTo) { },
        buttonClick: function (button, panelElementFrom, panelElementTo) { }

    },

    initialize: function (element, options) {
        this.setOptions(options);

        if (!$(element)) return false;
        if ($$(this.options.panelClass).length < 2) return false;

        this.element = $(element);

        // Run It
        this._dom();
        this._create_methods();

        return this.element;

    },

    _dom: function () {

        var self = this;
        self.css = new Element("link", { rel: "stylesheet", href: self.options.stylesheet, type: "text/css" }).inject(document.getElement("head"));
        self.element.panels = self.element.getElements(self.options.panelClass);

        this.element.addClass(this.options.animationStyle);

        // slider or fader?
        if (this.options.animationStyle == "fader") {
            this._build_fader();
        } else if (this.options.animationStyle == "slider") {
            this._build_slider();
        }

        if (this.options.showIndicators == true) this._build_indicators();
        if (this.options.showNextPreviousButtons == true) this._build_buttons();
    },

    _build_fader: function () {

        var self = this;

        self.element.activePanelIndex = 0;
        self.element.panels.each(function (panel, index) {

            if (index == 0) {
                self.element.activePanel == panel;
            } else {
                panel.fade("hide");
            }

            panel.index = index;

        });

        self.element.animatePanel = function (passedpanel) {

            var currentpanel = self.element.activePanelIndex;
            var nextpanel = (passedpanel == null) ? currentpanel + 1 : passedpanel;

            if (nextpanel == self.element.panels.length) nextpanel = 0;
            if (self.element.indicators) self.element.indicators.setActiveItem(nextpanel);

            self.element.panels[currentpanel].fade("out");
            self.element.panels[nextpanel].fade("in");

            self.element.activePanelIndex = nextpanel;

            // Simulated onComplete event. 
            (function () { self.options.animationComplete(); }).delay(550);


        };

        self.timer = self.element.animatePanel.periodical(self.options.slideDuration);

    },

    _build_slider: function () {

        var self = this;

        // Build the Slider Element.
        self.element.activePanelIndex = 0;
        self.element.slider = new Element("div", {
            id: self.element.get("id") + "-" + self.options.sliderId,
            "class": self.options.sliderClass + " " + self.options.sliderDirection
        }).inject(self.element, "top");

        // Directionality
        var directions = {
            "left-right": "left",
            "right-left": "right",
            "top-down": "top",
            "bottom-up": "bottom"
        };

        var direction = directions[self.options.sliderDirection];
        var insertionPoint = "";

        // Get the Insertion Point.
        if (direction == "top") {
            insertionPoint = "top";
        } else if (direction == "bottom") {
            insertionPoint = "bottom";
        } else {
            insertionPoint = null;
        }

        var panelsWidth = 0;
        var panelsHeight = 0;
        self.element.panels.each(function (panel, index) {

            panel.inject(self.element.slider, insertionPoint);
            panelsWidth += panel.getSize().x;
            panelsHeight += panel.getSize().y;
            // panel.setStyles({
            // 	"width" : self.element.getStyle("width"),
            // 	"height" : self.element.getStyle("height"),
            // 	"overflow" : "hidden"
            // });

        });

        // Set the width
        var sliderdimensions = {
            width: ((direction == "left" || direction == "right") ? panelsWidth : null),
            height: ((direction == "top" || direction == "bottom") ? panelsHeight : null)
        };

        self.element.slider.setStyles(sliderdimensions);

        // Build the slider.
        self.element.slider.morph = new Fx.Morph(self.element.slider, {
            transition: self.options.sliderTransition,
            duration: self.options.sliderDuration,
            onComplete: function () {

                // Animation Event.
                self.options.animationComplete();

            }
        });

        // Starting Position
        if (self.options.sliderDirection == "left-right") {
            self.element.slider.morph.set({ "left": -(panelsWidth - self.element.panels[0].getSize().x) });
        } else if (self.options.sliderDirection == "right-left") {
            self.element.slider.morph.set({ "right": 0 });
        } else if (self.options.sliderDirection == "top-down") {
            self.element.slider.morph.set({ "top": -(panelsHeight - self.element.panels[0].getSize().y) });
        } else if (self.options.sliderDirection == "bottom-up") {
            self.element.slider.morph.set({ "bottom": 0 });
        }

        self.element.animatePanel = function (passedpanel) {

            var currentpanel = self.element.activePanelIndex;
            var nextpanel = (passedpanel == null) ? currentpanel + 1 : passedpanel;

            if (nextpanel == self.element.panels.length) nextpanel = 0;
            if (self.element.indicators) self.element.indicators.setActiveItem(nextpanel);

            // get the sliding offsef
            var offset = ((direction == "top" || direction == "bottom") ? self.element.getStyle("height").toInt() : self.element.getStyle("width").toInt()) * nextpanel;

            if (self.options.sliderDirection == "left-right") {
                self.element.slider.morph.cancel().start({ "left": -(panelsWidth - (offset + self.element.panels[currentpanel].getSize().x)) });
            } else if (self.options.sliderDirection == "right-left") {
                self.element.slider.morph.cancel().start({ "right": offset });
            } else if (self.options.sliderDirection == "top-down") {
                self.element.slider.morph.cancel().start({ "top": -(panelsHeight - (offset + self.element.panels[currentpanel].getSize().y)) });
            } else if (self.options.sliderDirection == "bottom-up") {
                self.element.slider.morph.cancel().start({ "bottom": offset });
            }

            self.element.activePanelIndex = nextpanel;
        };

        self.timer = self.element.animatePanel.periodical(self.options.slideDuration);

    },

    _build_buttons: function () {

        var self = this;
        var paused = false;

        self.element.buttons = {};
        self.element.buttons.previousButton = new Element("a", {
            id: self.element.get("id") + "-previous-button",
            text: "Previous Panel",
            title: "Previous Panel",
            events: {
                click: function (evt) {

                    var currentpanel = self.element.activePanelIndex;
                    var previouspanel = currentpanel - 1;
                    if (previouspanel < 0) previouspanel = self.element.panels.length - 1;

                    evt.stop();
                    if (self.timer) clearInterval(self.timer);

                    self.element.animatePanel(previouspanel);

                    // RYAN: line 234 has the resume call.

                    if (!self.options.cancelLoopOnButtonClick) self.timer = self.element.animatePanel.periodical(self.options.slideDuration);

                }
            }
        }).inject(self.element.indicators, "top");


        self.element.buttons.pause = new Element('a', {
            id: self.element.get('id') + '-pause-button',
            html: '&nbsp;',
            events: {
                click: function (evt) {
                    if (!paused) {
                        paused = true;
                        evt.stop();
                        if (self.timer) clearInterval(self.timer);
                        self.element.buttons.pause.set('styles', { 'background-position': '-9px 0' });
                        self.element.buttons.pause.getParent().set('styles', { 'background-position': '-9px 0' });
                    } else {
                        paused = false;
                        self.element.buttons.pause.set('styles', { 'background-position': '-17px 0' });
                        self.element.buttons.pause.getParent().set('styles', { 'background-position': '-17px 0' });
                        self.timer = self.element.animatePanel.periodical(self.options.slideDuration);
                    }
                }
            }
        }).inject(self.element.indicators, 'bottom');


        self.element.buttons.nextButton = new Element("a", {
            id: self.element.get("id") + "-next-button",
            text: "Next Panel",
            title: "Next Panel",
            events: {
                click: function (evt) {

                    var currentpanel = self.element.activePanelIndex;
                    var nextpanel = currentpanel + 1;
                    if (nextpanel == self.element.panels.length) nextpanel = 0;

                    evt.stop();
                    if (self.timer) clearInterval(self.timer);

                    self.element.animatePanel();

                    if (!self.options.cancelLoopOnButtonClick) self.timer = self.element.animatePanel.periodical(self.options.slideDuration);

                    self.options.buttonClick(evt.target, self.element.panels[currentpanel], self.element.panels[nextpanel]);

                }
            }
        }).inject(self.element.indicators, "bottom");


        // new Element('span', {
        // 	id: self.element.get('id') + '-pause-button',
        // 	class: 'button',
        // 	html: '<a href="#"> || </a>',
        // 	styles: { position: 'relative', 'z-index': 9000},
        // 	events: {
        // 		click: function(evt) {
        // 			evt.stop();
        // 			if (self.timer) clearInterval(self.timer);
        // 			this.set('html', '<a href="#"> &gt; </a>')
        // 		}
        // 	}
        // }).inject('all-slides', 'top');


        new Element('li', { id: self.element.get('id') + '-previous-button-wrap' }).wraps(self.element.buttons.previousButton);
        new Element('li', { id: self.element.get('id') + '-pause-button-wrap' }).wraps(self.element.buttons.pause);
        new Element('li', { id: self.element.get('id') + '-next-button-wrap' }).wraps(self.element.buttons.nextButton);

    },

    _build_indicators: function () {

        var self = this;

        self.element.indicators = new Element("ul", {
            id: self.element.get("id") + "-indicators"
        }).inject(self.element, "bottom");

        self.element.indicators.pages = [];
        self.element.indicators.activeItemIndex = 0;

        self.element.panels.each(function (panel, index) {

            var li = new Element("li", {
                html: "<a href=\"#panel-" + index + "\" title=\"Panel " + (index + 1) + "\">" + (index + 1) + "</a>"
            }).inject(self.element.indicators);

            if (index == 0) li.addClass("active");

            var a = li.getElement("a");
            a.index = index;
            a.addEvent("click", function (evt) {

                evt.stop();

                // reset the periodical
                if (self.timer) clearInterval(self.timer);

                self.element.animatePanel(index);

                if (!self.options.cancelLoopOnIndicatorClick) self.timer = self.element.animatePanel.periodical(self.options.slideDuration);

                self.element.indicators.setActiveItem(index);

                self.options.indicatorClick(index, self.element.panels[self.element.activePanelIndex], self.element.panels[index]);

            });


            self.element.indicators.pages.push(li);

        });

        self.element.indicators.setActiveItem = function (index) {

            if (self.element.indicators.pages[self.element.indicators.activeItemIndex].hasClass("active")) {
                self.element.indicators.pages[self.element.indicators.activeItemIndex].removeClass("active");
            }

            self.element.indicators.pages[index].addClass("active");
            self.element.indicators.activeItemIndex = index;

        };

    },

    _create_methods: function () {

        var self = this;

        // Cancel the Inverval
        self.element.cancelLoop = function () {

            if (self.timer) {

                clearInterval(self.timer);
                return true;

            }

            return false;

        };

        // Animate to Index
        self.element.animateTo = self.element.animatePanel;
        self.element.animateToIndex = self.element.animatePanel;
    }

});
