
/* --- Additional Methods --- */

Element.addMethods({
	findClassName: function(element, className) {
	  if (!(element = $(element))) return;
		if (typeof className == 'string') className = new RegExp(className);
		return element.classNames().detect(function(c){ return (className.exec(c)?true:false) });
	},
	cancelClick: function(element) {
		if (!(element = $(element))) return;
		element.onclick = element.onmousedown = function() {return false};
		return element;
	}
});



/* --- Object Classes ---*/


var Arrow = Class.create({
	initialize: function(container){
		this.container = container = $(container);
		this.paddingRight = 10;
		this.bindings = [];
		this.elm = document.createElement('div');
		container.appendChild(this.elm);
		this.elm = $(this.elm);
		this.hide();
		this.elm.addClassName('redArrow');
		// this.moveTo(y,x);
		// if(!dontShow) this.show();
		return this;
 	},
	hide: function() { this.elm.hide(); return this; },
	show: function() { this.elm.show(); return this; },
	moveTo: function(y,x) {
		this.elm.setStyle({
			top: parseInt(y)+'px',
			left: parseInt(x)+'px'
		})
		return this;
	},
	pointAt: function(obj) {
		this.pointedAt = $(obj);
		this._pointAt();
		this.observerFunction = function() { 
			if (!Prototype.Browser.IE) return this._pointAt(); 
			setTimeout(function() { this._pointAt(); }.bind(this), 100);
		}.bind(this);
		Event.observe(window,'resize', this.observerFunction);
		return this;
	},
	release: function() {
		this.hide();
		this.pointedAt = null;
		Event.stopObserving(window,'resize', this.observerFunction);
		return this;
	},
	_pointAt: function() {
		obj = this.pointedAt;
		var objDim = obj.getDimensions();
		var elmDim = this.elm.getDimensions();		
		var p = Position.cumulativeOffset(obj)
		var top = (p[1] +(objDim.height / 2) - (elmDim.height / 2) );
		var left = (p[0] - elmDim.width - this.paddingRight );
		this.moveTo(top,left);
	},
	getEventBindings: function(elm) {
		var indexOf = this.bindings.pluck('eventElm').indexOf(elm);
		return (indexOf == -1)? null : this.bindings[indexOf];
	},
	bindTo: function(eventElm, positionElm) {
		eventElm = $(eventElm);
		positionElm = ($(positionElm)||eventElm);
		
		this.bindings.push({
			eventElm:eventElm,
			positionElm:positionElm,
			onFocus:function(){ this.pointAt(positionElm).show();	}.bind(this),
			onBlur:function(){ this.release(); }.bind(this)
		});
		
		Event.observe(eventElm, 'focus', this.bindings.last().onFocus);
		Event.observe(eventElm, 'blur', this.bindings.last().onBlur);
		return this;
	},
	unBindFrom: function(eventElm) {
		eventElm = $(eventElm);
		var bindings = this.getEventBindings(eventElm);
		if (!bindings) return this;
		Event.stopObserving(eventElm, 'focus', bindings.onFocus);
		Event.stopObserving(eventElm, 'blur', bindings.onBlur);
		return this;
	},
	bindToFor: function(positionElm,eventElm) {
		this.bindTo(eventElm, positionElm);
	}
});


// This class adds .methods to all nodes of type (input,checkbox,textarea)
var FormElement = Class.create({
	initialize : function(elm){
		this.elm = elm = $(elm);
		this.elm.Methods = this;

		if (elm.readAttribute('name')) elm.addClassName(elm.readAttribute('name'));
		if (elm.readAttribute('type')) elm.addClassName('type'+elm.readAttribute('type').capitalize());

		elm.observe('focus',		function() { elm.addClassName('focus') });
		elm.observe('blur',			function() { elm.removeClassName('focus') });
		elm.observe('mouseover',function() { elm.addClassName('hover')} );
		elm.observe('mouseout',	function() { elm.removeClassName('hover')} );

 	},
	formElements: function(value) { return Form.getInputs(this.elm.form) },
	previousElement: function() {
		var elms = this.formElements();
		return elms[( elms.indexOf(this.elm) - 1)];
	},
	nextElement: function() {
		var elms = this.formElements();
		return elms[( elms.indexOf(this.elm) + 1)];
	},
	focusPreviousElement: function() {
		var pe = this.previousElement();
		if (typeof pe == 'undefined') return false;
		if (!pe.Methods.autoTab) return false;
		pe.focus();
		pe.Methods.setSelectionRange(pe.value.length,pe.value.length);
	},
	focusNextElement: function() {
		var ne = this.nextElement();
		if (typeof ne == 'undefined') return false;
		ne.focus();
	},
	removeTypeClass: function() {
		this.elm.classNames().findAll(function(s) { return s.match(/type.*/)	}).each(function(className) { this.elm.removeClassName(className) }.bind(this));
	}
});


