/**
 * © 2009 Zetafleet. All rights reserved.
 */

(function($)
{
	$.fn.smartDropDown = function(options)
	{
		return this.each(function() {
			new $.smartDropDown(this, options);
		});
	};
	
	$.fn.smartCheckbox = function(options)
	{
		return this.each(function() {
			new $.smartCheckbox(this, options);
		});
	};
	
	$.smartCheckbox = function(element, config)
	{
		if(element.tagName.toUpperCase() != 'INPUT'
		|| (element.type.toUpperCase() != 'CHECKBOX' && element.type.toUpperCase() != 'RADIO'))
		{
			return;
		}
		
		// To reference 'this' from inside closures
		var self = this;
		
		var defaults = {
			'class'        : '',
			'deselectable' : false
		};
		
		/**
		 * Toggles a clicked checkbox or radio button.
		 * @access public
		 */
		this.toggle = function(e)
		{
			// 32 = space bar
			if(e.keyCode && e.keyCode != 32)
			{
				return;
			}
		
			if(!self.isCheckbox) // Radio button
			{
				if(self.checkbox[0].checked && !self.config.deselectable)
				{
					return;
				}

				$('input[type="radio"][name="' + self.checkbox[0].name + '"]').parent()
				                                                              .attr('aria-checked', 'false');
			}
			
			e.preventDefault();
			e.stopPropagation();

			self.checkbox.triggerHandler('click');
			self.checkbox[0].checked = !self.checkbox[0].checked;
			self.wrapper.attr('aria-checked', self.checkbox[0].checked.toString());
			self.wrapper.focus();
		};
		
		this.config = $.extend({}, defaults, config || {});
		
		this.checkbox   = $(element);
		this.isCheckbox = element.type.toUpperCase() == 'CHECKBOX';

		this.wrapper = this.checkbox.wrap('<span class="smartCheckbox"></span>')
		                            .css({ 'position' : 'absolute', 'left' : '-32767em' })
		                            .parent()
		                            .attr('aria-checked', this.checkbox[0].checked.toString())
		                            .attr('role', this.isCheckbox ? 'checkbox' : 'radio')
		                            .attr('tabindex', 0)
		                            .addClass(this.config['class']);

		this.checkbox.attr('tabIndex', -1);

		this.wrapper.click(this.toggle);
		this.wrapper.keypress(this.toggle);
		
		if(element.id)
		{
			$('label[for="' + element.id + '"]').click(this.toggle);
		}
		
		this.checkbox.parents('label').click(this.toggle);
	};

	$.smartDropDown = function(element, config)
	{
		if(element.tagName.toUpperCase() != 'SELECT')
		{
			return;
		}

		// To reference 'this' from inside closures
		var self = this;
	
		var defaults = {
			'class'    : '',
			'comboBox' : false
		};
		
		this.Key = {
			UP   : 38,
			DOWN : 40,
			DEL  : 46,
			TAB  : 9,
			ESC  : 27,
			RETURN    : 13,
			PAGEUP    : 33,
			PAGEDOWN  : 34,
			BACKSPACE : 8
		};
		
		/**
		 * Opens the drop-down if a down arrow is pressed when the text field is
		 * focused.
		 * @access public
		 */
		this.checkOpenList = function(e)
		{
			if(e.keyCode == self.Key.DOWN)
			{
				self.openList(e);
			}
		};
		
		/**
		 * Displays the drop-down menu.
		 * @access public
		 */
		this.openList = function(e)
		{
			if(self.list.is(':visible'))
			{
				self.closeList(e);
				return;
			}
			
			// Close all other open lists
			$(document).click();

			self.list.show();
			self.wrapper.addClass('focused');
			self.list.find('li.selected').focus();

			e.stopPropagation();
			e.preventDefault();
			$(document).click(self.closeList);
		};

		/**
		 * Closes the drop-down menu and sets the real drop-down
		 * to its proper value.
		 * @access public
		 */
		this.closeList = function(e)
		{
			// Set the real drop-down to its proper state
			var dropdown = self.dropdown[0];
			var option = $(dropdown.options[dropdown.selectedIndex]);
			self.input.val(option.text());
			self.list.find('li').removeClass('selected');
			self.list.find('li').eq(dropdown.selectedIndex).addClass('selected');
			self.wrapper.removeClass('focused');

			self.list.hide();
			$(document).unbind('click', self.closeList);
		};
		
		/**
		 * Called when a user selects an option from the list.
		 * @access public
		 */
		this.selectOption = function(e)
		{
			var option = $(this);

			self.dropdown[0].selectedIndex = option.parent().children('li').index(this);
			self.dropdown.change();
			self.closeList(e);
		};

		/**
		 * Keyboard navigation support for the fake drop-down.
		 * @access public
		 */
		this.navigateList = function(e)
		{
			var options      = self.list.find('li'),
			    currentIndex = options.index(self.list.find('li.selected'));
			
			e.preventDefault();

			if(e.keyCode == self.Key.RETURN ||
			   e.keyCode == self.Key.TAB)
			{
				self.selectOption.call(self.list.find('li.selected'), e);
				self.input.focus();
				return;
			}
			
			if(e.keyCode == self.Key.ESC)
			{
				self.closeList(e);
				self.input.focus();
				return;
			}

			if(e.keyCode == self.Key.UP)
			{
				if(--currentIndex < 0)
				{
					currentIndex = options.length - 1;
				}
			}
			else if(e.keyCode == self.Key.DOWN)
			{
				if(++currentIndex >= options.length)
				{
					currentIndex = 0;
				}
			}

			self.list.find('li.selected').removeClass('selected');
			$(options[currentIndex]).addClass('selected').focus();
		};
		
		this.config = $.extend({}, defaults, config || {});

		this.dropdown = $(element);
		this.wrapper  = this.dropdown.wrap('<span class="smartDropDown"></span>')
		                             .css({ 'position' : 'absolute', 'left' : '-32767em' })
		                             .parent()
		                             .attr('aria-haspopup', 'true')
		                             .addClass(this.config['class']);

		this.input   = $('<input type="text" />').appendTo(this.wrapper)
		                                         .val($(this.dropdown[0].options[this.dropdown[0].selectedIndex]).text());
		$('<span class="message" />').appendTo(this.wrapper);
		this.arrow   = $('<div class="arrow" />').appendTo(this.wrapper);
		
		this.list    = $('<div class="options" role="listbox" />').appendTo(this.wrapper)
		                                                          .hide();

		// Combo-box
		if(this.config.comboBox)
		{
			this.wrapper.attr('role', 'combobox');
			this.input.attr('role', 'textfield');
			
			if(element.id)
			{
				$('label[for="' + element.id + '"]').click(function(e) { e.stopPropagation(); e.preventDefault(); this.input.focus(); });
			}
			
			this.dropdown.parents('label').click(function(e) { e.stopPropagation(); e.preventDefault(); this.input.focus(); });
		}

		// Drop-down list
		else
		{
			this.wrapper.attr('role', 'select');
			this.input.attr('readonly', 'readonly');
			
			// Stop the input field’s text from being selected when it is clicked on
			this.input.mousedown(function(e) { e.preventDefault(); });

			// IE: “Standards? What are those?”
			this.input.bind('selectstart', function(e) { e.preventDefault(); });
			
			this.input.click(this.openList);
			
			if(element.id)
			{
				$('label[for="' + element.id + '"]').click(function(e) { e.stopPropagation(); self.openList(e); });
			}
			
			this.dropdown.parents('label').click(function(e) { e.stopPropagation(); self.openList(e); });
		}
		
		this.dropdown.attr('tabIndex', -1);

		this.arrow.click(this.openList);
		this.input.keydown(this.checkOpenList);
		this.list.keydown(this.navigateList);
		this.list.mousedown(function(e) { e.preventDefault(); });

		var ulList = $('<ul />').appendTo(this.list);
		this.dropdown.children('option').each(function()
		{
			var option = $('<li role="listitem" />').text($(this).text())
			                                        .attr('tabindex', -1);

			if(self.dropdown[0].selectedIndex == this.index)
			{
				option.addClass('selected');
			}

			option.click(self.selectOption);
			option.appendTo(ulList);
		});
	};
})(jQuery);(function($) {
	var w = $(window), d = document.documentElement, ds = d.style;
	d.style.backgroundColor = '#9ec5a8';

	w.load(function() {
		var requestAnimFrame = (function() {
			return window.requestAnimationFrame ||
				window.webkitRequestAnimationFrame ||
				window.mozRequestAnimationFrame ||
				window.oRequestAnimationFrame ||
				window.msRequestAnimationFrame ||
				function (callback) {
					window.setTimeout(callback, 33);
				};
		})();

		(function updateBg() {
			var yPos = '-' + ~~((document.body.scrollTop || d.scrollTop) * 0.3) + 'px';

			if (ds.backgroundPositionY) {
				ds.backgroundPositionY = yPos;
			}
			else {
				ds.backgroundPosition = '0px ' + yPos;
			}

			requestAnimFrame(updateBg);
		}());

		d.style.backgroundColor = '';
		d.style.backgroundAttachment = 'fixed';
	});
})(jQuery);
