// This is for form validation
var rule = {};
	rule["word"] 	=	/^\w+/i;
	rule["alphabetical"] 	=	/^[a-z]+$/i;
	rule["alphabet"] 	=	rule["alphabetical"];
	rule["alpha"] 	=	rule["alphabetical"];
	rule["numeric"] =	/^\d+$/;
	rule["number"] =	rule["numeric"];	
	rule["num"] =	rule["numeric"];		
	rule["alpha_numeric"] = /^[a-z\d]+$/i;
	rule["alphanumeric"] = rule["alpha_numeric"];
	rule["alphanum"] = rule["alpha_numeric"];
	rule["currency"] = /^(\$|\-|\$\-)?\d{1,3}([,]?\d{3})*(\.\d{2})?$/;
	rule["date_standard"] = /^([1-9]|0[1-9]|[1-2]\d|3[0-1])(\/|\.|-)([1-9]|0[1-9]|1[0-2])\2\d{4}$/;
	rule["time_civilian"] = /^([1-9]|0[1-9]|1[0-2]):[0-5]\d[\s]?(am|pm)$/i;
	rule["time_militart"] = /^([0-1]\d|2[0-3]):[0-5]\d$/;
	rule["phone"] = /^[\(]?\d{3}[\)]?[\s|\.|-]?\d{3}[\s|\.|-]?\d{4}$/;
	rule["phone_international"] = /^\d{1,3}[\s|\.|-]\d{7,20}$/;
	rule["postal_code"] = /^([a-z]\d[a-z])[\s|-]?(\d[a-z]\d)$/i;
	rule["zip_code"] = /^\d{5}(-\d{4})?$/;
	rule["email"] = /^([a-z0-9_-]+)(\.[a-z0-9_-]+)*@([a-z0-9_-]+)(\.[a-z0-9_-]+)*[\.]([a-z0-9_-]+)$/i;
	rule["username"] = /^[a-z0-9_-]+$/i;
	rule["http"] = /^((http|https|ftp):\/\/)?([a-z0-9_-]+)(\.[a-z0-9_-]+)+(\/\w+)*(\.[a-z0-9_-]+)*$/i;
	//rule["ip_address"] = /^(\d{1,3})(\.\d{1,3}){3}$/;

var exit = {};

// When the page loads up
window.addEvent('domready', load_all);

// This is where we load stuff
function load_all(){
		
	// Loop through the required forms to add a form listener for ajax submission
	$$("form.required").each(function(el){

		form_check(el);

	// if
	});
	
	// This is the imask for form field
	 new iMask({  
		 onFocus: function(obj) {  
			 obj.setStyles({"background-color":"ff8", border:"1px solid 880"});  
		 },  
	   
		 onBlur: function(obj) {  
			 obj.setStyles({"background-color":"fff", border:"1px solid ccc"});  
		 },  
	   
		 onValid: function(event, obj) {  
			 obj.setStyles({"background-color":"fff", border:"1px solid 080"});  
		 },  
	   
		 onInvalid: function(event, obj) {  
			 if(!event.shift) {  
				 obj.setStyles({"background-color":"f88", border:"1px solid 800"});  
			 }  
		 }  
	 });  

// function
}
//--------------------------------------------------------------------//

// This check to see if the form is uploader or not
function form_check(el){
	
		// check if this is an image uploader or not
		if( el.get('enctype') == null || el.get('enctype') == "application/x-www-form-urlencoded" ){

			// Bind it with the form handler
			el.addEvent('submit', ajax_form_submit.bindWithEvent( el )	);

		// if
		} else {

			file_form_submit( el );

		// if
		}

// function
}
//--------------------------------------------------------------------//

