

function newButtons() {
	window.__Buttons.each(function(n) { n.rescan(); });
}

var Buttons = new Class({
	Implements: [Options],
	options: {
		iconHref: 'assets/images/buttons/'
	},
	initialize: function(options) {
		this.setOptions(options);
		//Asset.css('assets/css/Buttons.css');


		// store a reference to this instance so we can reference it later on, specifically to call rescan()
		if(!window.__Buttons) window.__Buttons = [ this ];
		this.rescan();
	},

	rescan: function() {
		$$('input[type=button],input[type=reset],input[type=submit],a.button,a.button-small').each(function(el) {
			if(!el.hasClass('legacy') && !el.hasClass('has-button')) new Button(el, this);
		}.bind(this));
	}

});


var Button = new Class({
	Implements: [Events],
	initialize: function(el, parent) {
		this.parent = parent;
		this.foo = 'bar';

		// this.el: store the original button element
		this.el = $(el);

		// the has-button class just prevents us from attaching buttons more than once to the same element
		if(this.el.hasClass('has-button')) return;
		else this.el.addClass('has-button');


		this.addEvents({
			click:		function(e) { this.click(e); },
			dblclick:	function(e) { this.dblclick(e); },
			mouseover:	function(e) { this.mouseover(e); },
			mouseout:	function(e) { this.mouseout(e); },
			mouseenter:	function(e) { this.mouseenter(e); },
			mouseleave:	function(e) { this.mouseleave(e); },

			mouseup:	function(e) { this.mouseup(e); },
			mousedown:	function(e) { this.mousedown(e); },
			mousemove:	function(e) { this.mousemove(e); },
			mousewheel:	function(e) { this.mousewheel(e); },

			blur:		function(e) { this.blur(e); },
			focus:		function(e) { this.focus(e); }

		});


		this.button = new Element('a', {
			id: this.el.id,
			'class': 'button ' + this.el.className,
			tabIndex: this.el.get('tabIndex'),
			title: this.el.get('title'),
			events: {
				click: 		function(e) { this.fireEvent('click', e); }.bind(this),
				dblclick: 	function(e) { this.fireEvent('dblclick', e); }.bind(this),
				mouseover:	function(e) { this.fireEvent('mouseover', e); }.bind(this),
				mouseout:	function(e) { this.fireEvent('mouseout', e); }.bind(this),
				mouseenter:	function(e) { this.fireEvent('mouseenter', e); }.bind(this),
				mouseleave:	function(e) { this.fireEvent('mouseleave', e); }.bind(this),
				mouseup:	function(e) { this.fireEvent('mouseup', e); }.bind(this),
				mousedown:	function(e) { this.fireEvent('mousedown', e); }.bind(this),
				mousemove:	function(e) { this.fireEvent('mousemove', e); }.bind(this),
				mousewheel:	function(e) { this.fireEvent('mousewheel', e); }.bind(this),
				blur:		function(e) { this.fireEvent('blur', e); }.bind(this),
				focus:		function(e) { this.fireEvent('focus', e); }.bind(this)
			}
		});

		if(this.el.hasClass('button-small')) {
			this.buttonType = 'small';
			this.button.addClass('button-small');
		}
		else this.buttonType = 'normal';

		// wraps left half of button (icon and label)
		this.buttonLeft = new Element('span', {
			'class': '_buttonLeft'
		}).inject(this.button);


		// icon
		this.buttonIcon = null;
		if(this.el.getAttribute('icon')) {
			var icon = this.parent.options.iconHref + this.el.getAttribute('icon').trim() + ((this.buttonType == 'small')?'-small':'') + '.png';
			this.buttonIcon = new Element('span', {
				'class': '_buttonIcon',
				styles: {
					backgroundImage: "url("+icon+")"
				}
			}).inject(this.buttonLeft);
		}


		this.buttonLabel = new Element('span', {
			'class': '_buttonLabel'
		}).inject(this.buttonLeft);

		if(this.el.tagName == 'A') {
			this.elType = 'anchor';
			this.buttonLabel.set('html', this.el.get('html')); 
			this.button.set('href', this.el.get('href'));
			this.button.set('target', this.el.get('target'));
		}
		else {
			this.elType = 'button';
			this.buttonLabel.set('html', this.el.getAttribute('value'));
		}

		// if the label is empty it is an icon-only button
		// we will hide the unnecessary label here so it looks nice
		if(this.buttonIcon && this.buttonLabel.get('html') == '') this.buttonLabel.setStyle('display', 'none');



		// right border of the button
		this.buttonRight = new Element('span', {
			'class': '_buttonRight'
		}).inject(this.button);


		// if we have a 'theme' attribute set we're going to change the bg image
		// and add a button-theme-themename class
		if(this.el.getAttribute('theme')) {
			this.theme = this.el.getAttribute('theme').trim();
			this.buttonLeft.setStyle('background-image', 'url(/assets/images/buttons/buttons-'+this.theme+'.png)');
			this.buttonRight.setStyle('background-image', 'url(/assets/images/buttons/buttons-'+this.theme+'.png)');
			this.button.addClass('button-theme-'+this.theme);
		}
		else this.theme = '';


		this.button.inject(this.el, 'after');

		// remove original element from dom
		this.el = this.el.dispose();

		// override set/get methods
		this.button.set = function(k, v) { this.set(k, v); }.bind(this);
		this.button.get = function(k, v) { return this.get(k); }.bind(this);

		var buttonRightSize = this.buttonRight.measure(function(){
    			return this.getSize();
		});
		var buttonLabelSize = this.buttonLabel.measure(function(){
    			return this.getSize();
		});
		// going to try to respect some of the button styles
		if( this.el.style.width ) {
			// if el has a width set
			var w = this.el.style.width.toInt();
			
			if( typeof(w) == 'number') this.buttonLabel.setStyle('width', w - 16);
			if( typeof(w) == 'number') this.button.setStyle('width', w);
		} else {
			
			this.buttonLabel.setStyle('width', this.buttonLabel.getWidth().toInt());
			this.button.setStyle('width', this.buttonLabel.getDimensions().x.toInt() + this.buttonRight.getDimensions().x.toInt());
		}
		// font styles
		var styleList = [ 'color', 'fontSize', 'fontWeight', 'fontStyle', 'textDecoration' ];
		for(var i=0; i<styleList.length; ++i) {
			if(this.el.style[styleList[i]]) {
				this.button.setStyle(styleList[i], this.el.style[styleList[i]]);
				this.buttonLabel.setStyle(styleList[i], this.el.style[styleList[i]]);
			}
		}



	},

	// set
	set: function(prop, value) {

		switch(prop) {
			case 'value':
				this.buttonLabel.innerHTML = value;
				break;

			default:
				switch ($type(prop)){
					case 'object':
						for (var p in prop) this.set(p, prop[p]);
						break;
					case 'string':
						var property = Element.Properties.get(prop);
						(property && property.set) ? property.set.apply(this, Array.slice(arguments, 1)) : this.setProperty(prop, value);
				}
		}
	},

	get: function(k) {
		switch(k) {
			case 'value': return this.buttonLabel.innerHTML; break;
		}

	},

	// tryEvent: attempt to execute events bound to the original element
	tryEvent: function(eName, eRef) {
		//test(eName);

		// try to execute original button event
		if( typeof(this.el['on'+eName]) == 'function') {
			//this.el['on'+eName](eRef);
			var func = Function.from(this.el['on'+eName]);
			func.attempt(eRef, this.button);
		}
		this.el.fireEvent(eName, eRef);
		//this.button.fireEvent(eName, eRef);
	},

	/**************** event handlers ****************/
	setButtonState: function(state) {
		this.button.removeClass('button-over');
		this.button.removeClass('button-small-over');
		this.button.removeClass('button-down');
		this.button.removeClass('button-small-down');
		this.button.removeClass('button-focus');
		this.button.removeClass('button-small-focus');


		switch(state) {
			case 'over':
			case 'down':
			case 'focus':
				this.button.addClass('button-' + ((this.button.hasClass('button-small'))?'small-':'') +state);
				break;
		}
	},

	getForm: function() {
		var f = this.button.getParent('form');
		if(!f) {
			var p = this.button.getParent();
			while(p && !f && p.tagName != 'BODY') {
				if(p.tagName == 'FORM') {
					f = p;
					break;
				}
				else f = p.getElement('form');
				p = p.getParent();
			}
		}
		return f;
	},
	click: function(e) {
		// the button click event should fire first
		this.tryEvent('click', e);


		if(this.elType == 'anchor') {
			// this button was created from a link, we need to blur here or the link will remain in the over state
			if(!Browser.ie) this.button.blur();
		}
		else {
			// special cases for reset and submit buttons
			switch( this.el.getAttribute('type') ) {
				case 'reset':
					try { this.getForm().reset(); } catch(e) {};
					break;
	
				case 'submit':
					var f = this.getForm();
					if(f) {
						// The form should always submit unless we have an onsubmit function that returns boolean false
						var submitThis = true;
	
						if(typeof(f.onsubmit) == 'function') {
							var ret = f.onsubmit();
							if(ret === false) submitThis = false;
						}
	
						// if we have one, we need to send the submit button name also
						if(submitThis) {
							$(f).getElements('input.__ButtonsHiddenSubmitButtonName').destroy();
	
							if(this.el.getAttribute('name')) {
								new Element('input', {
									type: 'hidden',
									'class': '__ButtonsHiddenSubmitButtonName',
									name: this.el.getAttribute('name'),
									value: this.el.getAttribute('name')
								}).inject(f);
							}
							f.submit();
						}
	
					}
					break;
			}
		}
	},

	dblclick: function(e) {
		this.tryEvent('dblclick', e);
	},

	mouseover: function(e) {
		this.tryEvent('mouseover', e);
	},

	mouseout: function(e) {
		this.tryEvent('mouseout', e);
	},

	mouseenter: function(e) {
		this.setButtonState('over');
		this.tryEvent('mouseenter', e);
	},

	mouseleave: function(e) {
		this.setButtonState('out');
		this.tryEvent('mouseleave', e);
	},

	mouseup: function(e) {
		this.setButtonState('over');

		this.tryEvent('mouseup', e);
	},

	mousedown: function(e) {
		// we need to manually focus the button here first for non-IE browsers
		// or the real focus event will superceed the mousedown
		if(!Browser.ie) this.button.focus();

		this.setButtonState('down');

		this.tryEvent('mousedown', e);
	},

	mousemove: function(e) {
		this.tryEvent('mousemove', e);
	},

	mousewheel: function(e) {
		this.tryEvent('mousewheel', e);
	},

	focus: function(e) {
		this.setButtonState('focus');

		this.tryEvent('focus', e);
	},

	blur: function(e) {
		this.setButtonState('out');

		this.tryEvent('blur', e);
	}

});










