/*!
 * JavaScript Custom Forms v0.5
 * Copyright 2011, Unknown
 */
jcf = {};
jcf.modules = {};
jcf.baseOptions = {
	hiddenClass:'outtaHere',
	replaceAll:true
}

// advanced replacer class
jcf.customForms = function(opt) {
	this.options = jcf.baseOptions;
	jcf.lib.extend(this.options, opt);
}
jcf.customForms.prototype.replace = function(obj, opt) {
	for(var k in jcf.modules) {
		var els = jcf.lib.queryBySelector(jcf.modules[k].prototype.selector);
		for(var i = 0; i<els.length; i++) {
			new jcf.modules[k]({
				replaces:els[i]
			});
		}
	}
}
jcf.setBaseModule = function(obj) {
	jcf.customControl = function(opt){
		this.options = {
			labelActiveClass: 'jcf-label-active',
			focusClass:'jcf-focus',
			foo:'bar'
		}
		jcf.lib.extend(this.options, opt);
		this.init();
	}
	for(var p in obj) {
		jcf.customControl.prototype[p] = obj[p];
	}
}
jcf.addModule = function(obj) {
	if(obj.name){
		// create new module proto class
		jcf.modules[obj.name] = function(){
			jcf.modules[obj.name].superclass.constructor.apply(this, arguments);
		}
		jcf.lib.inherit(jcf.modules[obj.name], jcf.customControl);
		for(var p in obj) {
			jcf.modules[obj.name].prototype[p] = obj[p]
		}

		// on create module
		jcf.modules[obj.name].prototype.onCreateModule();

		// make callback for exciting modules
		for(var mod in jcf.modules) {
			if(jcf.modules[mod] != jcf.modules[obj.name]) {
				jcf.modules[mod].prototype.onModuleAdded(jcf.modules[obj.name]);
			}
		}
	}
}

// custom control base class
jcf.setBaseModule({
	init: function(){
		this.initOptions();
		this.realElement = this.options.replaces;
		if(this.realElement) {
			this.replaceObject();
		}
	},
	initOptions: function(){

	},
	createWrapper: function(){
		this.fakeElement = document.createElement('div');
		this.fakeElement.jcf = this;
		this.realElement.jcf = this;
		this.labelFor = jcf.lib.getLabelFor(this.realElement);
		jcf.lib.disableTextSelection(this.fakeElement);
		jcf.lib.addClass(this.realElement, jcf.baseOptions.hiddenClass);
	},
	initEvents: function(){
		jcf.lib.event.add(this.realElement, 'click', this.onClick);
		jcf.lib.event.add(this.realElement, 'focus', this.onFocus);
		jcf.lib.event.add(this.realElement, 'blur', this.onBlur);
		
		jcf.lib.event.add(this.fakeElement, 'click', this.onFakeClick);
		jcf.lib.event.add(this.fakeElement, 'mousedown', this.onFakeMouseDown);
		jcf.lib.event.add(this.fakeElement, 'mouseup', this.onFakeMouseUp);

		if(this.labelFor) {
			this.labelFor.jcf = this;
			jcf.lib.event.add(this.labelFor, 'click', this.onFakeClick);
			jcf.lib.event.add(this.labelFor, 'mousedown', this.onFakeMouseDown);
			jcf.lib.event.add(this.labelFor, 'mouseup', this.onFakeMouseUp);
		}
	},
	setupWrapper: function(){
		// implement in subclass
	},
	refreshState: function(){
		// implement in subclass
	},
	replaceObject: function(){
		this.createWrapper();
		this.initEvents();
		this.setupWrapper();
	},
	onClick: function(){
		this.jcf.refreshState();
	},
	onFocus: function(){
		clearTimeout(this.jcf.focusTimer);
		this.jcf.fakeElement.mouseDownFlag = false;
		if(!this.jcf.realElement.disabled) {
			jcf.lib.addClass(this.jcf.fakeElement,this.jcf.options.focusClass);
		}
	},
	onBlur: function(){
		var _this = this;
		this.jcf.focusTimer = setTimeout(function(){
			if(!_this.jcf.fakeElement.mouseDownFlag) {
				jcf.lib.removeClass(_this.jcf.fakeElement,_this.jcf.options.focusClass);
			}
		},10);
	},
	onFakeClick: function(){
		this.jcf.realElement.focus();
	},
	onFakeMouseDown: function(){
		this.jcf.fakeElement.mouseDownFlag = true;
		return false;
	},
	onFakeMouseUp: function(){
		this.jcf.fakeElement.mouseDownFlag = false;
	},
	onCreateModule: function(){
		// implement in subclass
	},
	onModuleAdded: function(module) {
		// implement in subclass
	},
	onControlReady: function() {
		// implement in subclass
		try{
			selectready(this.realElement);
		} catch (error){
		}
		//jcf.lib.fireEvent(this.realElement, "dblclick");
	}
});