// This is the ajax form handler
function file_form_submit(el) {
	
			// Create a variable to hold everthing
			vars = {};
			opts = {};

			// Get the form variables
			el.getElements('input,select,textarea').each( function(f) {
												   
												  // Check if we're working on 
												  if( f.getProperty('type') == "hidden" && f.getProperty('name') == el.id + '_directory' ){
													
													vars["directory"] = f.value;
													opts["directory"] = f.value.toString();
													  
												  // Check if we're working on 
												  } else if( f.getProperty('type') == "hidden" && f.getProperty('name') == 'sole_form_handler' ){
													
													vars["handler"] = f.value;
													opts['sole_form_handler'] = f.value.toString();
													  
												  // Check if we're working on 
												  } else if( f.getProperty('type') == "hidden" && f.getProperty('name') == el.id + '_extensions' ){
													
													vars["extensions"] = f.value;
													opts['extensions'] = f.value.toString();
													  
									  			  // Check if we're working on 
												  } else if( f.getProperty('type') == "hidden" && f.getProperty('name') == el.id + '_description' ){
													
													vars["description"] = f.value;
												  
									  			  // Check if we're working on 
												  } else if( f.getProperty('type') == "hidden" && f.getProperty('name') == el.id + '_number' ){
													
													vars["number"] = f.value;
													
													if( vars["number"].toInt() > 1 ){
														
														vars["multiple"] = true;
														
													} else {
														
														vars["multiple"] = false;
														
													// if
													}
													  
									  			  // Check if we're working on 
												  } else if( f.getProperty('type') == "hidden" && f.getProperty('name') == el.id + '_limit' ){
													
													vars["limit"] = f.value;
													  
												  // if
												  } else if( f.getProperty('type') != "button" && f.getProperty('type') != "submit" ) {
													  
													  if( f.getProperty('name') && f.getProperty('name').toString().search(/\[/) == -1 ){
													  
														  try{
														   
															  opts[ f.getProperty('name')  ] = f.value.toString();
																																				  
														  } catch( er ){
															  
															  }
														  
													  // if
													  }

												  //  if
												  }

											  });
			
			
			// Create the elements
			/*
			var wrp1 = new Element('div',{id:'upload-status',class:'hide'}).injectBefore( el );
				
			var wrp2 = new Element('div').inject( wrp1 );
			var stg1 = new Element('strong',{class:'overall-title'}).set('html','Total Progress').inject( wrp2 );
			var br1 = new Element('br').inject( wrp2 );
			var img1 = new Element('img',{class:'progress fu-progress','src':'/images/bar.gif'}).inject( wrp2 );
				
			var wrp3 = new Element('div').inject( wrp1 );
			var stg2 = new Element('strong',{class:'overall-title'}).set('html','File Progress').inject( wrp3 );
			var br2 = new Element('br').inject( wrp3 );
			var img2 = new Element('img',{class:'progress current-progress','src':'/images/bar.gif'}).inject( wrp3 );
				
			var wrp4 = new Element('div',{class:'current-text'}).inject( wrp1 );
			var wrp5 = new Element('ul',{id:'upload-list'}).injectAfter( wrp1 );
				
			alert( $('upload-status') );
			*/
				
			// Create the uploader
			var swiffy = new FancyUpload2($('upload-status'), $('upload-list'), {
				'multiple': vars["multiple"],
				'id': el.id,
				'url': sole.url + "?" + sole.querystring + sole.upload,
				'data': opts,
				'fieldName': 'file',
				'path': sole.assets.swf + 'Swiff.Uploader.swf',
				'onLoad': function() {
					// $('upload-list').setStyle('display','block');
				}
			});
			
			// Assign handlers and stuff
			el.getElements('input,select,textarea').each( function(f) {						  
											  
									  			  // Check if we're working on 
												  if( f.getProperty('type') == "button" && (f.getProperty('name') == "browse" || f.getProperty('id') == "browse") ){
													
														f.addEvent('click', function() {
															swiffy.browse({'Local Files': vars["extensions"].replace(/,/g,";")});
															return false;
														});
													  
												  // if
												  }
												  
									  			  // Check if we're working on 
												  if( f.getProperty('type') == "button" && (f.getProperty('name') == "clear" || f.getProperty('id') == "clear") ){
													
														//alert(vars["extensions"]);
													
														f.addEvent('click', function() {
															swiffy.removeFile();
															return false;
														});
													  
												  // if
												  }
												  
									  			  // Check if we're working on 
												  if( f.getProperty('type') == "submit" ){
													
														//alert(vars["extensions"]);
													
														f.addEvent('click', function() {
															swiffy.upload();
															return false;
														});
													  
												  // if
												  }
												  
											  });

// function
}
//--------------------------------------------------------------------//

// This is the ajax form handler
function ajax_form_submit(e) {
		
		// Prevent the submit event
		e = new Event(e).stop();
		
		exit["now"] = false;
								 
		//--------------------------------------------------------------------//
		// This is where we do the form validation
				
			var i = 0;
					
			// This is for tiny mce hack
			// Loop through the forms to add a form listener
			$$("iframe").each(function(e){
				
				tmp_name = e.id.replace("_ifr","");
										
				// Check if this field is required
				if( $( tmp_name ) && $(tmp_name).get('tag') == "textarea" ){		
		
					var this_frame = window.frames[ i ].document.body.innerHTML;

						$( tmp_name ).value = this_frame;
				} i++;
			
			// Tiny mce hack
			});
			
			// This is if form is required
			this.getElements('input,select,textarea').each( function(el) {
																	 
				if( exit.now ){
					
					return;
					
				// if
				}

				// Check if the value is present
				if( el.hasClass('required') && el.value == "" ){
					
					// Cancel the submission
					exit["now"] = true;
					
				// if
				}
					
				// Check if it's a valid value
				if( el.hasClass('validate') ){

					// Check if we have a matching ruleset
					if( rule[ el.get('validate') ] ){
						
						// Do some checking
						if( el.value.search( eval(rule[ el.get('validate') ] )) == -1 ){
							
							// Cancel the submission
							exit["now"] = true;
						
						// RegEx Checking
						}
						
					// if
					}
					
				// if
				}
					
				// Check if we need to exit
				if( exit.now ){
					
					// If it has some text, say it
					if( el.get('required') != false ){	
					
						alert( el.get('required') );
						
					} else {
						
						alert( 'A required field is not valid (id:' + el.get('id') + ')' );
					
					// if
					}
					
					// Set the focus for this account
					el.focus();
					
				// if
				}
				
			// each
			});
				
			// Skip this function
			if( !exit.now  ){
				
				// This empties the log div and shows the spinning indicator
				var form_name = this.name;
		
				// Send takes care of encoding and returns the Ajax instance. onComplete removes the spinner from the log.
				this.set('send', {
					onComplete: function(e){
		
							// Convert the reponse to a string
							response = JSON.decode( e.toString() );
							
							// Do something in success field
							if( response != null && response.response != null && response.response != "false" ){
			
								// If there is a response id, use it
								if( response.id != null ){
									
									var response_id = response.id;
									
								}
								
								// add additional javascript functions if need be
								if( $(form_name + '_on_success') ){
			
									// Eval the javascript in the form
									eval ( $(form_name + '_on_success').value );
			
								}
																
								// add additional forward function if need be
								if( $(form_name + '_redirect_on_success' ) && $(form_name + '_redirect_on_success' ).value ){
									
									document.location.href = $(form_name + '_redirect_on_success' ).value;
										
								}
			
							// Do something in failure field
							} else {
								
								// add additional javascript functions if need be
								if( $(form_name + '_on_fail') ){
									
									//Evel the javascript instruction to do on failure
									eval ( $(form_name + '_on_fail').value );
									
								}
								
								// add additional forward function if need be
								if( $(form_name + '_redirect_on_fail') && $(form_name + '_redirect_on_fail').value  ){
										
									document.location.href = $(form_name + '_redirect_on_fail').value;
									
								}
								
							}
							
						// function
						}

				 }).send();
		
			//if
			}

// function
}

/**
 * Observer - Observe formelements for changes
 *
 * - Additional code from clientside.cnet.com
 *
 * @version		1.1
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */
var Observer = new Class({

	Implements: [Options, Events],

	options: {
		periodical: false,
		delay: 1000
	},

	initialize: function(el, onFired, options){
		this.element = $(el) || $$(el);
		this.addEvent('onFired', onFired);
		this.setOptions(options);
		this.bound = this.changed.bind(this);
		this.resume();
	},

	changed: function() {
		var value = this.element.get('value');
		if ($equals(this.value, value)) return;
		this.clear();
		this.value = value;
		this.timeout = this.onFired.delay(this.options.delay, this);
	},

	setValue: function(value) {
		this.value = value;
		this.element.set('value', value);
		return this.clear();
	},

	onFired: function() {
		this.fireEvent('onFired', [this.value, this.element]);
	},

	clear: function() {
		$clear(this.timeout || null);
		return this;
	},

	pause: function(){
		if (this.timer) $clear(this.timer);
		else this.element.removeEvent('keyup', this.bound);
		return this.clear();
	},

	resume: function(){
		this.value = this.element.get('value');
		if (this.options.periodical) this.timer = this.changed.periodical(this.options.periodical, this);
		else this.element.addEvent('keyup', this.bound);
		return this;
	}

});

var $equals = function(obj1, obj2) {
	return (obj1 == obj2 || JSON.encode(obj1) == JSON.encode(obj2));
};

/**
 * Autocompleter
 *
 * http://digitarald.de/project/autocompleter/
 *
 * @version		1.1.2
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */

var Autocompleter = new Class({

	Implements: [Options, Events],

	options: {/*
		onOver: $empty,
		onSelect: $empty,
		onSelection: $empty,
		onShow: $empty,
		onHide: $empty,
		onBlur: $empty,
		onFocus: $empty,*/
		minLength: 1,
		markQuery: true,
		width: 'inherit',
		maxChoices: 20,
		injectChoice: null,
		customChoices: null,
		emptyChoices: null,
		visibleChoices: true,
		className: 'autocompleter-choices',
		zIndex: 42,
		delay: 400,
		observerOptions: {},
		fxOptions: {},

		autoSubmit: false,
		overflow: false,
		overflowMargin: 25,
		selectFirst: false,
		filter: null,
		filterCase: false,
		filterSubset: false,
		forceSelect: false,
		selectMode: true,
		choicesMatch: null,

		multiple: false,
		separator: ', ',
		separatorSplit: /\s*[,;]\s*/,
		autoTrim: false,
		allowDupes: false,

		cache: true,
		relative: false
	},

	initialize: function(element, options) {
		this.element = $(element);
		this.setOptions(options);
		this.build();
		this.observer = new Observer(this.element, this.prefetch.bind(this), $merge({
			'delay': this.options.delay
		}, this.options.observerOptions));
		this.queryValue = null;
		if (this.options.filter) this.filter = this.options.filter.bind(this);
		var mode = this.options.selectMode;
		this.typeAhead = (mode == 'type-ahead');
		this.selectMode = (mode === true) ? 'selection' : mode;
		this.cached = [];
	},

	/**
	 * build - Initialize DOM
	 *
	 * Builds the html structure for choices and appends the events to the element.
	 * Override this function to modify the html generation.
	 */
	build: function() {
		if ($(this.options.customChoices)) {
			this.choices = this.options.customChoices;
		} else {
			this.choices = new Element('ul', {
				'class': this.options.className,
				'styles': {
					
					'zIndex': this.options.zIndex
				}
			}).inject(document.body);
			this.relative = false;
			if (this.options.relative) {
				this.choices.inject(this.element, 'after');
				this.relative = this.element.getOffsetParent();
			}
			this.fix = new OverlayFix(this.choices);
		}
		if (!this.options.separator.test(this.options.separatorSplit)) {
			this.options.separatorSplit = this.options.separator;
		}
		this.fx = (!this.options.fxOptions) ? null : new Fx.Tween(this.choices, $merge({
			'property': 'opacity',
			'link': 'cancel',
			'duration': 200
		}, this.options.fxOptions)).addEvent('onStart', Chain.prototype.clearChain).set(0);
		this.element .setProperty('autocomplete', 'off')
			.addEvent((Browser.Engine.trident || Browser.Engine.webkit) ? 'keydown' : 'keypress', this.onCommand.bind(this))
			.addEvent('click', this.onCommand.bind(this, [false]))
			.addEvent('focus', this.toggleFocus.create({bind: this, arguments: true, delay: 100}))
			.addEvent('blur', this.toggleFocus.create({bind: this, arguments: false, delay: 100}));
	},

	destroy: function() {
		if (this.fix) this.fix.destroy();
		this.choices = this.selected = this.choices.destroy();
	},

	toggleFocus: function(state) {
		this.focussed = state;
		if (!state) this.hideChoices(true);
		this.fireEvent((state) ? 'onFocus' : 'onBlur', [this.element]);
	},

	onCommand: function(e) {
		if (!e && this.focussed) return this.prefetch();
		if (e && e.key && !e.shift) {
			switch (e.key) {
				case 'enter':
					if (this.element.value != this.opted) return true;
					if (this.selected && this.visible) {
						this.choiceSelect(this.selected);
						return !!(this.options.autoSubmit);
					}
					break;
				case 'up': case 'down':
					if (!this.prefetch() && this.queryValue !== null) {
						var up = (e.key == 'up');
						this.choiceOver((this.selected || this.choices)[
							(this.selected) ? ((up) ? 'getPrevious' : 'getNext') : ((up) ? 'getLast' : 'getFirst')
						](this.options.choicesMatch), true);
					}
					return false;
				case 'esc': case 'tab':
					this.hideChoices(true);
					break;
			}
		}
		return true;
	},

	setSelection: function(finish) {
		var input = this.selected.inputValue, value = input;
		var start = this.queryValue.length, end = input.length;
		if (input.substr(0, start).toLowerCase() != this.queryValue.toLowerCase()) start = 0;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			value = this.element.value;
			start += this.queryIndex;
			end += this.queryIndex;
			var old = value.substr(this.queryIndex).split(split, 1)[0];
			value = value.substr(0, this.queryIndex) + input + value.substr(this.queryIndex + old.length);
			if (finish) {
				var tokens = value.split(this.options.separatorSplit).filter(function(entry) {
					return this.test(entry);
				}, /[^\s,]+/);
				if (!this.options.allowDupes) tokens = [].combine(tokens);
				var sep = this.options.separator;
				value = tokens.join(sep) + sep;
				end = value.length;
			}
		}
		this.observer.setValue(value);
		this.opted = value;
		if (finish || this.selectMode == 'pick') start = end;
		this.element.selectRange(start, end);
		this.fireEvent('onSelection', [this.element, this.selected, value, input]);
	},

	showChoices: function() {
		var match = this.options.choicesMatch, first = this.choices.getFirst(match);
		this.selected = this.selectedValue = null;
		if (this.fix) {
			var pos = this.element.getCoordinates(this.relative), width = this.options.width || 'auto';
			this.choices.setStyles({
				'left': pos.left,
				'top': pos.bottom,
				'width': 510 /*(width === true || width == 'inherit') ? pos.width : width*/,
				'padding': 0
			});

		}
		if (!first) return;
		if (!this.visible) {
			this.visible = true;
			this.choices.setStyle('display', '');
			if (this.fx) this.fx.start(1);
			this.fireEvent('onShow', [this.element, this.choices]);
		}
		if (this.options.selectFirst || this.typeAhead || first.inputValue == this.queryValue) this.choiceOver(first, this.typeAhead);
		var items = this.choices.getChildren(match), max = this.options.maxChoices;
		var styles = {'overflowY': 'hidden', 'height': ''};
		this.overflown = false;
		if (items.length > max) {
			var item = items[max - 1];
			styles.overflowY = 'scroll';
			styles.height = item.getCoordinates(this.choices).bottom;
			this.overflown = true;
		};
		this.choices.setStyles(styles);
		this.fix.show();
		if (this.options.visibleChoices) {
			var scroll = document.getScroll(),
			size = document.getSize(),
			coords = this.choices.getCoordinates();
			if (coords.right > scroll.x + size.x) scroll.x = coords.right - size.x;
			if (coords.bottom > scroll.y + size.y) scroll.y = coords.bottom - size.y;
			window.scrollTo(Math.min(scroll.x, coords.left), Math.min(scroll.y, coords.top));
		}
	},

	hideChoices: function(clear) {
		if (clear) {
			var value = this.element.value;
			if (this.options.forceSelect) value = this.opted;
			if (this.options.autoTrim) {
				value = value.split(this.options.separatorSplit).filter($arguments(0)).join(this.options.separator);
			}
			this.observer.setValue(value);
		}
		if (!this.visible) return;
		this.visible = false;
		if (this.selected) this.selected.removeClass('autocompleter-selected');
		this.observer.clear();
		var hide = function(){
			this.choices.setStyle('display', 'none');
			this.fix.hide();
		}.bind(this);
		if (this.fx) this.fx.start(0).chain(hide);
		else hide();
		this.fireEvent('onHide', [this.element, this.choices]);
	},

	prefetch: function() {
		var value = this.element.value, query = value;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			var values = value.split(split);
			var index = this.element.getSelectedRange().start;
			var toIndex = value.substr(0, index).split(split);
			var last = toIndex.length - 1;
			index -= toIndex[last].length;
			query = values[last];
		}
		if (query.length < this.options.minLength) {
			this.hideChoices();
		} else {
			if (query === this.queryValue || (this.visible && query == this.selectedValue)) {
				if (this.visible) return false;
				this.showChoices();
			} else {
				this.queryValue = query;
				this.queryIndex = index;
				if (!this.fetchCached()) this.query();
			}
		}
		return true;
	},

	fetchCached: function() {
		return false;
		if (!this.options.cache
			|| !this.cached
			|| !this.cached.length
			|| this.cached.length >= this.options.maxChoices
			|| this.queryValue) return false;
		this.update(this.filter(this.cached));
		return true;
	},

	update: function(tokens) {
		this.choices.empty();
		this.cached = tokens;
		var type = tokens && $type(tokens);

		if (!type || (type == 'array' && !tokens.length) || (type == 'hash' && !tokens.getLength())) {
			(this.options.emptyChoices || this.hideChoices).call(this);
		} else {
			
			if (this.options.maxChoices < tokens.length && !this.options.overflow) tokens.length = this.options.maxChoices;
			tokens.each(this.options.injectChoice || function(token){
				
				// Check if we just filling something in 
				if( typeof(token) == "string" ) {
															  
					var choice = new Element('li', {'html': this.markQueryValue(token)});
						choice.inputValue = token;

				// This is a different sort of beast!
				} else {
					
					var values = JSON.decode( this.element.getProperty('autocompleter') );
					
					// Check if there's more than one id
					if( values.value.search(",") > -1 ){
						
						tmp_fields = values.value.split(",");
						tmp_id = "";
						
						for(var i = 0; i < tmp_fields.length ; i++ ){
							
							tmp_id += token[ tmp_fields[i] ] + "-";
							
						// for
						}
						
						tmp_id = tmp_id.substring(0,(tmp_id.length-1))

					} else {
						
						tmp_id = token[ values.value ];
						
					// if
					}
					
					var choice = new Element('li', {'id': tmp_id, 'html': token[ values.text ] });
						choice.inputValue = token[ values.text ];
						
					// Check if theres somewhere to go
					if( values != null && values.url != null && values.url != "" ){
						
						choice.addEvent('click', function(){
														  
							document.location.href = values.url + "?" + values.value + "=" + token[ values.value ] + "&" + values.text + "=" + token[ values.text ];
														  
						// Onclick function
						});
						
					// if
					}
					
					// Check if theres somewhere to go
					if( values != null && values["function"] != null && values["function"] != "" ){
						
						choice.addEvent('click', function(){
	
							eval( values["function"] + "('" + token[ values.value ] + "','" + token[ values.text ] + "','" + token["section"] + "');" );
							
						// Onclick function
						});
						
					// if
					}

				// if
				}
				
				this.addChoiceEvents(choice).inject(this.choices);
				
			}, this);
			this.showChoices();
		}
	},

	choiceOver: function(choice, selection) {
		if (!choice || choice == this.selected) return;
		if (this.selected) this.selected.removeClass('autocompleter-selected');
		this.selected = choice.addClass('autocompleter-selected');
		this.fireEvent('onSelect', [this.element, this.selected, selection]);
		if (!this.selectMode) this.opted = this.element.value;
		if (!selection) return;
		this.selectedValue = this.selected.inputValue;
		if (this.overflown) {
			var coords = this.selected.getCoordinates(this.choices), margin = this.options.overflowMargin,
				top = this.choices.scrollTop, height = this.choices.offsetHeight, bottom = top + height;
			if (coords.top - margin < top && top) this.choices.scrollTop = Math.max(coords.top - margin, 0);
			else if (coords.bottom + margin > bottom) this.choices.scrollTop = Math.min(coords.bottom - height + margin, bottom);
		}
		if (this.selectMode) this.setSelection();
	},

	choiceSelect: function(choice) {
		if (choice) this.choiceOver(choice);
		this.setSelection(true);
		this.queryValue = false;
		this.hideChoices();
	},

	filter: function(tokens) {
		return (tokens || this.tokens).filter(function(token) {
			return this.test(token);
		}, new RegExp(((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp(), (this.options.filterCase) ? '' : 'i'));
	},

	/**
	 * markQueryValue
	 *
	 * Marks the queried word in the given string with <span class="autocompleter-queried">*</span>
	 * Call this i.e. from your custom parseChoices, same for addChoiceEvents
	 *
	 * @param		{String} Text
	 * @return		{String} Text
	 */
	markQueryValue: function(str) {
		return (!this.options.markQuery || !this.queryValue) ? str
			: str.replace(new RegExp('(' + ((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp() + ')', (this.options.filterCase) ? '' : 'i'), '<span class="autocompleter-queried">$1</span>');
	},

	/**
	 * addChoiceEvents
	 *
	 * Appends the needed event handlers for a choice-entry to the given element.
	 *
	 * @param		{Element} Choice entry
	 * @return		{Element} Choice entry
	 */
	addChoiceEvents: function(el) {
		return el.addEvents({
			'mouseover': this.choiceOver.bind(this, [el]),
			'click': this.choiceSelect.bind(this, [el])
		});
	}
});

var OverlayFix = new Class({

	initialize: function(el) {
		if (Browser.Engine.trident) {
			this.element = $(el);
			this.relative = this.element.getOffsetParent();
			this.fix = new Element('iframe', {
				'frameborder': '0',
				'scrolling': 'no',
				'src': 'javascript:false;',
				'styles': {
					'position': 'absolute',
					'border': 'none',
					'display': 'none',
					'filter': 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)'
				}
			}).inject(this.element, 'after');
		}
	},

	show: function() {
		if (this.fix) {
			var coords = this.element.getCoordinates(this.relative);
			delete coords.right;
			delete coords.bottom;
			this.fix.setStyles($extend(coords, {
				'display': '',
				'zIndex': (this.element.getStyle('zIndex') || 1) - 1
			}));
		}
		return this;
	},

	hide: function() {
		if (this.fix) this.fix.setStyle('display', 'none');
		return this;
	},

	destroy: function() {
		if (this.fix) this.fix = this.fix.destroy();
	}

});

Element.implement({

	getSelectedRange: function() {
		if (!Browser.Engine.trident) return {start: this.selectionStart, end: this.selectionEnd};
		var pos = {start: 0, end: 0};
		var range = this.getDocument().selection.createRange();
		if (!range || range.parentElement() != this) return pos;
		var dup = range.duplicate();
		if (this.type == 'text') {
			pos.start = 0 - dup.moveStart('character', -100000);
			pos.end = pos.start + range.text.length;
		} else {
			var value = this.value;
			var offset = value.length - value.match(/[\n\r]*$/)[0].length;
			dup.moveToElementText(this);
			dup.setEndPoint('StartToEnd', range);
			pos.end = offset - dup.text.length;
			dup.setEndPoint('StartToStart', range);
			pos.start = offset - dup.text.length;
		}
		return pos;
	},

	selectRange: function(start, end) {
		if (Browser.Engine.trident) {
			var diff = this.value.substr(start, end - start).replace(/\r/g, '').length;
			start = this.value.substr(0, start).replace(/\r/g, '').length;
			var range = this.createTextRange();
			range.collapse(true);
			range.moveEnd('character', start + diff);
			range.moveStart('character', start);
			range.select();
		} else {
			this.focus();
			this.setSelectionRange(start, end);
		}
		return this;
	}

});

/* compatibility */

Autocompleter.Base = Autocompleter;

/**
 * Autocompleter.Local
 *
 * http://digitarald.de/project/autocompleter/
 *
 * @version		1.1.2
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */

Autocompleter.Local = new Class({

	Extends: Autocompleter,

	options: {
		minLength: 0,
		delay: 200
	},

	initialize: function(element, tokens, options) {
		this.parent(element, options);
		this.tokens = tokens;
	},

	query: function() {
		this.update(this.filter());
	}

});

/**
 * Autocompleter.Request
 *
 * http://digitarald.de/project/autocompleter/
 *
 * @version		1.1.2
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */

Autocompleter.Request = new Class({

	Extends: Autocompleter,

	options: {/*
		indicator: null,
		indicatorClass: null,
		onRequest: $empty,
		onComplete: $empty,*/
		postData: {},
		ajaxOptions: {},
		postVar: 'value'

	},

	query: function(){
		var data = $unlink(this.options.postData) || {};
		data[this.options.postVar] = this.queryValue;
		var indicator = $(this.options.indicator);
		if (indicator) indicator.setStyle('display', 'block');
		var cls = this.options.indicatorClass;
		if (cls) this.element.addClass(cls);
		this.fireEvent('onRequest', [this.element, this.request, data, this.queryValue]);
		this.request.send({'data': data});
	},

	/**
	 * queryResponse - abstract
	 *
	 * Inherated classes have to extend this function and use this.parent()
	 */
	queryResponse: function() {
		var indicator = $(this.options.indicator);
		if (indicator) indicator.setStyle('display', 'none');
		var cls = this.options.indicatorClass;
		if (cls) this.element.removeClass(cls);
		return this.fireEvent('onComplete', [this.element, this.request]);
	}

});

Autocompleter.Request.JSON = new Class({

	Extends: Autocompleter.Request,

	initialize: function(el, options) {
		this.parent(el, options);
		this.request = new Request.JSON($merge({
			'url': sole.url + "?" + sole.querystring + "&" + sole.autocomplete,
			'link': 'cancel'
		}, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this));
	},

	queryResponse: function(response) {
		this.parent();
		this.update(response);
	}

});

Autocompleter.Request.HTML = new Class({

	Extends: Autocompleter.Request,

	initialize: function(el, url, options) {
		this.parent(el, options);
		this.request = new Request.HTML($merge({
			'url': url,
			'link': 'cancel',
			'update': this.choices
		}, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this));
	},

	queryResponse: function(tree, elements) {
		this.parent();
		if (!elements || !elements.length) {
			this.hideChoices();
		} else {
			this.choices.getChildren(this.options.choicesMatch).each(this.options.injectChoice || function(choice) {
				var value = choice.innerHTML;
				choice.inputValue = value;
				this.addChoiceEvents(choice.set('html', this.markQueryValue(value)));
			}, this);
			this.showChoices();
		}

	}

});

/* compatibility */

Autocompleter.Ajax = {
	Base: Autocompleter.Request,
	Json: Autocompleter.Request.JSON,
	Xhtml: Autocompleter.Request.HTML
};

/* ************************************************************************************* *\
 * The MIT License
 * Copyright (c) 2007 Fabio Zendhi Nagao - http://zend.lojcomm.com.br
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
 * software and associated documentation files (the "Software"), to deal in the Software
 * without restriction, including without limitation the rights to use, copy, modify,
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies
 * or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
\* ************************************************************************************* */

var iMask = new Class({
	options: {
		targetClass: ".iMask",
		maskEmptyChr: '_',

		validNumbers: "1234567890",
		validAlphas: "abcdefghijklmnopqrstuvwxyz",
		validAlphaNums: "abcdefghijklmnopqrstuvwxyz1234567890",

		onFocus: Class.empty,
		onBlur: Class.empty,
		onValid: Class.empty,
		onInvalid: Class.empty,
		onKeyDown: Class.empty
	},

	initialize: function(options) {
		this.setOptions(options);

		var fields = $$(this.options.targetClass);
		fields.each(function(obj, i) {
			obj.options = JSON.decode(obj.alt);
			if(obj.options.type == "number") obj.setStyle("text-align", "right");
			obj.addEvent("mousedown", function(event) {
				event = new Event(event);
				event.stop();
			});
			obj.addEvent("mouseup", function(event) {
				event = new Event(event);
				event.stop();
				this._onMouseUp(event, obj);
			}.bind(this));
			obj.addEvent("click", function(event) {
				event = new Event(event);
				event.stop();
			});
			obj.addEvent("keydown", function(event) {
				event = new Event(event);
				this._onKeyDown(event, obj);
				this.fireEvent("onKeyDown", obj, 20);
			}.bind(this));
			obj.addEvent("keypress", function(event) {
				event = new Event(event);
				this._onKeyPress(event, obj);
			}.bind(this));
			obj.addEvent("focus", function(event) {
				event = new Event(event);
				event.stop();
				this._onFocus(event, obj);
				this.fireEvent("onFocus", obj, 20);
			}.bind(this));
			obj.addEvent("blur", function(event) {
				event = new Event(event);
				event.stop();
				this._onBlur(event, obj);
				this.fireEvent("onBlur", obj, 20);
			}.bind(this));
		}.bind(this));
	},

	_onMouseUp: function(event, obj) {
		if(obj.options.type == "fixed") {
			var p = this._getSelectionStart(obj);
			this._setSelection(obj, p, (p + 1));
		} else if(obj.options.type == "number") {
			this._setEnd(obj);
		}
	},

	_onKeyDown: function(event, obj) {
		if(event.code == 13) { // enter
			obj.blur();
			this._submitForm(obj);
		} else if(!(event.code == 9)) {
			event.stop();
			if(obj.options.type == "fixed") {
				var p = this._getSelectionStart(obj);
				switch(event.code) {
					case 8: // Backspace
						this._selectPrevious(obj);
						break;
					case 36: // Home
						this._selectFirst(obj);
						break;
					case 35: // End
						this._selectLast(obj);
						break;
					case 37: // Left
					case 38: // Up
						this._selectPrevious(obj);
						break;
					case 39: // Right
					case 40: // Down
						this._selectNext(obj);
						break;
					case 46: // Delete
						this._updSelection(obj, p, this.options.maskEmptyChr);
						break;
					default:
						var chr = this._chrFromEvent(event);
						if(this._isViableInput(obj, p, chr)) {
							if(event.shift)
								{this._updSelection(obj, p, chr.toUpperCase());}
							else
								{this._updSelection(obj, p, chr);}
							this.fireEvent("onValid", [event, obj], 20);
							this._selectNext(obj);
						} else {
							this.fireEvent("onInvalid", [event, obj], 20);
						}
						break;
				}
			} else if(obj.options.type == "number") {
				switch(event.code) {
					case 8: // backspace
					case 46: // delete
						this._popNumber(obj);
						break;
					default:
						var chr = this._chrFromEvent(event);
						if(this.options.validNumbers.indexOf(chr) >= 0) {
							this._pushNumber(obj, chr);
							this.fireEvent("onValid", [event, obj], 20);
						} else {
							this.fireEvent("onInvalid", [event, obj], 20);
						}
						break;
				}
			}
		}
	},

	_onKeyPress: function(event, obj) {
		if(
			   !(event.code == 9) // tab
			&& !(event.shift && event.code == 9) // shift + tab
			&& !(event.code == 13) // enter
			&& !(event.ctrl && event.code == 67) // ctrl + c
			&& !(event.ctrl && event.code == 86) // ctrl + v
			&& !(event.ctrl && event.code == 88) // ctrl + x
		) {
			event.stop();
		}
	},

	_onFocus: function(event, obj) {
		if(obj.options.stripMask) obj.value = this._wearMask(obj, obj.value);
		if(obj.options.type == "fixed")
			{this._selectFirst.delay(20, this, obj);}
		else
			{this._setEnd.delay(20, this, obj);}
	},

	_onBlur: function(event, obj) {
		if(obj.options.stripMask)
			obj.value = this._stripMask(obj);
	},

	_selectAll: function(obj) {
		this._setSelection(obj, 0, obj.value.length);
	},

	_selectFirst: function(obj) {
		for(var i = 0, len = obj.options.mask.length; i < len; i++) {
			if(this._isInputPosition(obj, i)) {
				this._setSelection(obj, i, (i + 1));
				return;
			}
		}
	},

	_selectLast: function(obj) {
		for(var i = (obj.options.mask.length - 1); i >= 0; i--) {
			if(this._isInputPosition(obj, i)) {
				this._setSelection(obj, i, (i + 1));
				return;
			}
		}
	},

	_selectPrevious: function(obj, p) {
		if(!$chk(p))p = this._getSelectionStart(obj);
		if(p <= 0) {
			this._selectFirst(obj);
		} else {
			if(this._isInputPosition(obj, (p - 1))) {
				this._setSelection(obj, (p - 1), p);
			} else {
				this._selectPrevious(obj, (p - 1));
			}
		}
	},

	_selectNext: function(obj, p) {
		if(!$chk(p))p = this._getSelectionEnd(obj);
		if(p >= obj.options.mask.length) {
			this._selectLast(obj);
		} else {
			if(this._isInputPosition(obj, p)) {
				this._setSelection(obj, p, (p + 1));
			} else {
				this._selectNext(obj, (p + 1));
			}
		}
	},

	_setSelection: function(obj, a, b) {
		if(obj.setSelectionRange) {
			obj.focus();
			obj.setSelectionRange(a, b);
		} else if(obj.createTextRange) {
			var r = obj.createTextRange();
			r.collapse();
			r.moveStart("character", a);
			r.moveEnd("character", (b - a));
			r.select();
		}
	},

	_updSelection: function(obj, p, chr) {
		var value = obj.value;
		var output = "";
		output += value.substring(0, p);
		output += chr;
		output += value.substr(p + 1);
		obj.value = output;
		this._setSelection(obj, p, (p + 1));
	},

 	_setEnd: function(obj) {
		var len = obj.value.length;
		this._setSelection(obj, len, len);
	},

	_getSelectionStart: function(obj) {
		var p = 0;
		if(obj.selectionStart) {
			if($type(obj.selectionStart) == "number") p = obj.selectionStart;
		} else if(document.selection) {
			var r = document.selection.createRange().duplicate();
			r.moveEnd("character", obj.value.length);
			p = obj.value.lastIndexOf(r.text);
			if(r.text == "") p = obj.value.length;
		}
		return p;
	},

	_getSelectionEnd: function(obj) {
		var p = 0;
		if(obj.selectionEnd) {
			if($type(obj.selectionEnd) == "number")
				{p = obj.selectionEnd;}
		} else if(document.selection) {
			var r = document.selection.createRange().duplicate();
			r.moveStart("character", -obj.value.length);
			p = r.text.length;
		}
		return p;

	},

	_isInputPosition: function(obj, p) {
		var mask = obj.options.mask.toLowerCase();
		var chr = mask.charAt(p);
		if("9ax".indexOf(chr) >= 0)
			return true;
		return false;
	},

	_isViableInput: function(obj, p, chr) {
		var mask = obj.options.mask.toLowerCase();
		var chMask = mask.charAt(p);
		switch(chMask) {
			case '9':
				if(this.options.validNumbers.indexOf(chr) >= 0) return true;
				break;
			case 'a':
				if(this.options.validAlphas.indexOf(chr) >= 0) return true;
				break;
			case 'x':
				if(this.options.validAlphaNums.indexOf(chr) >= 0) return true;
				break;
			default:
				return false;
				break;
		}
	},

	_wearMask: function(obj, str) {
		var mask = obj.options.mask.toLowerCase();
		var output = "";
		for(var i = 0, u = 0, len = mask.length; i < len; i++) {
			switch(mask.charAt(i)) {
				case '9':
					if(this.options.validNumbers.indexOf(str.charAt(u).toLowerCase()) >= 0) {
						if(str.charAt(u) == "") {output += this.options.maskEmptyChr;}
						else {output += str.charAt(u++);}
					} else {
						output += this.options.maskEmptyChr;
					}
					break;
				case 'a':
					if(this.options.validAlphas.indexOf(str.charAt(u).toLowerCase()) >= 0) {
						if(str.charAt(u) == "") {output += this.options.maskEmptyChr;}
						else {output += str.charAt(u++);}
					} else {
						output += this.options.maskEmptyChr;
					}
					break;
				case 'x':
					if(this.options.validAlphaNums.indexOf(str.charAt(u).toLowerCase()) >= 0) {
						if(str.charAt(u) == "") {output += this.options.maskEmptyChr;}
						else {output += str.charAt(u++);}
					} else {
						output += this.options.maskEmptyChr;
					}
					break;
				default:
					output += mask.charAt(i);
					break
			}
		}
		return output;
	},

	_stripMask: function(obj) {
		var value = obj.value;
		if("" == value) return "";
		var output = "";
		if(obj.options.type == "fixed") {
			for(var i = 0, len = value.length; i < len; i++) {
				if((value.charAt(i) != this.options.maskEmptyChr) && (this._isInputPosition(obj, i)))
					{output += value.charAt(i);}
			}
		} else if(obj.options.type == "number") {
			for(var i = 0, len = value.length; i < len; i++) {
				if(this.options.validNumbers.indexOf(value.charAt(i)) >= 0)
					{output += value.charAt(i);}
			}
		}
		return output;
	},

	_chrFromEvent: function(event) {
		var chr = '';
		switch(event.code) {
			case 48: case 96: // 0 and numpad 0
				chr = '0';
				break;
			case 49: case 97: // 1 and numpad 1
				chr = '1';
				break;
			case 50: case 98: // 2 and numpad 2
				chr = '2';
				break;
			case 51: case 99: // 3 and numpad 3
				chr = '3';
				break;
			case 52: case 100: // 4 and numpad 4
				chr = '4';
				break;
			case 53: case 101: // 5 and numpad 5
				chr = '5';
				break;
			case 54: case 102: // 6 and numpad 6
				chr = '6';
				break;
			case 55: case 103: // 7 and numpad 7
				chr = '7';
				break;
			case 56: case 104: // 8 and numpad 8
				chr = '8';
				break;
			case 57: case 105: // 9 and numpad 9
				chr = '9';
				break;
			default:
				chr = event.key; // key pressed as a lowercase string
				break;
		}
		return chr;
	},

	_pushNumber: function(obj, chr) {
		obj.value = obj.value + chr;
		this._formatNumber(obj);
	},

	_popNumber: function(obj) {
		obj.value = obj.value.substring(0, (obj.value.length - 1));
		this._formatNumber(obj);
	},

	_formatNumber: function(obj) {
		// stripLeadingZeros
		var str2 = this._stripMask(obj);
		var str1 = "";
		for(var i = 0, len = str2.length; i < len; i++) {
			if('0' != str2.charAt(i)) {
				str1 = str2.substr(i);
				break;
			}
		}

		// wearLeadingZeros
		str2 = str1;
		str1 = "";
		for(var len = str2.length, i = obj.options.decDigits; len <= i; len++) {
			str1 += "0";
		}
		str1 += str2;

		// decimalSymbol
		str2 = str1.substr(str1.length - obj.options.decDigits)
		str1 = str1.substring(0, (str1.length - obj.options.decDigits))

		// groupSymbols
		var re = new RegExp("(\\d+)(\\d{"+ obj.options.groupDigits +"})");
		while(re.test(str1)) {
			str1 = str1.replace(re, "$1"+ obj.options.groupSymbol +"$2");
		}

		obj.value = str1 + obj.options.decSymbol + str2;
	},

	_getObjForm: function(obj) {
		var parent = obj.getParent();
		if(parent.getTag() == "form") {
			return parent;
		} else {
			return this._getObjForm(parent);
		}
	},

	_submitForm: function(obj) {
		var form = this._getObjForm(obj);
		form.submit();
	}
});
iMask.implement(new Events); // Implements addEvent(type, fn), fireEvent(type, [args], delay) and removeEvent(type, fn)
iMask.implement(new Options);// Implements setOptions(defaults, options)

/*
 * DatePicker
 * @author Rick Hopkins
 * @modified by Micah Nolte and Martin Vašina
 * @version 0.3.2
 * @classDescription A date picker object. Created with the help of MooTools v1.11
 * MIT-style License.

-- start it up by doing this in your domready:

$$('input.DatePicker').each( function(el){
	new DatePicker(el);
});

 */

var DatePicker = new Class({

	/* set and create the date picker text box */
	initialize: function(dp){

		// Options defaults
		this.dayChars = 1; // number of characters in day names abbreviation
		this.dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
		this.daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
		this.format = 'mm/dd/yyyy';
		this.monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
		this.startDay = 7; // 1 = week starts on Monday, 7 = week starts on Sunday
		this.yearOrder = 'asc';
		this.yearRange = 10;
		this.yearStart = (new Date().getFullYear())-2;


		// Finds the entered date, or uses the current date
		if(dp.value != '') {
			dp.then = new Date(dp.value);
			dp.today = new Date();
		} else {
			dp.then = dp.today = new Date();
		}
		// Set beginning time and today, remember the original
		dp.oldYear = dp.year = dp.then.getFullYear();
		dp.oldMonth = dp.month = dp.then.getMonth();
		dp.oldDay = dp.then.getDate();
		dp.nowYear = dp.today.getFullYear();
		dp.nowMonth = dp.today.getMonth();
		dp.nowDay = dp.today.getDate();

		// Pull the rest of the options from the alt attr
		if(dp.alt) {
			options = Json.evaluate(dp.alt);
		} else {
			options = [];
		}
		dp.options = {
			monthNames: (options.monthNames && options.monthNames.length == 12 ? options.monthNames : this.monthNames) || this.monthNames, 
			daysInMonth: (options.daysInMonth && options.daysInMonth.length == 12 ? options.daysInMonth : this.daysInMonth) || this.daysInMonth, 
			dayNames: (options.dayNames && options.dayNames.length == 7 ? options.dayNames : this.dayNames) || this.dayNames,
			startDay : options.startDay || this.startDay,
			dayChars : options.dayChars || this.dayChars, 
			format: options.format || this.format,
			yearStart: options.yearStart || this.yearStart,
			yearRange: options.yearRange || this.yearRange,
			yearOrder: options.yearOrder || this.yearOrder
		};
		dp.setProperties({'id':dp.getProperty('name'), 'readonly':true});
		dp.container = false;
		dp.calendar = false;
		dp.interval = null;
		dp.active = false;
		dp.onclick = dp.onfocus = this.create.pass(dp, this);
	},

	/* create the calendar */
	create: function(dp){
		if (dp.calendar) return false;

		// Hide select boxes while calendar is up
		if(window.ie6){
			$$('select').addClass('dp_hide');
		}
		
		/* create the outer container */
		dp.container = new Element('div', {'class':'dp_container'}).injectBefore(dp);
		
		/* create timers */
		dp.container.onmouseover = dp.onmouseover = function(){
			$clear(dp.interval);
		};
		dp.container.onmouseout = dp.onmouseout = function(){
			dp.interval = setInterval(function(){
				if (!dp.active) this.remove(dp);
			}.bind(this), 500);
		}.bind(this);
		
		/* create the calendar */
		dp.calendar = new Element('div', {'class':'dp_cal'}).injectInside(dp.container);
		
		/* create the date object */
		var date = new Date();
		
		/* create the date object */
		if (dp.month && dp.year) {
			date.setFullYear(dp.year, dp.month, 1);
		} else {
			dp.month = date.getMonth();
			dp.year = date.getFullYear();
			date.setDate(1);
		}
		dp.year % 4 == 0 ? dp.options.daysInMonth[1] = 29 : dp.options.daysInMonth[1] = 28;
		
		/* set the day to first of the month */
		var firstDay = (1-(7+date.getDay()-dp.options.startDay)%7);
		
		
		
		/* create the month select box */
		monthSel = new Element('select', {'id':dp.id + '_monthSelect'});
		for (var m = 0; m < dp.options.monthNames.length; m++){
			monthSel.options[m] = new Option(dp.options.monthNames[m], m);
			if (dp.month == m) monthSel.options[m].selected = true;
		}
		
		/* create the year select box */
		yearSel = new Element('select', {'id':dp.id + '_yearSelect'});
		i = 0;
		dp.options.yearStart ? dp.options.yearStart : dp.options.yearStart = date.getFullYear();
		if (dp.options.yearOrder == 'desc'){
			for (var y = dp.options.yearStart; y > (dp.options.yearStart - dp.options.yearRange - 1); y--){
				yearSel.options[i] = new Option(y, y);
				if (dp.year == y) yearSel.options[i].selected = true;
				i++;
			}
		} else {
			for (var y = dp.options.yearStart; y < (dp.options.yearStart + dp.options.yearRange + 1); y++){
				yearSel.options[i] = new Option(y, y);
				if (dp.year == y) yearSel.options[i].selected = true;
				i++;
			}
		}
		
		/* start creating calendar */
		calTable = new Element('table');
		calTableThead = new Element('thead');
		calSelRow = new Element('tr');
		calSelCell = new Element('th', {'colspan':'7'});
		monthSel.injectInside(calSelCell);
		yearSel.injectInside(calSelCell);
		calSelCell.injectInside(calSelRow);
		calSelRow.injectInside(calTableThead);
		calTableTbody = new Element('tbody');
		
		/* create day names */
		calDayNameRow = new Element('tr');
		for (var i = 0; i < dp.options.dayNames.length; i++) {
			calDayNameCell = new Element('th');
			calDayNameCell.appendText(dp.options.dayNames[(dp.options.startDay+i)%7].substr(0, dp.options.dayChars)); 
			calDayNameCell.injectInside(calDayNameRow);
		}
		calDayNameRow.injectInside(calTableTbody);
		
		/* create the day cells */
		while (firstDay <= dp.options.daysInMonth[dp.month]){
			calDayRow = new Element('tr');
			for (i = 0; i < 7; i++){
				if ((firstDay <= dp.options.daysInMonth[dp.month]) && (firstDay > 0)){
					calDayCell = new Element('td', {'class':dp.id + '_calDay', 'axis':dp.year + '|' + (parseInt(dp.month) + 1) + '|' + firstDay}).appendText(firstDay).injectInside(calDayRow);
				} else {
					calDayCell = new Element('td', {'class':'dp_empty'}).appendText(' ').injectInside(calDayRow);
				}
				// Show the previous day
				if ( (firstDay == dp.oldDay) && (dp.month == dp.oldMonth ) && (dp.year == dp.oldYear) ) {
					calDayCell.addClass('dp_selected');
				}
				// Show today
				if ( (firstDay == dp.nowDay) && (dp.month == dp.nowMonth ) && (dp.year == dp.nowYear) ) {
					calDayCell.addClass('dp_today');
				}
				firstDay++;
			}
			calDayRow.injectInside(calTableTbody);
		}
		
		/* table into the calendar div */
		calTableThead.injectInside(calTable);
		calTableTbody.injectInside(calTable);
		calTable.injectInside(dp.calendar);
		
		/* set the onmouseover events for all calendar days */
		$$('td.' + dp.id + '_calDay').each(function(el){
			el.onmouseover = function(){
				el.addClass('dp_roll');
			}.bind(this);
		}.bind(this));
		
		/* set the onmouseout events for all calendar days */
		$$('td.' + dp.id + '_calDay').each(function(el){
			el.onmouseout = function(){
				el.removeClass('dp_roll');
			}.bind(this);
		}.bind(this));
		
		/* set the onclick events for all calendar days */
		$$('td.' + dp.id + '_calDay').each(function(el){
			el.onclick = function(){
				ds = el.axis.split('|');
				dp.value = this.formatValue(dp, ds[0], ds[1], ds[2]);
				this.remove(dp);
			}.bind(this);
		}.bind(this));
		
		/* set the onchange event for the month & year select boxes */
		monthSel.onfocus = function(){ dp.active = true; };
		monthSel.onchange = function(){
			dp.month = monthSel.value;
			dp.year = yearSel.value;
			this.remove(dp);
			this.create(dp);
		}.bind(this);
		
		yearSel.onfocus = function(){ dp.active = true; };
		yearSel.onchange = function(){
			dp.month = monthSel.value;
			dp.year = yearSel.value;
			this.remove(dp);
			this.create(dp);
		}.bind(this);
	},
	
	/* Format the returning date value according to the selected formation */
	formatValue: function(dp, year, month, day){
		/* setup the date string variable */
		var dateStr = '';
		
		/* check the length of day */
		if (day < 10) day = '0' + day;
		if (month < 10) month = '0' + month;
		
		/* check the format & replace parts // thanks O'Rey */
		dateStr = dp.options.format.replace( /dd/i, day ).replace( /mm/i, month ).replace( /yyyy/i, year );
		dp.month = dp.oldMonth = '' + (month - 1) + '';
		dp.year = dp.oldYear = year;
		dp.oldDay = day;
		
		dateStr = year + "-" + month + "-" + day;
		
		/* return the date string value */
		return dateStr;
	},
	
	/* Remove the calendar from the page */
	remove: function(dp){
		$clear(dp.interval);
		dp.active = false;
		if (window.opera) dp.container.empty();
		else if (dp.container) dp.container.destroy();
		dp.calendar = false;
		dp.container = false;
		$$('select.dp_hide').removeClass('dp_hide');
	}
});

/**
 * Swiff.Uploader - Flash FileReference Control
 *
 * @version		1.2
 *
 * @license		MIT License
 *
 * @author		Harald Kirschner <mail [at] digitarald [dot] de>
 * @copyright	Authors
 */

Swiff.Uploader = new Class({

	Extends: Swiff,

	Implements: Events,

	options: {
		path: sole.assets.swf + 'Swiff.Uploader.swf',
		multiple: true,
		queued: true,
		typeFilter: null,
		url: null,
		method: 'post',
		data: null,
		fieldName: 'Filedata',
		target: null,
		height: '100%',
		width: '100%',
		callBacks: null,
		id: ''
	},

	initialize: function(options){
		if (Browser.Plugins.Flash.version < 9) return false;
		this.setOptions(options);

		var callBacks = this.options.callBacks || this;
		if (callBacks.onLoad) this.addEvent('onLoad', callBacks.onLoad);
		if (!callBacks.onBrowse) {
			callBacks.onBrowse = function() {
				return this.options.typeFilter;
			}
		}

		var prepare = {}, self = this;
		['onBrowse', 'onSelect', 'onAllSelect', 'onCancel', 'onBeforeOpen', 'onOpen', 'onProgress', 'onComplete', 'onError', 'onAllComplete'].each(function(index) {
			var fn = callBacks[index] || $empty;
			prepare[index] = function() {
				self.fireEvent(index, arguments, 10);
				return fn.apply(self, arguments);
			};
		});

		prepare.onLoad = this.load.create({delay: 10, bind: this});
		this.options.callBacks = prepare;

		var path = this.options.path;
		if (!path.contains('?')) path += '?noCache=' + $time(); // quick fix

		this.parent(path);

		var scroll = window.getScroll();
		this.box = new Element('div', {
			styles: {
				position: 'absolute',
				visibility: 'visible',
				zIndex: 9999,
				overflow: 'hidden',
				height: 15, width: 15,
				top: scroll.y, left: scroll.x
			}
		});
		this.inject(this.box);
		this.box.inject($(this.options.container) || document.body);

		return this;
	},

	load: function(){
		this.remote('register', this.instance, this.options.multiple, this.options.queued);
		this.fireEvent('onLoad');

		this.target = $(this.options.target);
		if (Browser.Plugins.Flash.version >= 10 && this.target) {
			this.reposition();
			window.addEvent('resize', this.reposition.bind(this));
		}
	},

	reposition: function() {
		var pos = this.target.getCoordinates(this.box.getOffsetParent());
		this.box.setStyles(pos);
	},

	/*
	Method: browse
		Open the file browser.
	*/

	browse: function(typeFilter){
		this.options.typeFilter = $pick(typeFilter, this.options.typeFilter);
		return this.remote('browse');
	},

	/*
	Method: upload
		Starts the upload of all selected files.
	*/

	upload: function(options){
		var current = this.options;
		options = $extend({data: current.data, url: current.url, method: current.method, fieldName: current.fieldName}, options);
		if ($type(options.data) == 'element') options.data = $(options.data).toQueryString();
		return this.remote('upload', options);
	},

	/*
	Method: removeFile
		For multiple uploads cancels and removes the given file from queue.

	Arguments:
		name - (string) Filename
		name - (string) Filesize in byte
	*/

	removeFile: function(file){
		if (file) file = {name: file.name, size: file.size};
		return this.remote('removeFile', file);
	},

	/*
	Method: getFileList
		Returns one Array with with arrays containing name and size of the file.

	Returns:
		(array) An array with files
	*/

	getFileList: function(){
		return this.remote('getFileList');
	}

});

/**
 * Fx.ProgressBar
 *
 * @version		1.0
 *
 * @license		MIT License
 *
 * @author		Harald Kirschner <mail [at] digitarald [dot] de>
 * @copyright	Authors
 */

Fx.ProgressBar = new Class({

	Extends: Fx,

	options: {
		text: null,
		transition: Fx.Transitions.Circ.easeOut,
		link: 'cancel'
	},

	initialize: function(element, options) {
		this.element = $(element);
		this.parent(options);
		this.text = $(this.options.text);
		this.set(0);
	},

	start: function(to, total) {
		return this.parent(this.now, (arguments.length == 1) ? to.limit(0, 100) : to / total * 100);
	},

	set: function(to) {
		this.now = to;
		this.element.setStyle('backgroundPosition', (100 - to) + '% 0px');
		if (this.text) this.text.set('text', Math.round(to) + '%');
		return this;
	}

});

/**
 * FancyUpload - Flash meets Ajax for powerful and elegant uploads.
 *
 * @version		2.1
 *
 * @license		MIT License
 *
 * @author		Harald Kirschner <mail [at] digitarald [dot] de>
 * @copyright	Authors
 */

var FancyUpload2 = new Class({

	Extends: Swiff.Uploader,

	options: {
		limitSize: false,
		limitFiles: 5,
		instantStart: false,
		allowDuplicates: false,
		validateFile: $lambda(true), // provide a function that returns true for valid and false for invalid files.
		debug: false,

		fileInvalid: null, // called for invalid files with error stack as 2nd argument
		fileCreate: null, // creates file element after select
		fileUpload: null, // called when file is opened for upload, allows to modify the upload options (2nd argument) for every upload
		fileComplete: null, // updates the file element to completed state and gets the response (2nd argument)
		fileRemove: null // removes the element
		/**
		 * Events:
		 * onBrowse, onSelect, onAllSelect, onCancel, onBeforeOpen, onOpen, onProgress, onComplete, onError, onAllComplete
		 */
	},

	initialize: function(status, list, options) {
		this.status = $(status);
		this.list = $(list);

		this.files = [];

		if (options.callBacks) {
			this.addEvents(options.callBacks);
			options.callBacks = null;
		}

		this.parent(options);
		this.render();
	},

	render: function() {
		
		try{
		
			this.overallTitle = this.status.getElement('.overall-title');
			this.currentTitle = this.status.getElement('.current-title');
			this.currentText = this.status.getElement('.current-text');
	
			var progress = this.status.getElement('.overall-progress');
			this.overallProgress = new Fx.ProgressBar(progress, {
				text: new Element('span', {'class': 'progress-text'}).inject(progress, 'after')
			});
			progress = this.status.getElement('.current-progress')
			this.currentProgress = new Fx.ProgressBar(progress, {
				text: new Element('span', {'class': 'progress-text'}).inject(progress, 'after')
			});

		} catch( error ){}
	},

	onLoad: function() {
		this.log('Uploader ready!');
	},

	onBeforeOpen: function(file, options) {
		this.log('Initialize upload for "{name}".', file);
		var fn = this.options.fileUpload;
		var obj = (fn) ? fn.call(this, this.getFile(file), options) : options;
		return obj;
	},

	onOpen: function(file, overall) {
		this.log('Starting upload "{name}".', file);
		file = this.getFile(file);
		file.element.addClass('file-uploading');
		this.currentProgress.cancel().set(0);
		this.currentTitle.set('html', 'File Progress "{name}"'.substitute(file) );
	},

	onProgress: function(file, current, overall) {
		this.overallProgress.start(overall.bytesLoaded, overall.bytesTotal);
		this.currentText.set('html', 'Upload with {rate}/s. Time left: ~{timeLeft}'.substitute({
			rate: (current.rate) ? this.sizeToKB(current.rate) : '- B',
			timeLeft: Date.fancyDuration(current.timeLeft || 0)
		}));
		this.currentProgress.start(current.bytesLoaded, current.bytesTotal);
	},

	onSelect: function(file, index, length) {
		var errors = [];
		if (this.options.limitSize && (file.size > this.options.limitSize)) errors.push('size');
		if (this.options.limitFiles && (this.countFiles() >= this.options.limitFiles)) errors.push('length');
		if (!this.options.allowDuplicates && this.getFile(file)) errors.push('duplicate');
		if (!this.options.validateFile.call(this, file, errors)) errors.push('custom');
		if (errors.length) {
			var fn = this.options.fileInvalid;
			if (fn) fn.call(this, file, errors);
			return false;
		}
		(this.options.fileCreate || this.fileCreate).call(this, file);
		this.files.push(file);
		$('upload-list').setStyle('display','block');
		return true;
	},

	onAllSelect: function(files, current, overall) {
		this.log('Added ' + files.length + ' files, now we have (' + current.bytesTotal + ' bytes).', arguments);
		this.updateOverall(current.bytesTotal);
		this.status.removeClass('status-browsing');
		if (this.files.length && this.options.instantStart) this.upload.delay(10, this);
	},

	onComplete: function(file, resp) {
		
		if( this.countFiles() <= 1){

			response = JSON.decode(resp);
			
			if( response.response == "true" && $(this.options.id + '_on_success') ){
	
				// Eval the javascript in the form
				eval ( $(this.options.id + '_on_success').value );
	
			// if
			}
			
			if( response.response == "false" && $(this.options.id + '_on_fail') ){
	
				// Eval the javascript in the form
				eval ( $(this.options.id + '_on_fail').value );
	
			// if
			}

		// if
		}
		
		this.log('Completed upload "' + file.name + '".', arguments);
		this.currentText.set('html', 'Upload complete!');
		this.currentProgress.start(100);
		(this.options.fileComplete || this.fileComplete).call(this, this.finishFile(file), resp);
	},

	onError: function(file, error, info) {
		this.log('Upload "' + file.name + '" failed. "{1}": "{2}".', arguments);
		(this.options.fileError || this.fileError).call(this, this.finishFile(file), error, info);
	},

	onCancel: function() {
		this.log('Filebrowser cancelled.', arguments);
		this.status.removeClass('file-browsing');
	},

	onAllComplete: function(current) {
		this.log('Completed all files, ' + current.bytesTotal + ' bytes.', arguments);
		this.updateOverall(current.bytesTotal);
		this.overallProgress.start(100);
		this.status.removeClass('file-uploading');
		
	},

	browse: function(fileList) {
		var ret = this.parent(fileList);
		if (ret !== true){
			if (ret) this.log('An error occured: ' + ret);
			else this.log('Browse in progress.');
		} else {
			this.log('Browse started.');
			this.status.addClass('file-browsing');
		}
	},

	upload: function(options) {
		var ret = this.parent(options);
		if (ret !== true) {
			this.log('Upload in progress or nothing to upload.');
			if (ret) alert(ret);
		} else {
			this.log('Upload started.');
			this.status.addClass('file-uploading');
			this.overallProgress.set(0);
		}
	},

	removeFile: function(file) {
		var remove = this.options.fileRemove || this.fileRemove;
		if (!file) {
			this.files.each(remove, this);
			this.files.empty();
			this.updateOverall(0);
		} else {
			if (!file.element) file = this.getFile(file);
			this.files.erase(file);
			remove.call(this, file);
			this.updateOverall(this.bytesTotal - file.size);
		}
		this.countFiles();
		this.parent(file);
	},

	getFile: function(file) {
		var ret = null;
		this.files.some(function(value) {
			if ((value.name != file.name) || (value.size != file.size)) return false;
			ret = value;
			return true;
		});
		return ret;
	},

	countFiles: function() {
		var ret = 0;
		for (var i = 0, j = this.files.length; i < j; i++) {
			if (!this.files[i].finished) ret++;
		}
		return ret;
	},

	updateOverall: function(bytesTotal) {
		this.bytesTotal = bytesTotal;
		this.overallTitle.set('html', 'Overall Progress (' + this.sizeToKB(bytesTotal) + ')');
	},

	finishFile: function(file) {
		file = this.getFile(file);
		file.element.removeClass('file-uploading');
		file.finished = true;
		return file;
	},

	fileCreate: function(file) {
		file.info = new Element('span', {'class': 'file-info'});
		file.element = new Element('li', {'class': 'file'}).adopt(
			new Element('span', {'class': 'file-size', 'html': this.sizeToKB(file.size)}),
			new Element('a', {
				'class': 'file-remove',
				'href': '#',
				'html': 'x',
				'events': {
					'click': function() {
						this.removeFile(file);
						return false;
					}.bind(this)
				}
			}),
			new Element('span', {'class': 'file-name', 'html': file.name}),
			file.info
		).inject(this.list);
	},

	fileComplete: function(file, response) {
		tmp = this.countFiles();
		this.options.processResponse || this
		var json = $H(JSON.decode(response, true));
		if (json.response == 'true') {
			file.element.addClass('file-success');
			file.info.set('html', json.get('size'));
		} else {
			file.element.addClass('file-failed');
			file.info.set('html', json.get('error') || json.message);
		}
	},

	fileError: function(file, error, info) {
		file.element.addClass('file-failed');
		file.info.set('html', '<strong>' + error + '</strong><br />' + info);
	},

	fileRemove: function(file) {
		file.element.fade('out').retrieve('tween').chain(Element.destroy.bind(Element, file.element));
	},

	sizeToKB: function(size) {
		var unit = 'B';
		if ((size / 1048576) > 1) {
			unit = 'MB';
			size /= 1048576;
		} else if ((size / 1024) > 1) {
			unit = 'kB';
			size /= 1024;
		}
		return size.round(1) + ' ' + unit;
	},

	log: function(text, args) {
		if (this.options.debug && window.console) console.log(text.substitute(args || {}));
	}

});

/**
 * @todo Clean-up, into Date.js
 */
Date.parseDuration = function(sec) {
	var units = {}, conv = Date.durations;
	for (var unit in conv) {
		var value = Math.floor(sec / conv[unit]);
		if (value) {
			units[unit] = value;
			if (!(sec -= value * conv[unit])) break;
		}
	}
	return units;
};

Date.fancyDuration = function(sec) {
	var ret = [], units = Date.parseDuration(sec);
	for (var unit in units) ret.push(units[unit] + Date.durationsAbbr[unit]);
	return ret.join(', ');
};

Date.durations = {years: 31556926, months: 2629743.83, days: 86400, hours: 3600, minutes: 60, seconds: 1, milliseconds: 0.001};
Date.durationsAbbr = {
	years: 'j',
	months: 'm',
	days: 'd',
	hours: 'h',
	minutes: 'min',
	seconds: 'sec',
	milliseconds: 'ms'
};