var PanelCarousel = new Class ({
	Implements: [Options, Events],
	
	options: {
		// base options
		stylesheet: "/_classes/PanelCarousel/PanelCarousel.css",
		panelClass: ".slide",
		showIndicators: true,
		showNextPreviousButtons: true,
		cancelLoopOnIndicatorClick: true,
		cancelLoopOnButtonClick: false,
		animationStyle: "slider", // slider, fader
		
		// Slider config options
		sliderId: "panelcarousel-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 == 0) 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);
		self.controlContainer = $('controls-container');

		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.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;
		
		self.element.buttons = {};
		self.element.buttons.previousButton = new Element("li", {
			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);
					
					if (!self.options.cancelLoopOnArrowClick) self.timer = self.element.animatePanel.periodical(self.options.slideDuration);
					
					self.options.buttonClick(evt.target, self.element.panels[currentpanel], self.element.panels[previouspanel]);
								
				}
			}
		}).inject(self.element.indicators, "top");
		
		self.element.buttons.nextButton = new Element("li", {
			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.cancelLoopOnArrowClick) 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");
		
	},
	
	_build_indicators: function() {
		
		var self = this;

		self.element.indicators = new Element("ul", {
			id: self.element.get("id") + "-indicators"
		}).inject(self.controlContainer, "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;
	}

});