// custom forms util library
jcf.lib = {
	bind: function(func, scope){
		var _function = func;
		return function() {
			return _function.apply(scope, arguments);
		}
	},
	browser: (function() {
		var rwebkit = /(webkit)[ \/]([\w.]+)/,
		ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
		rmsie = /(msie) ([\w.]+)/,
		rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/;
		var ua = navigator.userAgent.toLowerCase();
		var match = rwebkit.exec( ua ) || ropera.exec( ua ) || rmsie.exec( ua ) || ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || [];
		var res = {};
		res[match[1]] = true;
		res.version = match[2] || "0";
		return res;
	})(),
	getOffset: function(element) {
		var el = element;
		var valueT = 0, valueL = 0;
		if (element.offsetParent) {
			do {
				// hello reflow
				valueT += element.offsetTop  || 0;
				valueL += element.offsetLeft || 0;
				if(element != document.body && element != document.body.parentNode) {
					valueT -= element.scrollTop  || 0;
					valueL -= element.scrollLeft  || 0;
				}
				valueT += parseInt(jcf.lib.getStyle(element,'borderTopWidth')) || 0;
				valueL += parseInt(jcf.lib.getStyle(element,'borderLeftWidth')) || 0;
				element = element.offsetParent;
			} while (element);
		}
		return {top:valueT, left:valueL};
	},
	getStyle: function(el, prop) {
		if (document.defaultView && document.defaultView.getComputedStyle) {
			return document.defaultView.getComputedStyle(el, null)[prop];
		} else if (el.currentStyle) {
			return el.currentStyle[prop];
		} else {
			return el.style[prop];
		}
	},
	getParent: function(obj, selector) {
		while(obj.parentNode && obj.parentNode != document.body) {
			if(obj.parentNode.tagName.toLowerCase() == selector.toLowerCase()) {
				return obj.parentNode;
			}
			obj = obj.parentNode;
		}
		return false;
	},
	isParent: function(child, parent) {
		while(child.parentNode) {
			if(child.parentNode === parent) {
				return true;
			}
			child = child.parentNode;
		}
		return false;
	},
	getLabelFor: function(object) {
		if(jcf.lib.getParent(object,'label')) {
			return object.parentNode;
		} else if(object.id && object.id.length) {
			return jcf.lib.queryBySelector('label[for=' + object.id + ']')[0];
		}
	},
	disableSelection: function() {
		document.onselectstart = function(){return false}
	},
	enableSelection: function() {
		document.onselectstart = null
	},
	disableTextSelection: function(el){
		if(el.setProperty) {
			el.setProperty("unselectable","on");
		}
		el.style.MozUserSelect = 'none';
		el.style.KhtmlUserSelect = 'none';
	},
	queryBySelector: function(selector, scope){
		return document.querySelectorAll ? (scope || document).querySelectorAll(selector) : jcf.lib.getElementsBySelector(selector, scope);
	},
	prevSibling: function(node) {
		while(node = node.previousSibling) if(node.nodeType == 1) break;
		return node;
	},
	nextSibling: function(node) {
		while(node = node.nextSibling) if(node.nodeType == 1) break;
		return node;
	},
	fireEvent: function(element,event) {
		if (document.createEventObject){
			var evt = document.createEventObject();
			return element.fireEvent('on'+event,evt)
		}
		else{
			var evt = document.createEvent('HTMLEvents');
			evt.initEvent(event, true, true );
			return !element.dispatchEvent(evt);
		}
	},
	isParent: function(p, c) {
		while(c.parentNode) {
			if(p == c) {
				return true;
			}
			c = c.parentNode;
		}
		return false;
	},
	inherit: function(Child, Parent) {
		var F = function() { }
		F.prototype = Parent.prototype
		Child.prototype = new F()
		Child.prototype.constructor = Child
		Child.superclass = Parent.prototype
	},
	extend: function(obj1,obj2) {
		for(var prop in obj2) {
			obj1[prop] = obj2[prop];
		}
	},
	hasClass: function (obj,cname) {
		return (obj.className ? obj.className.match(new RegExp('(\\s|^)'+cname+'(\\s|$)')) : false);
	},
	addClass: function (obj,cname) {
		if (!this.hasClass(obj,cname)) obj.className += " "+cname;
	},
	removeClass: function (obj,cname) {
		if (this.hasClass(obj,cname)) obj.className=obj.className.replace(new RegExp('(\\s|^)'+cname+'(\\s|$)'),' ');
	},
	getAllClasses: function(cname, prefix, skip) {
		if(!skip) skip = '';
		if(!prefix) prefix = '';
		return cname ? cname.replace(new RegExp('(\\s|^)'+skip+'(\\s|$)'),' ').replace(/[\s]*([\S]+)+[\s]*/gi,prefix+"$1 ") : '';
	},
	getElementsBySelector: function(selector, scope) {
		// Attempt to fail gracefully in lesser browsers
		if (!document.getElementsByTagName) {
			return new Array();
		}
		// Split selector in to tokens
		var tokens = selector.split(' ');
		var currentContext = new Array(scope || document.body);
		for (var i = 0; i < tokens.length; i++) {
			token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');
			if (token.indexOf('#') > -1) {
				// Token is an ID selector
				var bits = token.split('#');
				var tagName = bits[0];
				var id = bits[1];
				var element = document.getElementById(id);
				if (tagName && element.nodeName.toLowerCase() != tagName) {
					// tag with that ID not found, return false
					return new Array();
				}
				// Set currentContext to contain just this element
				currentContext = new Array(element);
				continue; // Skip to next token
			}
			if (token.indexOf('.') > -1) {
				// Token contains a class selector
				var bits = token.split('.');
				var tagName = bits[0];
				var className = bits[1];
				if (!tagName) {
					tagName = '*';
				}
				// Get elements matching tag, filter them for class selector
				var found = new Array;
				var foundCount = 0;
				for (var h = 0; h < currentContext.length; h++) {
					var elements;
					if (tagName == '*') {
						elements = currentContext[h].getElementsByTagName('*');
					} else {
						elements = currentContext[h].getElementsByTagName(tagName);
					}
					for (var j = 0; j < elements.length; j++) {
						found[foundCount++] = elements[j];
					}
				}
				currentContext = new Array;
				var currentContextIndex = 0;
				for (var k = 0; k < found.length; k++) {
					if (found[k].className && found[k].className.match(new RegExp('(\\s|^)'+className+'(\\s|$)'))) {
						currentContext[currentContextIndex++] = found[k];
					}
				}
				continue; // Skip to next token
			}
			// Code to deal with attribute selectors
			if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
				var tagName = RegExp.$1;
				var attrName = RegExp.$2;
				var attrOperator = RegExp.$3;
				var attrValue = RegExp.$4;
				if (!tagName) {
					tagName = '*';
				}
				// Grab all of the tagName elements within current context
				var found = new Array;
				var foundCount = 0;
				for (var h = 0; h < currentContext.length; h++) {
					var elements;
					if (tagName == '*') {
						elements = currentContext[h].getElementsByTagName('*');
					} else {
						elements = currentContext[h].getElementsByTagName(tagName);
					}
					for (var j = 0; j < elements.length; j++) {
						found[foundCount++] = elements[j];
					}
				}
				currentContext = new Array;
				var currentContextIndex = 0;
				var checkFunction; // This function will be used to filter the elements
				if(attrName.toLowerCase() == 'for' && jcf.lib.browser.msie && jcf.lib.browser.version < 8) {
					attrName = 'htmlFor';
				}
				switch (attrOperator) {
					case '=': // Equality
						checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
						break;
					case '~': // Match one of space seperated words
						checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('(\\s|^)'+attrValue+'(\\s|$)'))); };
						break;
					case '|': // Match start with value followed by optional hyphen
						checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
						break;
					case '^': // Match starts with value
						checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); };
						break;
					case '$': // Match ends with value
						checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
						break;
					case '*': // Match ends with value
						checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); };
						break;
					default :
						// Just test for existence of attribute
						checkFunction = function(e) { return e.getAttribute(attrName); };
				}
				currentContext = new Array;
				var currentContextIndex = 0;
				for (var k = 0; k < found.length; k++) {
					if (checkFunction(found[k])) {
						currentContext[currentContextIndex++] = found[k];
					}
				}
				continue; // Skip to next token
			}
			// If we get here, token is JUST an element (not a class or ID selector)
			tagName = token;
			var found = new Array;
			var foundCount = 0;
			for (var h = 0; h < currentContext.length; h++) {
				var elements = currentContext[h].getElementsByTagName(tagName);
				for (var j = 0; j < elements.length; j++) {
					found[foundCount++] = elements[j];
				}
			}
			currentContext = found;
		}
		return currentContext;
	},
	domReady: function (handler){
		var called = false
		function ready() {
			if (called) return;
			called = true;
			handler();
		}
		if (document.addEventListener) {
			document.addEventListener( "DOMContentLoaded", ready, false )
		} else if (document.attachEvent) {
			if (document.documentElement.doScroll && window == window.top) {
				function tryScroll(){
					if (called) return
					if (!document.body) return
					try {
						document.documentElement.doScroll("left")
						ready()
					} catch(e) {
						setTimeout(tryScroll, 0)
					}
				}
				tryScroll()
			}
			document.attachEvent("onreadystatechange", function(){
				if ( document.readyState === "complete" ) {
					ready()
				}
			})
		}
		if (window.addEventListener) window.addEventListener('load', ready, false)
		else if (window.attachEvent) window.attachEvent('onload', ready)
	},
	event: (function(){
		var guid = 0;
		function fixEvent(event) {
			event = event || window.event;
			if ( event.isFixed ) {
				return event;
			}
			event.isFixed = true;
			event.preventDefault = event.preventDefault || function(){this.returnValue = false}
			event.stopPropagation = event.stopPropagaton || function(){this.cancelBubble = true}
			if(!event.target) {
				event.target = event.srcElement;
			}
			if(!event.relatedTarget && event.fromElement) {
				event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
			}
			if(event.pageX == null && event.clientX != null ) {
				var html = document.documentElement, body = document.body;
				event.pageX = event.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html.clientLeft || 0);
				event.pageY = event.clientY + (html && html.scrollTop || body && body.scrollTop || 0) - (html.clientTop || 0);
			}
			if(typeof event.layerX == 'undefined') {
				event.layerX = event.offsetX;
				event.layerY = event.offsetY;
			}
			if(!event.which && event.button ) {
				event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
			}
			return event;
		}

		function commonHandle(event) {
			event = fixEvent(event);
			if(!this.events) return;
			var handlers = this.events[event.type]
			for(var g in handlers ) {
				var handler = handlers[g]
				var ret = handler.call(this, event)
				if ( ret === false ) {
					event.preventDefault()
					event.stopPropagation()
				}
			}
		}

		return {
			add: function(elem, type, handler) {
				if (elem.setInterval && (elem != window && !elem.frameElement)) {
					elem = window;
				}
				if (!handler.guid) {
					handler.guid = ++guid;
				}
				if (!elem.events) {
					elem.events = {}
					elem.handle = function(event) {
						if (typeof jcf.lib.event !== "undefined") {
							return commonHandle.call(elem, event)
						}
					}
				}

				if (!elem.events[type]) {
					elem.events[type] = {}
					if (elem.addEventListener) {
						elem.addEventListener(type, elem.handle, true);
					} else {
						if (elem.attachEvent) elem.attachEvent('on' + type, elem.handle);
					}
				}
				elem.events[type][handler.guid] = handler
			},

			remove: function(elem, type, handler) {
				var handlers = elem.events && elem.events[type];
				if (!handlers) return;
				delete handlers[handler.guid];
				for(var any in handlers) return;
				if (elem.removeEventListener) elem.removeEventListener(type, elem.handle, false)
				else if (elem.detachEvent) elem.detachEvent("on" + type, elem.handle)
				delete elem.events[type]

				for (var any in elem.events) return;
				try {
					delete elem.handle
					delete elem.events
				} catch(e) { // IE
					try {
						elem.removeAttribute("handle")
						elem.removeAttribute("events")
					} catch(e) {}
				}
			}
		}
	}())
}

