/************************************************************************
/
/	ELEMENT EXTENSIONS
/	-------------------------------------------------------
/	Helper functions that allow you to easily extend an element
/	with UI functionality
/	Also some of the jQuery API is implemented and some aliases too
/
/	V1.02 	- 2 customised methods added (KPB), removed Browser.js dependencies
/	V1.03	- Selectors.Pseudo.lt / gt added to return all matched elements before or after a given number
/
/***********************************************************************/
Element.implement({
	/*
	---------------------------------------------------------------------
	CLICK
	---------------------------------------------------------------------
	Adds the jQuery "$$().click()" style event binding
	---------------------------------------------------------------------
	*/
	click: function(fn)	{
		return this.addEvent('click', fn);
	},
	/*
	---------------------------------------------------------------------
	SET LABEL
	---------------------------------------------------------------------
	A label that appears inside a form field until you click on it, removes
	it when forms are submitted too
	---------------------------------------------------------------------
	*/
	setLabel: function(attr)	{
		var attr = attr || 'alt';
		var label = this.getProperty(attr);
		if($defined(label))	{
			this.store('abacus:innerLabel', label);
			this.addEvents({
				'focus': function()	{
					if(this.get('value').clean() == label)
						this.set('value', '').removeClass('helpOn');
				},
				'blur': function()	{
					if(this.get('value').clean() == '' || this.get('value').clean() == label)
						this.set('value', label).addClass('helpOn');
				},
				'click': function()	{
				}
			}).fireEvent('blur');
			var element = this;
			$$('FORM').addEvent('submit', function()    {
			    if(element.get('value').clean() == label)
					element.set('value', '').removeClass('helpOn');
			});
		}
		return this.removeProperty(attr);
	},
	/*
	---------------------------------------------------------------------
	MAKE BUTTON
	---------------------------------------------------------------------
	Adds mouseenter/mouseleave events to an element so it can have a
	hover state cross-browser, preloads hover states
	---------------------------------------------------------------------
	*/
	makeButton: function()	{
	    this.addEvents({
		    'mouseover': function()	{
			    this.setProperty('src', this.getProperty('src').replace(".over", "").replace(/\.(...)$/, ".over.$1"));
		    },
		    'mouseout': function()	{
			    this.setProperty('src', this.getProperty('src').replace(/\.over\.(...)$/, ".$1"));
		    },
		    'click': function() {
		        this.fireEvent('mouseout');
		    }
	    }).fireEvent('mouseout');
	    new Image().src = this.getProperty('src').replace(/\.(...)$/, ".over.$1");
		return this;
	},
	/*
	---------------------------------------------------------------------
	MAKE TABS
	---------------------------------------------------------------------
	Turns the elements into tabs to show and hide content with
	---------------------------------------------------------------------
	*/
	makeTabs: function(selector)	{
		var tabs = this.getChildren();
		var contents = this.getAllNext();
		tabs.each(function(tab, i)	{
			tab.addEvent('click', function()	{
				tabs.removeClass('selected');
				contents.removeClass('selected');
				this.addClass('selected').blur();
				contents[i].addClass('selected');
				return false;
			});
		});
		if($defined(selector))	
			this.getElement(selector).fireEvent('click');
		return this;
	},
	/*
	---------------------------------------------------------------------
	CHANGE INTO TABS
	---------------------------------------------------------------------
	Changes a series of lists with headings into a tabbed block
	---------------------------------------------------------------------
	*/
	changeIntoTabs: function(selector)	{
		var tabs = this.getElements('.active_block > H2');
		var blocks = this.getElements('.active_block');
		var tabContainer = new Element('DIV').addClass('tab_block').set('html', '<ul></ul>').inject(this, 'top');
		tabs.each(function(tab, i)	{
			new Element('LI').grab(tab).inject(tabContainer.getElement('UL'));
			tab.addEvent('click', function()	{
				blocks.setStyle('display', 'none');
				blocks[i].setStyle('display', '');
				tabs.getParents().each(function(el)	{
					el.removeClass('current');
				});
				this.getParent().addClass('current');
			});
		});
		if($defined(selector))	
			this.getElement(selector).fireEvent('click');
		else
			tabs[0].fireEvent('click');
		return this;
	},
	/*
	---------------------------------------------------------------------
	CHANGE INTO TABS - CUSTOMISED
	---------------------------------------------------------------------
	Changes elements with class="give hover" into a tabbed block
	---------------------------------------------------------------------
	*/
	customChangeIntoTabs: function(selector) {
    	var tabs = this.getElements('.active_block > .give');
		var blocks = this.getElements('.active_block');
		var tabContainer = new Element('DIV').addClass('tab_block').set('html', '<ul></ul>').inject(this, 'top');
		tabs.each(function(tab, i)	{
			new Element('LI').grab(tab).inject(tabContainer.getElement('UL'));
			tab.addEvent('click', function()	{
				blocks.setStyle('display', 'none');
				blocks[i].setStyle('display', '');
				tabs.getParents().each(function(el)	{
					el.removeClass('current');
				});
				this.getParent().addClass('current');
			});
		});
		if($defined(selector))	
			this.getElement(selector).fireEvent('click');
		else
			tabs[0].fireEvent('click');
		return this;
	},
	/*
	---------------------------------------------------------------------
	CHECK
	---------------------------------------------------------------------
	Checks a checkbox for you
	---------------------------------------------------------------------
	*/
	check: function()	{
		this.checked = true;
		return this;
	},
	/*
	---------------------------------------------------------------------
	UNCHECK
	---------------------------------------------------------------------
	Unchecks a checkbox for you
	---------------------------------------------------------------------
	*/
	uncheck: function()	{
		this.checked = false;
		return this;
	},
	/*
	---------------------------------------------------------------------
	MAKE ALL CLICKABLE
	---------------------------------------------------------------------
	Hunts down a link within an element and makes the whole thing clickable
	---------------------------------------------------------------------
	*/
	makeAllClickable: function(onClick)	{
		var linkElement = this.getElements('A');
		var href = linkElement.getProperty('href').clean();
		this.addEvents({
			'mouseenter': function()	{
				this.addClass('hover');
				if(this.hasClass('first'))
					this.addClass('firstHover');
				if(this.hasClass('last'))
					this.addClass('lastHover');
			},
			'mouseleave': function()	{
				this.removeClass('hover');
				if(this.hasClass('first'))
					this.removeClass('firstHover');
				if(this.hasClass('last'))
					this.removeClass('lastHover');
			},
			'click': function()	{
				$defined(onClick) ? onClick.attempt(href, this) : window.location = href;
			}
		});
		var self = this;
		linkElement.addEvent('click', function()	{
			this.blur();
			self.fireEvent('click');
			return false;
		});
		return this.store('abacus:href', href);
	},
	/*
	---------------------------------------------------------------------
	GIVE FOCUS CLASS ON SELECT
	---------------------------------------------------------------------
	When you select a form element in IE it needs to be given a class of
	'focus' so we can use the pseudo CSS selector :FOCUS
	---------------------------------------------------------------------
	*/
	giveFocusClassOnSelect: function()	{
		if(Browser.Engine.trident)	{
			this.addEvents({
				'focus': function()	{
					this.addClass('focus');	
				},
				'blur': function()	{
					this.removeClass('focus');	
				}
			});
		}
		return this;
	},
	/*
	---------------------------------------------------------------------
	SET AS LOADING
	---------------------------------------------------------------------
	Allows you to define an element as loading. A div with a class of
	'loading' will be absolutely positioned above the element.
	---------------------------------------------------------------------
	*/
	setAsLoading: function()	{
		var loadingElement = this.retrieve('abacus:ui:loading');
		if(!$defined(loadingElement))	{
			loadingElement = new Element('DIV');
			this.store('abacus:ui:loading', loadingElement);
		}
		loadingElement.setStyles(this.getCoordinates()).setStyles({
			position: 'absolute',
			opacity: 0.7
		}).addClass('loading').inject(document.id(document.body));
		return this;
	},
	/*
	---------------------------------------------------------------------
	STOP AS LOADING
	---------------------------------------------------------------------
	Destroys the element positioned above it with the 'loading' class
	---------------------------------------------------------------------
	*/
	stopAsLoading: function(nohighlight)	{
		var loadingElement = this.retrieve('abacus:ui:loading');
		loadingElement.dispose();
		return ($defined(nohighlight)) ? this : this.set('tween', {duration: 'long'}).highlight('#FFC');
	},
	/*
	---------------------------------------------------------------------
	MAKE EXPANDABLE
	---------------------------------------------------------------------
	Lets you set a list to have an expanded and collapsed state
	---------------------------------------------------------------------
	*/
	makeExpandable: function()	{
		if(this.get('tag') == 'ul')	{
			// It's a list so add more/less links
			this.getElements('LI').each(function(item, i)	{
				if(i < 5)	{
					item.addClass('always');
				}
				else if(i == 5)	{
					new Element('LI').addClass('more').set('html', 'more&hellip;').inject(this);
				}
			}, this);
			this.getElements('LI.more').addEvent('click', function()	{
				this.set('html', this.getParent().hasClass('collapsed') ? 'less&hellip;' : 'more&hellip;');
				this.getParent().toggleClass('collapsed');
			});
			if(!this.hasClass('start expanded'))	this.addClass('collapsed');
		}
		else	{
			// Not a list so it's a whole section
			var toggle = this.getFirst();
			toggle.addEvent('click', function()	{
				this.getParent().toggleClass('hidden');							  
			});
			if(this.hasClass('start collapsed'))	{
				this.addClass('hidden');
			}
		}
		return this;
	},
	/*
	---------------------------------------------------------------------
	MAKE EXPANDABLE - CUSTOMISED
	---------------------------------------------------------------------
	Change text of clicked element (e.g. "more" --> "less")
	---------------------------------------------------------------------
	*/
	customMakeExpandable: function()	{
		if(this.get('tag') == 'ul')	{
			// It's a list so add more/less links
			this.getElements('LI').each(function(item, i)	{
				if(i < 5)	{
					item.addClass('always');
				}
				else if(i == 5)	{
					new Element('LI').addClass('more').set('html', 'more&hellip;').inject(this);
				}
			}, this);
			this.getElements('LI.more').addEvent('click', function()	{
				this.set('html', this.getParent().hasClass('collapsed') ? 'less&hellip;' : 'more&hellip;');
				this.getParent().toggleClass('collapsed');
			});
			if(!this.hasClass('start expanded'))	this.addClass('collapsed');
		}
		else	{
			// Not a list so it's a whole section
			var toggle = this.getFirst();
			toggle.addEvent('click', function()	{
				this.getParent().toggleClass('hidden');							  
				//change SPAN to show "more"/"less" as appropriate
				var span = this.getElement('span');
				span.toggleClass('moreless').set('html', span.hasClass('moreless') ? 'more' : 'less');
			});
			if(this.hasClass('start collapsed'))	{
				this.addClass('hidden');
			}
		}
		return this;
	},
	/*
	---------------------------------------------------------------------
	HIDE
	---------------------------------------------------------------------
	Sets an element's display: none
	---------------------------------------------------------------------
	*/
	hide: function()	{
		return this.setStyle('display', 'none');
	},
	/*
	---------------------------------------------------------------------
	SHOW
	---------------------------------------------------------------------
	Sets an element's display to a blank so it follows the stylesheet.
	---------------------------------------------------------------------
	*/
	show: function(type)	{
		return this.setStyle('display', $defined(type) ? type : '');
	},
	/*
	---------------------------------------------------------------------
	EMULATE BREAK WORD
	---------------------------------------------------------------------
	Pads out an element's inner HTML with a special character that allows
    break-word in Firefox and Safari / Chrome.
	---------------------------------------------------------------------
	*/
	emulateBreakWord: function()	{
		if(Browser.Engine.gecko || Browser.Engine.webkit)	{
			var html = this.get('html');
			html = html.split('').join(String.fromCharCode(8203));
			return this.set('html', html);
		}
	},
	/*
	---------------------------------------------------------------------
	GIVE HOVER STATE
	---------------------------------------------------------------------
	Gives a hover state in IE6 (.hover) or all browsers if you pass in 'true'
	---------------------------------------------------------------------
	*/
	giveHoverState: function(all)    {
	    var all = all || false;
	    if(all || (Browser.Engine.trident && Browser.Engine.version == 4))	{
			this.addEvents({
				'mouseenter': function()	{
					this.addClass('hover');
				},
				'mouseleave': function()	{
					this.removeClass('hover');
				}
			});
	    }
	    return this.fireEvent('mouseleave');
	},
	/*
	---------------------------------------------------------------------
	MAKE VIEW SWITCHER
	---------------------------------------------------------------------
	Adds the view changing functionality 
	---------------------------------------------------------------------
	*/
	makeViewSwitcher: function()    {
	    var element = this;
        return this.getElements('.viewChanger .view').addEvent('click', function()	{
            element.getElements('.viewChanger .view').removeClass('selected');
            this.addClass('selected');
            element.getElements('UL').setProperty('class', '').addClass(this.getParent().getProperty('class'));
            this.blur();
            return false;
        });
	}
});

/************************************************************************
/
/	Selectors
/
/***********************************************************************/
Selectors.Pseudo.gt = function(count){
	return $(this).getAllPrevious(this.get('tag')).length >= count;
};
Selectors.Pseudo.lt = function(count){
	return $(this).getAllPrevious(this.get('tag')).length < count - 1;
};

/************************************************************************
/
/	Aliases
/
/***********************************************************************/
Element.alias('match', 'is');