// This class adds additional .Methods to all input nodes of type text or password
var TextInput = Class.create(FormElement, {
	initialize : function($super, elm){
		$super(elm);
		
		if(! elm.findClassName(/^ibi-/)) elm.addClassName('ibi-'+elm.readAttribute('name')); 
		this.backgroundImageURL = Globals.imagesURL+'inputBg-'+elm.findClassName(/^ibi-/).replace(/^ibi-/,'')+'.gif';
		elm.setStyle({'backgroundImage': 'url('+this.backgroundImageURL+')'})
		
		this.storeState();
		
		elm.observe('focus', function() { 
			this.updateClassNames();
			if (this.autoTab) this.setSelectionRange(0,this.elm.value.length);
		}.bind(this));

		elm.observe('blur', this.updateClassNames.bind(this));
		elm.observe('keydown', this.storeState.bind(this));
		elm.observe('keyup', function(e) {
			this.updateClassNames();
			if (e.keyCode != 9 & this.autoTab){
				try{ if ([8,16,37,38,39,40,46].indexOf(e.keyCode) == -1 & this.elm.value.length >= this.elm.maxLength & this.nextElement().Methods.autoTab) this.focusNextElement(); }catch(e){}
				if (
					[8].indexOf(e.keyCode) != -1 & 
					this.elm.lastSelection.length == 0 & 
					this.elm.value.length == 0
				) this.focusPreviousElement();
				// this.elm.lastValue.length <= 1 &
			}
		}.bind(this));
		
		this.updateClassNames();
		elm.onkeypress = this.onKeyPress.bindAsEventListener(this);
		return this;
 	},
	selection: function() {
			if (typeof this.selectionStart != 'undefined' & typeof this.selectionEnd != 'undefined') return	{
				start: this.selectionStart,
				end: this.selectionEnd,
				length: (this.selectionEnd - this.selectionStart)
			};
			if (this.createTextRange) return {
				start: 0,
				end: 0,
				length: this.createTextRange().text.length
			};
			return{start:0,end:0,length:0}
	},

	setSelectionRange: function(start,end) {
		if (typeof this.elm.setSelectionRange == 'function') return this.elm.setSelectionRange(start,end);
		start = (start||0);
		end = (end||0)
		var range = this.elm.createTextRange();
		range.collapse(true);
		range.moveStart('character', start);
		range.moveEnd('character', end);
		range.select();
	},

	storeState: function() {
		this.elm.lastValue = this.elm.value;
		this.elm.lastSelection = this.selection();
	},
	// validCharactor: optional function to validate input field's charactors before they are allowed
	onKeyPress: function(e) {
		var keyCode = (window.event)? window.event.keyCode : e.which;
		var charactor = String.fromCharCode(keyCode);
		return (typeof this.validCharactor == 'function')? this.validCharactor(e, keyCode, charactor) : true;
	},
	updateClassNames: function() {
		if (this.elm.value == ''){
			this.elm.addClassName('empty');
			this.elm.removeClassName('notEmpty');
		}else{
			this.elm.removeClassName('empty');
			this.elm.addClassName('notEmpty');
		}
		return this;
	}
});

// This class adds additional .Methods to all input nodes of type text or password
var Checkbox = Class.create(FormElement, {
	initialize : function($super, elm){
		$super(elm);
		
	}
});


// This class adds additional .Methods to all input nodes of type text or password
var Textarea = Class.create(FormElement, {
	initialize : function($super, elm){
		$super(elm);

	}
});

// This class adds additional .Methods to all input nodes of type text or password
var Dropdown = Class.create(FormElement, {
	initialize : function($super, elm){
		$super(elm);

	}
});