// custom checkbox module
jcf.addModule({
	name:'checkbox',
	selector:'input[type=checkbox]',
	initOptions: function(){
		jcf.lib.extend(this.options,{
			wrapperClass:'checkboxArea',
			focusClass:'checkboxAreaFocus',
			checkedClass:'checkboxAreaChecked',
			labelActiveClass:'chk-label-active',
			uncheckedClass:'chk-unchecked',
			disabledClass:'chk-disabled',
			chkStructure:'<span></span>'
		});
	},
	setupWrapper: function(){
		jcf.lib.addClass(this.fakeElement, this.options.wrapperClass);
		this.fakeElement.innerHTML = this.options.chkStructure;
		this.realElement.parentNode.insertBefore(this.fakeElement, this.realElement);
		this.refreshState();
		this.addEvents();
	},
	addEvents: function(){
		jcf.lib.event.add(this.fakeElement, 'click', this.toggle);
		if(jcf.lib.browser.msie && jcf.lib.browser.version < 7 && this.labelFor && !this.labelFor.getAttribute('htmlFor')) {
			jcf.lib.event.add(this.labelFor, 'mousedown', this.onLabelMouseDown);
		}
	},
	onFakeMouseDown: function(e){
		jcf.modules[this.jcf.name].superclass.onFakeMouseDown.apply(this, arguments);

		// IE image inside label fix
		if(jcf.lib.browser.msie && e.target && e.target.tagName.toLowerCase() == 'img') {
			if(jcf.lib.browser.version < 7) {
				if(this.jcf.labelFor && this.jcf.labelFor.getAttribute('htmlFor')) {
					this.jcf.toggle.apply(this);
				}
			} else {
				this.jcf.toggle.apply(this);
			}
		}
		return false;
	},
	onLabelMouseDown: function(e){
		jcf.modules[this.jcf.name].superclass.onFakeMouseDown.apply(this, arguments);
		this.jcf.toggle.apply(this);
	},
	toggle: function(e){
		if(!this.jcf.realElement.disabled) {
			if(this.jcf.realElement.checked) {
				this.jcf.realElement.checked = false;
			} else {
				this.jcf.realElement.checked = true;
			}
		}
		if(jcf.lib.browser.opera) {
			this.jcf.realElement.checked = !this.jcf.realElement.checked;
		}
		jcf.lib.fireEvent(this.jcf.realElement, 'click');
		jcf.lib.fireEvent(this.jcf.realElement, 'change');
		this.jcf.refreshState();
		return false;
	},
	refreshState: function(){
		if(this.realElement.checked) {
			jcf.lib.addClass(this.fakeElement, this.options.checkedClass);
			jcf.lib.removeClass(this.fakeElement, this.options.uncheckedClass);
			if(this.labelFor) {
				jcf.lib.addClass(this.labelFor, this.options.labelActiveClass);
			}
		} else {
			jcf.lib.removeClass(this.fakeElement, this.options.checkedClass);
			jcf.lib.addClass(this.fakeElement, this.options.uncheckedClass);
			if(this.labelFor) {
				jcf.lib.removeClass(this.labelFor, this.options.labelActiveClass);
			}
		}
		if(this.realElement.disabled) {
			jcf.lib.addClass(this.fakeElement, this.options.disabledClass);
		} else {
			jcf.lib.removeClass(this.fakeElement, this.options.disabledClass);
		}
	}
});

