
/**
* Extension for a select field. 
* Contains some methods to 
* simplyfy the selecti element.
* 
* Method names and functions are 
* selfexplanatory.
*/
SelectField = Class.create();
Object.extend(SelectField.prototype, {
	initialize: function() {	
		this.extended = true;
	},
	
	selectOptionByValue: function(value) {
		for(i = 0; i < this.length; ++i){
			if(this.options[i].value == value) {
				this.options[i].selected = true;
			}
		}
		return true;
	},
	
	selectAll: function() {
		for(i = 0; i < this.length; ++i){
			this.options[i].selected = true;
		}
		return true;
	},
	
	unselectAll: function() {
		if(!isNaN(this.length)) {
			for(i = 0; i < this.length; ++i) {
				this.options[i].selected = false;
			}
		}
		return true;
	},
	
	removeOptionByValue: function(value) {
		for(i = 0; i < this.length; ++i) {
			if(this.options[i].value == value) {
				this.options[i]=null;
				return i;
			}
		}
		return -1;
	},
	
	removeOption: function(option) {
		this.options[option.index]=null;
	},
	
	removeSelected: function() {
		this.options[this.selectedIndex]=null;
	},
	
	addOption: function(value, label) {
		newoption = new Option(label,value);
		this.options[this.length] = newoption;		
		return newoption;
	},
	
	addOptionFrom: function(option) {
		var text = option.text;		
		text = text.replace(/(^[\s\xA0]+|[\s\xA0]+$)/g, '');
		return this.addOption(option.value, text);
	},
	
	getSelected: function() {
		if(this.selectedIndex > -1)
			return this.options[this.selectedIndex];
		return null;
	},
	contains: function(option) {
		for(i = 0; i < this.options.length; ++i) {
			var option2 = this.options[i];
			if(option2.value == option.value)
				return true;
		}
		return false;
	},
	sort: function() {
		var objects = $A(this.options).sortBy(function(s) {
			var text = s.text;
			return text;
		});
		for(i = 0; i < objects.length; ++i) {
			this.options[i] = objects[i];
		}
	},
	isSelected: function() {
		return (this.selectedIndex >= 0);
	}, 
	removeAll: function() {
		while(this.options.length > 0){
			this.options[0] = null;
		}
	}
});

/*
* FormSelection is a combination of 3 select elements.
* value change in the first select element triggers an
* ajax update and updates the values in the middle. (ajax response is a 
* html formatted option list.)
* 
* value update in the middle (click) updates the right column with the value. 
* 
* value update in the left (click) removes the value from the option list.
* when new option is added the notify message to registered observers is sent.
* that 
*/
FormSelection = Class.create();
Object.extend(FormSelection.prototype, {
	initialize: function(leftSelect, middleSelect, rightSelect, middleUpdateUrl) {
		this.leftSelect = Object.extend(leftSelect,new SelectField());
		this.middleSelect = Object.extend(middleSelect,new SelectField());
		this.rightSelect = Object.extend(rightSelect,new SelectField());
		this.middleUpdateUrl = middleUpdateUrl;
		this.initEvents();			
		this.updating = false;	
		this.observers = new Array();
		if (navigator.appName=="Microsoft Internet Explorer") 
			this.delayed = true;
		else
			this.delayed = false;
		this.setupSelections();
	},
	initEvents: function() {		
		Event.observe(this.leftSelect, 'change',this.leftAction.bind(this));
		Event.observe(this.leftSelect, 'select',this.leftAction.bind(this));
		Event.observe(this.middleSelect, 'change',this.middleAction.bind(this));
		Event.observe(this.middleSelect, 'select',this.middleAction.bind(this));	
		Event.observe(this.rightSelect, 'change',this.rightAction.bind(this));
		Event.observe(this.rightSelect, 'select',this.rightAction.bind(this));
	},
	
	setupSelections: function() {
		if (this.delayed) {
			this.timer1 = new PeriodicalExecuter(this.leftSelect.unselectAll.bind(this.leftSelect), 0.5);
			this.timer2 = new PeriodicalExecuter(this.middleSelect.unselectAll.bind(this.middleSelect), 0.5);
		}
	},
	breakSelections: function() {
		if (this.delayed) {
			this.timer1.stop();
			this.timer2.stop();
		}
	},
	clearSelections: function() {
		if (this.delayed) {
			this.breakSelections();
			this.setupSelections();
		}		
	},
	
	leftAction: function(event ) {		
		if(this.leftSelect.isSelected()) {			
			this.updateMiddle(this.leftSelect.getSelected());		
		}
		Event.stop(event);
		this.clearSelections();
	},
	
	middleAction: function(event) {
		this.breakSelections();
		if(this.middleSelect.isSelected()) {
			var option = this.middleSelect.getSelected();
			if(!this.rightSelect.contains(option)) {
				//option.text = option.text.strip();
				this.rightSelect.addOptionFrom(option);
				this.notify();
			}
			this.middleSelect.unselectAll();			
		}	
		Event.stop(event);
		if(window.selectionPostHook)
			selectionPostHook(this.rightSelect);
	},
	rightAction: function() {		
		if(this.rightSelect.isSelected()) {		
			this.rightSelect.removeSelected();
		}
		this.notify();
		if(window.selectionPostHook)
			selectionPostHook(this.rightSelect);
	},
	
	updateMiddle: function(option) {		
		new Ajax.Updater(this.middleSelect,this.middleUpdateUrl+option.value);			
	},
	
	updatingSearch: function(updating) {
		this.updating = updating;
		if(updating) {
			this.rightSelect.selectAll();
		} else {
			this.rightSelect.unselectAll();
		}		
	},
	
	notify: function() {
		this.observers.each(function(o) {
			o.childUpdated();
		});
	},
	
	addObserver: function(observer) {
		this.observers[this.observers.length] = observer;
	}	
	
});