// This class adds additional .Methods to all input nodes of type text or password
var Button = Class.create(FormElement, {
	initialize : function($super, elm){
		$super(elm);
		
	}
});

// This class adds additional .Methods to all input nodes of type text or password
// usage: (either will work)
//  <input class="redButton" type="submit" name="signup" value="Sign up for Private Beta"></p>
//  <a class="redButton" href="">Sign up for Private Beta</a></p>
//  
var RedButton = Class.create(FormElement, {
	initialize : function($super, elm){
		this.elm = elm = $(elm);
		this.elm.Methods = this;
		// $super(elm);
		this.removeTypeClass();

		var id = elm.id || false;
		if (!(elm.nodeName == 'A' || elm.nodeName == 'INPUT')) return;
		
		this.container = container = $(document.createElement('div'));
		container.addClassName('redButton');
		container.Methods = this;
		elm.parentNode.insertBefore(container,elm);
		var div = $(document.createElement('div'));
		div.addClassName('generated');
		container.appendChild(div);
		div.appendChild(elm);
		elm.removeClassName('redButton');
		elm.addClassName('generated');
		
		if (elm.nodeName == 'A'){
			var input = $(document.createElement('INPUT'));
			var href=elm.href;
			var elmOnclickEvent = (typeof elm.onclick != 'undefined' && elm.onclick != null)? elm.onclick : function() { return true; };
			input.type = "button";
			input.onclick = input.onclick = function(e) {
				if (e) Event.stop(e);
				if (elmOnclickEvent() != false) window.location=href;
			}
			input.value = (elm.innerText||elm.textContent);
			input.addClassName('generated');
			elm.parentNode.insertBefore(input,elm);
			elm.parentNode.removeChild(elm);
			this.elm = elm = input;
		}
		if (id) this.elm.id = id;

		this.container.observe('click', function() {
			this.click();
		}.bindAsEventListener(this));
		
		
		
		// this.container.observe('mousedown', this.press.bind(this));
		// this.container.observe('mouseup', this.depress.bind(this));
		// this.container.observe('mouseout', this.depress.bind(this));
		
		this.container.observe = function(type, handler) { 
			Event.observe(this.elm, type, handler)
			Element.observe(this.container, type, handler);
		}.bind(this);
		
		return this;
	},
	
	press: function() {	this.container.addClassName('pressed'); },
	depress: function() { this.container.removeClassName('pressed'); },
	click: function() { this.elm.click(); } // TODO see if there is a better way to do this
});



var Condensable = Class.create({
	initialize : function(elm){
		this.elm = elm = $(elm);		
		this.toggler = $(this.elm.getElementsByClassName('toggler')[0]);
		this.toggler.observe('click', this.toggle.bind(this));	

		this.toggler.observe('mouseover', function() { this.addClassName('hover'); });
		this.toggler.observe('mouseout', function() { this.removeClassName('hover'); });

		this.condense();

		return this;
 	},
	toggle: function() {
		return this.elm.hasClassName('isCondensed')? this.unCondense() : this.condense();
	},
	condense: function(value) {
		this.elm.addClassName('isCondensed');
		return this;
	},
	unCondense: function() {
		this.elm.removeClassName('isCondensed');
		return this;
	}
});


/*
 	ON LOAD.....
*/


Event.observe(window,'load',function() {

	//Setting up forms
	window.FormFocusArrow = new Arrow($('content'));
	$$('input,textarea,select').each(function(formElement){
		formElement = $(formElement);
		if (formElement.readAttribute('jstyle') != null && formElement.readAttribute('jstyle').match(/no/i)) return;		
		if (formElement.hasClassName('redButton')) return;

		switch(formElement.nodeName.toLowerCase()){
			case 'input':
				switch(formElement.readAttribute('type').toLowerCase()){
					case 'text': case 'password': new TextInput(formElement); break;    
					case 'button': case 'submit': new Button(formElement); break;
					case 'checkbox': new Checkbox(formElement); break;
				}
				
			break;    
			case 'textarea': new Textarea(formElement); break;
			case 'select': new Dropdown(formElement); break;
		}

		window.FormFocusArrow.bindTo(formElement);
	});

	$$('.redButton').each(function(button) { new RedButton(button) });
	$$('.condense').each(function(elm) { new Condensable(elm) });

	document.fire('afterCommonLoad');
});