// custom upload field module
jcf.addModule({
	name: 'file',
	selector: 'input[type=file]',
	initOptions: function(){
		jcf.lib.extend(this.options,{
			buttonWidth: 30,
			buttonText:'Browse...',
			wrapperClass:'file-area',
			focusClass:'file-focus',
			disabledClass:'file-disabled',
			opacityClass:'file-input-opacity',
			noFileClass:'no-file',
			extPrefixClass:'extension-',
			uploadStructure:'<div class="jcf-input-wrapper"><div class="jcf-wrap"></div><label class="jcf-fake-input"><span><em></em></span></label><a class="jcf-upload-button"><span></span></a></div>',
			uploadFileNameSelector:'label.jcf-fake-input span em',
			uploadButtonSelector:'a.jcf-upload-button span',
			inputWrapper: 'div.jcf-wrap'
		});
	},
	setupWrapper: function(){
		jcf.lib.addClass(this.fakeElement, this.options.wrapperClass);
		this.fakeElement.innerHTML = this.options.uploadStructure;
		this.realElement.parentNode.insertBefore(this.fakeElement, this.realElement);
		this.fileNameInput = jcf.lib.queryBySelector(this.options.uploadFileNameSelector ,this.fakeElement)[0];
		this.uploadButton = jcf.lib.queryBySelector(this.options.uploadButtonSelector ,this.fakeElement)[0];
		this.inputWrapper = jcf.lib.queryBySelector(this.options.inputWrapper ,this.fakeElement)[0];

		this.uploadButton.innerHTML = this.realElement.title || this.options.buttonText;
		this.realElement.removeAttribute('title');
		this.fakeElement.style.position = 'relative';
		this.realElement.style.position = 'absolute';
		this.realElement.style.zIndex = 100;
		this.inputWrapper.appendChild(this.realElement);

		this.oTop = 0;
		this.oLeft = 0;
		this.oWidth = 0;
		this.oHeight = 0;

		this.refreshState();
		this.addEvents();
		jcf.lib.addClass(this.realElement, this.options.opacityClass);
		jcf.lib.removeClass(this.realElement, jcf.baseOptions.hiddenClass);
		this.inputWrapper.style.width = this.inputWrapper.parentNode.offsetWidth+'px';
	},
	addEvents: function(){
		jcf.lib.event.add(this.realElement, 'change', this.onChange);
		jcf.lib.event.add(this.fakeElement, 'mousemove', this.onMouseMove);
		jcf.lib.event.add(this.fakeElement, 'mouseover', this.onMouseEnter);
	},
	onMouseEnter: function(e){
		var o = jcf.lib.getOffset(this.jcf.fakeElement);
		this.jcf.oTop = o.top;
		this.jcf.oLeft = o.left;
		this.jcf.oWidth = this.jcf.realElement.offsetWidth;
		this.jcf.oHeight = this.jcf.realElement.offsetHeight;
	},
	onMouseMove: function(e){
		this.jcf.realElement.style.top = Math.round(e.pageY - this.jcf.oTop - this.jcf.oHeight/2) + 'px';
		this.jcf.realElement.style.left = (e.pageX - this.jcf.oLeft - this.jcf.oWidth + this.jcf.options.buttonWidth) + 'px';
	},
	onChange: function(){
		this.jcf.refreshState();
	},
	getFileName: function(){
		return this.realElement.value.replace(/^[\s\S]*(?:\\|\/)([\s\S^\\\/]*)$/g, "$1");
	},
	getFileExtension: function(){
		return this.realElement.value.lastIndexOf('.') < 0 ? false : this.realElement.value.substring(this.realElement.value.lastIndexOf('.')+1).toLowerCase();
	},
	updateExtensionClass: function(){
		var currentExtension = this.getFileExtension();
		if(currentExtension) {
			this.fakeElement.className = this.fakeElement.className.replace(new RegExp('(\\s|^)'+this.options.extPrefixClass+'[^ ]+','gi'),'')
			jcf.lib.addClass(this.fakeElement, this.options.extPrefixClass+currentExtension)
		}
	},
	refreshState: function(){
		this.realElement.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)';
		this.realElement.style.opacity = 0;
		this.fileNameInput.innerHTML = this.getFileName();
		if(this.realElement.disabled) {
			jcf.lib.addClass(this.fakeElement, this.options.disabledClass);
		} else {
			jcf.lib.removeClass(this.fakeElement, this.options.disabledClass);
		}

		if(this.realElement.value.length) {
			jcf.lib.removeClass(this.fakeElement, this.options.noFileClass);
		} else {
			jcf.lib.addClass(this.fakeElement, this.options.noFileClass);
		}
		this.updateExtensionClass();
	}
});