/**
* Updatable form handles the ajax update to updateElem based on the URL
* it handles also the actions taken in the FormSelection objects.
* Creates the query url based on the Form.serialize(); (similary as form GET).
* @param form form element
* @param formSelections - Array of FormSelections
* @param updateUrl - url where to update  the updateElem
* @param updateElem - updated element 
*/
UpdatableForm = Class.create();
Object.extend(UpdatableForm.prototype, {
	initialize: function(form, formSelections, updateUrl, updateElem) {
		this.form = form;
		this.formSelections = formSelections;
		this.updateUrlBase = updateUrl;
		this.updateUrl = null;
		this.updateElem = updateElem;
		this.initEvents();		
	},
	
	initEvents: function() {
		Event.observe(this.form, 'change', this.updateSearch.bind(this));				
		for(i = 0 ; i < this.formSelections.length; ++i) {		
			this.formSelections[i].addObserver(this);
		}
		Event.observe(this.form, 'submit', this.submitForm.bind(this));
		var array = Form.getElements(this.form);
		for(i = 0 ; i < array.length; ++i) {
			var elem = array[i];
			if(elem.match("INPUT")) {
				// inputs are handled separately.
			} else if(elem.match("SELECT") && elem != $('cityAreas') && elem != $('products') && elem != $('makeModel')) {
				if(!elem.match(".ignoreAjax")) {
					Event.observe(elem, 'change', this.updateSearch.bind(this));
					Event.observe(elem, 'select', this.updateSearch.bind(this));	
				}
			}
		}
		var inputs = Form.getInputs(this.form, 'checkbox');
		for(j = 0 ; j < inputs.length; ++j) {
			Event.observe(inputs[j], 'click', this.updateSearch.bind(this));
			Event.observe(inputs[j], 'change', this.updateSearch.bind(this));	
		}
		var inputs = Form.getInputs(this.form, 'text');
		for(j = 0 ; j < inputs.length; ++j) {		
			Event.observe(inputs[j], 'change', this.updateSearch.bind(this));			
		}
		this.updateSearch();
	},
	
	childUpdated: function() {
		this.updateSearch();
	},
	
	submitForm: function() {
		this.formSelections.each(function(selection) {
			selection.updatingSearch(true);
		});
		Event.stopObserving(this.form, 'submit', this.submitForm.bind(this));
		this.form.submit();
	},

	updateSearch: function() {
		this.formSelections.each(function(selection) {
			selection.updatingSearch(true);
		});					
		this.buildUrl();
		this.formSelections.each(function(selection) {
			selection.updatingSearch(false);
		});		
		this.sendAjax();		
	},
	
	buildUrl: function() {
		var query = Form.serialize(this.form);			
		this.updateUrl = this.updateUrlBase + query;
	},	
	sendAjax: function() {
		new Ajax.Updater(this.updateElem,this.updateUrl);
	}
});