argos.require("utils");
argos.require("classes");
argos.check("widgets");


argos.widgets.TabbedArea = function(items, options) {

	// Private variables
	var _tabbedArea = this;
	var _controller = null;
	var _hasSorting = false;
	var _automateId = null;
	var _updating = false;

	// Helpers
	var _helpers = {
		getMaxHeight : argos.utils.getMaxHeight,
		width : argos.utils.width,
		arrayToCollection : argos.utils.arrayToCollection,
		getType : argos.utils.getType
	}

	// Classes
	var _classes = {
		Element : argos.classes.Element
	}


	// Externally configurable options.
	var _options = _updateOptions.call(new Object({
		"afterSwitch" : function() {}, // Function that activates after switch to new tab.
		"automate" : false,
		"beforeSwitch" : function() {}, // Function that activates before switch to new tab.
		"cssClass" : "tabbedArea",
		"cssSelected" : "selected",
		"delay" : 4000, // if automated, time before resume after user clicks a tab.
		"duration" : 250,
		"interval" : 2000, // if automated, time between movements.
		"labels" : "h3", // selector that extracts label information.
		"reverse" : false,
		"start" : 0, // initial tab.
		"supportIE6HoverOnButtons" : true,
		"wrapper" : "<div />",
		"zIndexMax" : 50 // Arbitrary default number assuming you won't have more than this number of tabs (required for visual show/hide).
	}), options);


	// PRIVATE:
	(function _init(items) {
		var start = _options.start;

		// Check that passed items are actually a jQuery collection.
		items = items.pop && !items.wrapAll ? _helpers.arrayToCollection(items) : items;
		
		// Only create tabbedArea if we have at least one item.
		if(items.length > 0) {
			_controller = _createController(items);

			// Initial set item.
			_controller.property("selected", start);
			_controller.property("buttons")[start].addClass(_options.cssSelected);
			_controller.property("tabs")[start].show().addClass(_options.cssSelected);
		}
	}).call(this, items);

	function _updateOptions(customisations) {
		// Update options with new values.
		for(var c in customisations) {
			this[c] = customisations[c];
		}
		return this;
	}

	function _createController(items) {
		// Create the tabbedArea controller and initialise states/values.
		var controller = new _classes.Element("<div class=\"controller\"></div>");
		var itemsLength = items.length;		
		controller.property("buttons", new Array());

		// Create buttons.
		items.each(function(i) {
			var item = $(this);
			var button = _createButton(item, i);
			if(i == 0) button.addClass("buttonFirst");
			if(itemsLength == i + 1) button.addClass("buttonLast");
			controller.$node.append(button);
			controller.property("buttons").push(button);
		});

		controller.property("tabs", _setUpTabs(items));
		items.parent().prepend(controller.node);

		return controller;
	}

	function _createButton(item, num) {
		// Create buttons from passed items and append to controller.
		var button = $("<a class=\"button\" href=\"#" + item.attr("id") + "\"><span>" + item.find(_options.labels).text() + "</span></a>");
		button.data("tabNumber", num);
		button.click(function() {
			var button = $(this);
			if(_options["automate"]) {
				// Stop animation. Restart after delay.
				_disableAutomation();
				_automateId = window.setTimeout(_tabbedArea.automate, _options.delay);

			}
			_update(button.data("tabNumber"));
			return false;
		});

		// compensation for lack of :hover support in IE6
		if(_options.supportIE6HoverOnButtons && jQuery.browser.msie && Math.floor(jQuery.browser.version) <= 6) {
			button.bind("mouseover mouseout", function() { $(this).toggleClass("button_hover")});
			button.bind("mouseover mouseout", function() { $(this).toggleClass("button_hover")});
		}

		return button;
	}

	function _setUpTabs(items) {
		var tabs = new Array();
		var max, vPadding, vMargin;

		// Add tabbedArea wrapper if requested.
		if(_options.wrapper != "") {
			items.wrapAll(_options.wrapper);
			items.parent().addClass(_options.cssClass);
		}

		// Doing this after tabbedArea wrap to make sure we have all styles.
		max = _helpers.getMaxHeight(items);
		vPadding = Number($(items[0]).css("padding-top").replace("px","")) + Number($(items[0]).css("padding-bottom").replace("px",""));
		vMargin = Number($(items[0]).css("margin-top").replace("px","")) + Number($(items[0]).css("margin-bottom").replace("px",""));

		// Set items to have same height based on max (note: remove padding from max because it will distort visual result).
		// While looping, we can also hide item and add to our array.
		for(var i=0, item; i < items.length; i++) {
			item = $(items[i]); 
//			item.css({"height": (max - vPadding) + "px", "position":"absolute"});
			item.css({"position":"absolute"});
			item.hide();
			
			tabs.push(item);
		}

		// Items parent should equal their height + any vertical margin applied to them.
		items.parent().css({"height": (max + vMargin) + "px", "position":"relative"});


		// If automate is true, pause animation when cursor is held over a tab.
		if(_options.automate) {
			items.mouseover(_disableAutomation);
			items.mouseout(_tabbedArea.automate);
		}

		return tabs;
	}
	
	function _update(num) {
		// Fade current item out. Selected item fade in. Set _current variable to keep track.
		var selected = _controller.property("selected");
		var tabs = _controller.property("tabs");
		var buttons = _controller.property("buttons");
		var info = {
			from : { 
				button : buttons[selected],
				index : selected,
				tab : tabs[selected]
			},
			to : {
				button : buttons[num],
				index : num,
				tab : tabs[num]
			}
		}

		if(!_updating) {
			_updating = true;
			_options.beforeSwitch.call(info);
			buttons[selected].removeClass(_options.cssSelected);
			tabs[selected].fadeOut(_options.duration, function() { $(this).css("z-index", "-1"); });

			buttons[num].addClass(_options.cssSelected);
			tabs[num].fadeIn(_options.duration, function() { 
				_updating = false;
				$(this).css("z-index", _options.zIndexMax);
				_options.afterSwitch.call(info);
			});
			_controller.property("selected", num);
		}

		return false;
	}

	function _disableAutomation() {
		window.clearTimeout(_automateId);
		_automateId = null;
	}

	// PUBLIC:
	this.controller = _controller;

	this.forward = function() {
		var current = _controller.property("selected");
		if(!_updating) {
			if(current < _controller.property("buttons").length - 1) {
				current++;
			}
			else {
				current = 0;
			}
			_update(current);
		}
	}
	
	this.back = function() {
		var current = _controller.property("selected");
		if(!_updating) {
			if(current > 0) {
				current--;
			}
			else {
				current = _controller.property("buttons").length - 1;
			}
			_update(current);
		}
	}

	this.automate = function() {
		// Automate the forward/backward movements.
		// interval = speed between each movement.
		// reverse = movement (forward/back).
		var options = _options;
		var interval = options.interval > options.duration ? options.interval : options.duration + 100;
		var direction = options.reverse ? _tabbedArea.back : _tabbedArea.forward;

		if(_controller && !isNaN(interval) && interval > 1) {
			_automateId = window.setInterval(direction, interval);
		}
	}

	this.focus = function(tab) {
		var str = _helpers.getType(tab) == "String";
		var $buttons = $(".button", _controller.node);
		var $tab;
		if(str) {
			$buttons.each(function() {
				$tab = $(this);
				if($tab.text().toLowerCase() == tab.toLowerCase()) {
					return false;
				}
			});		  
		}
		else {
			$buttons.each(function(i) {
				$tab = $(this);
				// +1 so we can start count from 1, and pass in 4 (not 3) to request 4th tab.
				if((i + 1) == tab) {
					return false;
				}
			});
		}
		$tab.click();
	}


	this.setOptions = function(opts) {
		// Update options with new values.
		for(var i in opts) {
			_options[i] = opts[i];
		}
	}


}