// custom radio module
jcf.addModule({
	name:'radio',
	selector: 'input[type=radio]',
	initOptions: function(){
		jcf.lib.extend(this.options,{
			wrapperClass:'radioArea',
			focusClass:'radioAreaFocus',
			checkedClass:'radioAreaChecked',
			uncheckedClass:'radioAreaUnchecked',
			disabledClass:'radioAreaDisabled',
			radStructure:'<span></span>'
		});
	},
	getRadioGroup: function(item){
		var name = item.getAttribute('name');
		if(name) {
			return jcf.lib.queryBySelector('input[name='+name+']', jcf.lib.getParent('form'));
		} else {
			return [item];
		}
	},
	setupWrapper: function(){
		jcf.lib.addClass(this.fakeElement, this.options.wrapperClass);
		this.fakeElement.innerHTML = this.options.radStructure;
		this.realElement.parentNode.insertBefore(this.fakeElement, this.realElement);
		this.refreshState();
		this.addEvents();
	},
	addEvents: function(){
		jcf.lib.event.add(this.fakeElement, 'click', this.toggleRadio);
		if(this.labelFor) {
			jcf.lib.event.add(this.labelFor, 'click', this.toggleRadio);
		}
	},
	toggleRadio: function(){
		if(!this.jcf.realElement.disabled) {
			this.jcf.realElement.checked = true;
		}
		this.jcf.refreshState();
	},
	refreshState: function(){
		var els = this.getRadioGroup(this.realElement);
		for(var i = 0; i < els.length; i++) {
			var curEl = els[i].jcf;
			if(curEl) {
				if(curEl.realElement.checked) {
					jcf.lib.addClass(curEl.fakeElement, curEl.options.checkedClass);
					jcf.lib.removeClass(curEl.fakeElement, curEl.options.uncheckedClass);
					if(curEl.labelFor) {
						jcf.lib.addClass(curEl.labelFor, curEl.options.labelActiveClass);
					}
				} else {
					jcf.lib.removeClass(curEl.fakeElement, curEl.options.checkedClass);
					jcf.lib.addClass(curEl.fakeElement, curEl.options.uncheckedClass);
					if(curEl.labelFor) {
						jcf.lib.removeClass(curEl.labelFor, curEl.options.labelActiveClass);
					}
				}
				if(curEl.realElement.disabled) {
					jcf.lib.addClass(curEl.fakeElement, curEl.options.disabledClass);
				} else {
					jcf.lib.removeClass(curEl.fakeElement, curEl.options.disabledClass);
				}
			}
		}
	}
});

// custom select module
jcf.addModule({
	name:'select',
	selector:'select',
	initOptions: function(){
		jcf.lib.extend(this.options,{
			wrapperClass:'selectArea',
			focusClass:'selectAreaFocus',
			selectedClass:'item-selected',
			disabledClass:'selectAreaDisabled',
			valueSelector:'span.center',
			optGroupClass:'optgroup',
			openerSelector:'a.selectButton',
			selectStructure:'<span class="left"></span><span class="center"></span><a class="selectButton"></a>',
			selectPrefixClass:'select-',
			dropMaxHeight: 200,
			dropHiddenClass:'optionsDivInvisible',
			dropScrollableClass:'options-overflow',
			dropClass:'optionsDivVisible',
			dropClassPrefix:'drop-',
			dropStructure:'<div class="drop-holder"><div class="drop-list"></div></div>',
			dropSelector:'div.drop-list'
		});
	},
	setupWrapper: function(){
		jcf.lib.addClass(this.fakeElement, this.options.wrapperClass);
		this.realElement.parentNode.insertBefore(this.fakeElement, this.realElement);
		this.fakeElement.innerHTML = this.options.selectStructure;
		this.fakeElement.style.width = this.realElement.offsetWidth + 'px';
		jcf.lib.addClass(this.fakeElement, jcf.lib.getAllClasses(this.realElement.className, this.options.selectPrefixClass, jcf.baseOptions.hiddenClass));

		// create select body
		this.opener = jcf.lib.queryBySelector(this.options.openerSelector, this.fakeElement)[0];
		this.valueText = jcf.lib.queryBySelector(this.options.valueSelector, this.fakeElement)[0];
		this.opener.jcf = this;

		this.createDropdown();
		this.refreshState();
		this.addEvents();
		this.onControlReady(this);
	},
	addEvents: function(){
		jcf.lib.event.add(this.fakeElement, 'click', this.toggleDropdown);
		jcf.lib.event.add(this.realElement, 'change', this.onChange);
		
	},
	onFocus: function(){
		jcf.modules[this.jcf.name].superclass.onFocus.apply(this, arguments);
		jcf.lib.event.add(this.jcf.realElement, 'keydown', this.jcf.onKeyDown);
		if(jcf.activeControl && jcf.activeControl != this.jcf) {
			jcf.activeControl.hideDropdown();
		}
	},
	onBlur: function(){
		if(!this.jcf.isActiveDrop() || !this.jcf.isOverDrop()) {
			jcf.modules[this.jcf.name].superclass.onBlur.apply(this, arguments);
		}
		jcf.lib.event.remove(this.jcf.realElement, 'keydown', this.jcf.onKeyDown);
	},
	onChange: function() {
		this.jcf.refreshState();
	},
	onKeyDown: function(e){
		var context = this;
		setTimeout(function(){
			context.jcf.refreshState();
		},10);
		if(e.keyCode == 13) {
			context.jcf.toggleDropdown.apply(context);
			return false;
		}
	},
	onResizeWindow: function(e){
		if(jcf.activeControl) {
			jcf.activeControl.hideDropdown();
		}
	},
	onScrollWindow: function(e){
		if(jcf.activeControl) {
			jcf.activeControl.positionDropdown();
		}
	},
	onOptionClick: function(e){
		var opener = e.target && e.target.tagName && e.target.tagName.toLowerCase() == 'li' ? e.target : jcf.lib.getParent(e.target, 'li');
		if(opener) {
			this.jcf.realElement.selectedIndex = parseInt(opener.getAttribute('rel'));
			this.jcf.realElement.focus();
			this.jcf.refreshState();
			this.jcf.hideDropdown();
			jcf.lib.fireEvent(this.jcf.realElement, 'change');
		}
		return false;
	},
	onClickOutside: function(e){
		if(jcf.activeControl && !jcf.lib.isParent(jcf.activeControl, e.target) && !jcf.lib.isParent(jcf.activeControl.fakeElement, e.target)) {
			jcf.activeControl.hideDropdown();
		}
	},
	onDropHover: function(e){
		if(jcf.activeControl) {
			jcf.activeControl.hoverFlag = true;
			var opener = e.target && e.target.tagName && e.target.tagName.toLowerCase() == 'li' ? e.target : jcf.lib.getParent(e.target, 'li');
			if(opener) {
				jcf.activeControl.realElement.selectedIndex = parseInt(opener.getAttribute('rel'));
				jcf.activeControl.refreshSelectedClass(parseInt(opener.getAttribute('rel')));
			}
		}
	},
	onDropLeave: function(){
		if(jcf.activeControl) {
			jcf.activeControl.hoverFlag = false;
		}
	},
	isActiveDrop: function(){
		return !jcf.lib.hasClass(this.selectDrop, this.options.dropHiddenClass);
	},
	isOverDrop: function(){
		return this.hoverFlag;
	},
	createDropdown: function(){
		// remove old dropdown if exists
		if(this.selectDrop) {
			this.selectDrop.parentNode.removeChild(this.selectDrop);
		}

		// create dropdown holder
		this.selectDrop = document.createElement('div');
		this.selectDrop.className = this.options.dropClass;
		this.selectDrop.innerHTML = this.options.dropStructure;
		this.selectList = jcf.lib.queryBySelector(this.options.dropSelector,this.selectDrop)[0];
		jcf.lib.addClass(this.selectDrop, this.options.dropHiddenClass);
		document.body.appendChild(this.selectDrop);
		this.selectDrop.jcf = this;
		jcf.lib.event.add(this.selectDrop, 'click', this.onOptionClick);
		jcf.lib.event.add(this.selectDrop, 'mouseover', this.onDropHover);
		jcf.lib.event.add(this.selectDrop, 'mouseout', this.onDropLeave);
		this.buildDropdown();
	},
	buildDropdown: function() {
		// build select options / optgroups
		this.buildDropdownOptions();

		// position and resize dropdown
		this.positionDropdown();

		// cut dropdown if height exceedes
		this.buildDropdownScroll();
	},
	buildDropdownOptions: function() {
		this.resStructure = '';
		this.optNum = 0;
		for(var i = 0; i < this.realElement.children.length; i++) {
			this.resStructure += this.buildElement(this.realElement.children[i]) +'\n';
		}
		this.selectList.innerHTML = this.resStructure;
	},
	buildDropdownScroll: function() {
		if(this.options.dropMaxHeight) {
			if(this.selectDrop.offsetHeight > this.options.dropMaxHeight) {
				this.selectList.style.height = this.options.dropMaxHeight+'px';
				this.selectList.style.overflow = 'auto';
				this.selectList.style.overflowX = 'hidden';
				jcf.lib.addClass(this.selectDrop, this.options.dropScrollableClass);
			}
		}
		jcf.lib.addClass(this.selectDrop, jcf.lib.getAllClasses(this.realElement.className, this.options.dropClassPrefix, jcf.baseOptions.hiddenClass));
	},
	buildElement: function(obj){
		// build option
		var res = '';
		if(obj.tagName.toLowerCase() == 'option') {
			if(!jcf.lib.prevSibling(obj) || jcf.lib.prevSibling(obj).tagName.toLowerCase() != 'option') {
				res += '<ul>';
			}
			res += '<li rel="'+(this.optNum++)+'" class="'+(obj.className? obj.className : '')+' jcfcalc"><a href="#">'+(obj.title? '<img src="'+obj.title+'" alt="" />' : '')+'<span>' + obj.innerHTML + '</span></a></li>';
			if(!jcf.lib.nextSibling(obj) || jcf.lib.nextSibling(obj).tagName.toLowerCase() != 'option') {
				res += '</ul>';
			}
			return res;
		}
		// build option group with options
		else if(obj.tagName.toLowerCase() == 'optgroup' && obj.label) {
			res += '<div class="'+this.options.optGroupClass+'">';
			res += '<strong class="jcfcalc"><em>'+(obj.label)+'</em></strong>';
			for(var i = 0; i < obj.children.length; i++) {
				res += this.buildElement(obj.children[i]);
			}
			res += '</div>';
			return res;
		}
	},
	positionDropdown: function(){
		var ofs = jcf.lib.getOffset(this.fakeElement);
		this.selectDrop.style.top = (ofs.top+this.fakeElement.offsetHeight)+'px';
		this.selectDrop.style.left = ofs.left+'px';
		this.selectDrop.style.width = this.fakeElement.offsetWidth+'px';
	},
	showDropdown: function(){
		jcf.lib.removeClass(this.selectDrop, this.options.dropHiddenClass);
		this.positionDropdown();

		// hide active dropdown
		if(jcf.activeControl) {
			jcf.activeControl.hideDropdown();
		}

		// show current dropdown
		jcf.activeControl = this;
		jcf.lib.event.add(window, 'resize', this.onResizeWindow);
		jcf.lib.event.add(window, 'scroll', this.onScrollWindow);
		jcf.lib.event.add(document.body, 'click', this.onClickOutside);
		this.positionDropdown();
	},
	hideDropdown: function(){
		if(jcf.activeControl && typeof jcf.activeControl.origSelectedIndex === 'number') {
			jcf.activeControl.realElement.selectedIndex = jcf.activeControl.origSelectedIndex;
		}
		jcf.lib.addClass(this.selectDrop, this.options.dropHiddenClass);
		jcf.activeControl = null;
		jcf.lib.event.remove(window, 'resize', this.onResizeWindow);
		jcf.lib.event.remove(window, 'scroll', this.onScrollWindow);
		jcf.lib.event.remove(document.body, 'click', this.onClickOutside);
	},
	toggleDropdown: function(){
		this.jcf.dropOpened = true;
		if(!this.jcf.realElement.disabled) {
			if(this.jcf.isActiveDrop()) {
				this.jcf.hideDropdown();
			} else {
				this.jcf.showDropdown();
			}
		}
		this.jcf.refreshState();
	},
	scrollToItem: function(){
		if(this.isActiveDrop()) {
			var dropHeight = this.selectList.offsetHeight;
			var offsetTop = this.calcOptionOffset(this.getFakeActiveOption());
			var sTop = this.selectList.scrollTop;
			var oHeight = this.getFakeActiveOption().offsetHeight;
			//offsetTop+=sTop;

			if(offsetTop >= sTop + dropHeight) {
				this.selectList.scrollTop = offsetTop - dropHeight + oHeight;
			} else if(offsetTop < sTop) {
				this.selectList.scrollTop = offsetTop;
			}
		}
	},
	getFakeActiveOption: function(c) {
		return jcf.lib.queryBySelector('li[rel="'+(typeof c === 'number' ? c : this.realElement.selectedIndex) +'"]',this.selectList)[0];
	},
	calcOptionOffset: function(fake) {
		var h = 0;
		var els = jcf.lib.queryBySelector('.jcfcalc',this.selectList);
		for(var i = 0; i < els.length; i++) {
			if(els[i] == fake) break;
			h+=els[i].offsetHeight;
		}
		return h;
	},
	childrenHasItem: function(hold,item) {
		var items = hold.getElementsByTagName('*');
		for(i = 0; i < items.length; i++) {
			if(items[i] == item) return true;
		}
		return false;
	},
	removeSelectedClass: function(){
		var children = jcf.lib.queryBySelector('li',this.selectList);
		for(var i = children.length - 1; i >= 0; i--) {
			jcf.lib.removeClass(children[i], this.options.selectedClass);
		}
	},
	setSelectedClass: function(c){
		jcf.lib.addClass(this.getFakeActiveOption(c), this.options.selectedClass);
	},
	refreshSelectedClass: function(c){
		this.removeSelectedClass(c);
		this.setSelectedClass(c);
		if(this.realElement.disabled) {
			jcf.lib.addClass(this.fakeElement, this.options.disabledClass);
		} else {
			jcf.lib.removeClass(this.fakeElement, this.options.disabledClass);
		}
	},
	refreshSelectedText: function() {
		if(!this.dropOpened && this.realElement.title) {
			this.valueText.innerHTML = this.realElement.title;
		} else {
			if(this.realElement.options[this.realElement.selectedIndex].title) {
				this.valueText.innerHTML = '<img src="'+this.realElement.options[this.realElement.selectedIndex].title+'" alt="" />' + this.realElement.options[this.realElement.selectedIndex].innerHTML;
			} else {
				this.valueText.innerHTML = this.realElement.options[this.realElement.selectedIndex].innerHTML;
			}
		}
	},
	refreshState: function(){
		if(jcf.activeControl) {
			jcf.activeControl.origSelectedIndex = jcf.activeControl.realElement.selectedIndex;
		}
		this.refreshSelectedClass();
		this.refreshSelectedText();
		this.scrollToItem();
	}
});

jcf.lib.domReady(function(){
	var cfManager = new jcf.customForms();
	
	cfManager.replace();
	
	
});
