if(!ch){
	var ch = {};
}
if(!ch.exmachina){
	ch.exmachina = {};
}
if(!ch.exmachina.bravofly){
	ch.exmachina.bravofly = {};
}
/**
 * RichField e' la classe base per l'autocompleter cosi' come viene usato in pricefinder. Al proprio interno utilizza
 * il componente Ajax.Autocompleter di Scriptaculous ed aggiunge al suo fianco l'immagine che fa da closer, il cui
 * comportamento viene definito da chi si occupa di costruire l'istanza di RichField
 * @constructor
 * @param ctorArgs
 */
ch.exmachina.bravofly.RichField = function(/* object */ctorArgs){
	var _timestamp = (new Date()).getTime(),
		autocompleteURL = ctorArgs.autocompleteURL,
		resultsLimit = ctorArgs.resultsLimit || 20,
		type = ctorArgs.type,
		self = this
	;
	this.domNode = document.createElement("div");
	this.pNode = $(ctorArgs.pNode);
	this.pGroup = $(ctorArgs.pGroup);
	this.searchLanguage = ctorArgs.searchLanguage || this.searchLanguage;
	
	this.domNode.innerHTML = this.template.replace(/{\$FieldId}/g, _timestamp).
		replace("{$Searching}", ctorArgs.searching || "Searching...")
	;
	// ricava fieldNode prima di togliere il commento da queste due righe
	this.pNode.appendChild(this.domNode);
	this.fieldNode = $("RichField" + _timestamp);
	this.listNode = $("ta_list" + _timestamp);
	this.indicatorNode = $("ta_indicator" + _timestamp);
	this.closerNode = $("Clean" + _timestamp);
	// removing node ids
	this.fieldNode.writeAttribute("id", null);	
	//this.listNode.writeAttribute("id", null);	
	this.indicatorNode.writeAttribute("id", null);	
	this.closerNode.writeAttribute("id", null);	
	
	
	this.dirty = ctorArgs.dirty || this.dirty;
	this.promptText = ctorArgs.defaultValue || ctorArgs.promptText || "";
	
	this.indicatorNode.style.position = "absolute";
	this.onComplete = ctorArgs.onComplete || this.onComplete;
	this.onClose = ctorArgs.onClose || this.onClose;
	this.onClean = ctorArgs.onClean || this.onClean;
	this.onFreeze = ctorArgs.onFreeze || this.onFreeze;
	this.onUnfreeze = ctorArgs.onUnfreeze || this.onUnfreeze;
    this.countryCode = ctorArgs.countryCode || "";
    this.continentCode = ctorArgs.continentCode || "";
	// RIMUOVERE GLI ID!


	/* Autocompleter */
    !Prototype.Browser.IE && this.bindEvents();
    this.autocompleter = new Ajax.Autocompleter(this.fieldNode, this.listNode, autocompleteURL, {
    	paramName: "key", 
    	frequency: .01, 
    	minChars:3, 
    	parameters: "type=dep&language=" + self.searchLanguage + "&limit=" + 
            resultsLimit + "&countryCode=" + self.countryCode + "&continentCode=" + self.continentCode,
    	updateElement: function(cItem){
    		if(!self.isFreezed()){
				self.storedId = cItem.id;
    			self.fieldNode.value = cItem.innerHTML.stripTags();
	    		self.freeze();
	    		self.onComplete();
                self.fieldNode.writeAttribute("data", cItem.id);
    		}
    	},
    	fields: ['routeFilter'], 
    	indicator: self.indicatorNode
    });
	if(!this.dirty){
		this.fieldNode.value = this.promptText;
	}
    Prototype.Browser.IE && this.bindEvents();
};

ch.exmachina.bravofly.RichField.prototype = {
	// ****************************************************************************************************
	// members
	/**
	 * Il template di questo oggetto, contenente il campo target che diventera' un autocompleter e il link per
	 * la chiusura del campo/cancellazione del contenuto
	 * @type {String}
	 */
	template: '<input type="text" value="" class="ta_rich_field" id="RichField{$FieldId}" />' +
			'<a id="Clean{$FieldId}" ' +
			'class="ta_cleanAirport_hidden" href="#"><img src="http://www3.staticroot.com/images/pricefinder/ta_x.gif" /></a>' +
			'<div class="aeroList" id="ta_list{$FieldId}"></div>' +
			'<div id="ta_indicator{$FieldId}" ' +
			'style="display:none" id="ta_indicator{$FieldId}" class="ta_indicator">{$Searching}</div>',
	/**
	 * Linguaggio di ricerca per l'autocompleter
	 * @type {String}
	 * @default EN
	 */
	searchLanguage: "EN",
	/**
	 * Limite di risultati presentati nell'autocompleter
	 * @type {Number}
	 * @default 20
	 */
	resultsLimit: 20,
	/**
	 * Questo flag dice se il campo di testo e' stato modificato da una azione dell'utente
	 * @type {Boolean}
	 */
	dirty: false,
	/**
	 * Testo mostrato all'inizio, sarebbe l'equivalente dell'attributo "placeholder" di html5
	 * @type {String}
	 * @default ""
	 */
	promptText: "",
	/**
	 * Id della selezione attuale: dal server arriva un frammento di HTML (non valido, ci sono degli id che cominciano
	 * con dei numeri, sono quelli che forniscono idCity, latitudine e longitudine separati da :), gli id vengono
	 * inseriti all'interno di questa proprieta'
	 * @type {String}
	 * @default ""
	 */
	storedId: "",
	/**
	 * Viene passato direttamente alla ricerca, e' fornito come argomento del costruttore
	 * @type {String}
	 * @default ""
	 */
    countryCode: "",
	/**
	 * Analogo a countryCode, viene fornito come argomento al costruttore e servito direttamente al server nella
	 * richiesta
	 * @type {String}
	 * @default ""
	 */
    continentCode: "",
	// domNodes
	/**
	 * Nodo DOM dell'istanza corrente
	 * @type {Node}
	 * @default null
	 */
	domNode: null,
	/**
	 * Nodo DOM del campo di testo che diventera' Autocompleter
	 * @type {Node}
	 * @default null
	 */
	fieldNode: null,
	/**
	 * Nodo contenente un'eventuale notifica di connessione attiva
	 * @type {Node}
	 */
	indicatorNode: null,
	/**
	 * Nodo che contiene l'immagine X; al click viene invocata la onClose, che puo' essere sovrascritta esternamente
	 * in modo da tenere conto delle interazioni fra i diversi campi del gruppo e di eventuali altri vincoli, come
	 * per esempio il numero massimo e minimo di campi per ogni gruppo
	 * @type {Node}
	 */
	closerNode: null,
	// parent node
	/**
	 * Nodo parent del campo
	 * @type {Node}
	 */
	pNode: null,
	// status
	/**
	 * Campo disabled di questo input field: non impostare mai direttamente, usare i
	 * metodi {@link ch.exmachina.bravofly.RichField#enable} e {@link ch.exmachina.bravofly.RichField#disable}
	 */
	disabled: false,
	// parent group ref
	/**
	 * Gruppo di appartenenza del Field
	 * @type {ch.exmachina.bravofly.FieldGroup}
	 */
	pGroup: null,
	/**
	 * Proprieta' che ospita l'autocompleter che fa parte di questo field
	 * @type {Object}
	 */
    autocompleter: null,

	// ****************************************************************************************************
	// methods
	/**
	 * Restituisce il valore associato con questo campo
	 * @returns {String}
	 */
	getValue: function(){
		return this.fieldNode.value;
	},
	/**
	 * Assegna un valore a questo campo
	 * @param {String} value Il campo da assegnare
	 */
	setValue: function(/** String */ value){
		this.fieldNode.value = value;
	},
	/**
	 * Restituisce l'id relativo ai dati contenuti in questo campo
	 * @returns {String}
	 */
	getStoredId: function(){
		return this.storedId;
	},
	// hooks
	/**
	 * Invocata ogni volta che viene ripulito il campo corrente. Sovrascrivibile dall'esterno
	 */
	onClean: function(){
	},
	/**
	 * Hook eseguito quando l'utente seleziona l'opzione dalla lista e questa va a valorizzare il campo corrente
	 */
	onComplete: function(){
	},
	/**
	 * Callback invocata quando viene cliccato il nodo closer, quello contenente la X
	 */
	onClose: function(){
	},
	/**
	 * Callback chiamata quando avviene la blur del campo di testo
	 */
	onBlur: function(){
	},
	/**
	 * Callback chiamata quando avviene la focus del campo di testo
	 */
	onFocus: function(){
	},
	/**
	 * Funzione eseguita quando il campo viene "congelato" e reso in sola lettura.
	 * @see ch.exmachina.bravofly.RichField#onUnfreeze
	 */
	onFreeze: function(){
	},
	/**
	 * Funzione eseguita quando il campo viene "scongelato", rendendolo di nuovo scrivibile.
	 * @see ch.exmachina.bravofly.RichField#onFreeze
	 */
	onUnfreeze: function(){
	},
	// event handlers
	/**
	 * Gestore dell'evento di chiusura, che si verifica al click sul closer, la X alla destra del campo
	 * @param evt
	 */
	closeHandler: function(evt){
		this.onClose();
        Event.stop(evt);
	},
	/**
	 * Gestore del fuoco sul campo di testo contenuto in questo Field, alla fine invoca l'hook per questo evento
	 */
	focusHandler: function(){
		if(this.disabled){ return; }
		Element.clonePosition(this.indicatorNode, this.fieldNode,{
			setLeft: true,
			setTop: true,
			setHeight: false,
			setWidth: false,
			offsetTop: this.fieldNode.offsetHeight
		});
		if(!this.dirty){
			this.fieldNode.value = "";
		}
		this.onFocus();
	},
	/**
	 * Gestore dell'evento blur, si occupa di chiamare l'hook collegato
	 */
	blurHandler: function(){
		if(this.disabled){ return; }
		this.dirty = this.getValue() !== "";
//		!this.dirty && (this.fieldNode.value = this.promptText);
		if(!this.dirty){
            this.fieldNode.value = this.promptText;
        }else{
            this.autocompleter.active && this.autocompleter.selectEntry();
        }
		this.onBlur();
	},
	/**
	 * Gestore dell'evento "onkeyup": mostra il nodo closer nel caso in cui ci sia almeno un carattere nel campo di
	 * testo, altrimenti lo nasconde
	 */
	keyupHandler: function(){
		this.closerNode.className = this.fieldNode.value.length ? "ta_cleanAirport" : "ta_cleanAirport_hidden";
	},
	// methods
	/**
	 * Si occupa di collegare i gestori degli eventi onblur, onclick, onkeyop e onfocus
	 */
	bindEvents: function(){
		Event.observe(this.fieldNode, 'blur', this.blurHandler.bindAsEventListener(this), false);
		Event.observe(this.fieldNode, 'focus', this.focusHandler.bindAsEventListener(this));
		Event.observe(this.fieldNode, 'keyup', this.keyupHandler.bindAsEventListener(this), false);
		Event.observe(this.closerNode, 'click', this.closeHandler.bindAsEventListener(this), false);
	},
	/**
	 * Disconnessione degli eventi: da implementare
	 */
	unbindEvents: function(){
		// todo
	},
	/**
	 * Si occupa di "congelare" il campo di testo: lo rende sola lettura e ne cambia lo stile in modo da distinguerlo
	 * da quelli liberi. Duale del metodo {@link ch.exmachina.bravofly.RichField#unfreeze}
	 */
	freeze: function(){
		var fnode = this.fieldNode;
		fnode.addClassName("fixed");
		this.disable();
		this.closerNode.className = "ta_cleanAirport";
		this.onFreeze();
	},
	/**
	 * Rende di nuovo il campo di testo scrivibile, modificandone anche l'aspetto. Duale
	 * di {@link ch.exmachina.bravofly.RichField#freeze}
	 */
	unfreeze: function(){
		var fnode = this.fieldNode;
		fnode.removeClassName("fixed");
		this.enable();
		this.onUnfreeze();
//		this.closerNode.className = "ta_cleanAirport_hidden";
	},
	/**
	 * Metodo che informa sullo stato di "congelamento" (= bloccato e valido) del campo di testo
	 * @returns {Boolean}
	 */
	isFreezed: function(){
		return this.disabled;
	},
	/**
	 * Disabilita il field corrente
	 * @see ch.exmachina.bravofly.RichField#enable
	 */
	disable: function(){
		this.fieldNode.disabled = true;
		this.disabled = true;
	},
	/**
	 * Abilita il field corrente
	 * @see ch.exmachina.bravofly.RichField#disable
	 */
	enable: function(){
		this.fieldNode.disabled = false;
		this.disabled = false;
	},
	/**
	 * Distrugge il campo corrente, rimuovendolo da DOM
	 */
	destroy: function(){
		this.unbindEvents();
		this.pNode.removeChild(this.domNode);
	},
	/**
	 * Svuota il campo corrente, eseguendo una unfreeze e riportando il flag dirty a false
	 */
	clean: function(){
		this.fieldNode.value = this.promptText;
		this.dirty = false;
		this.closerNode.className = "ta_cleanAirport_hidden";
		this.unfreeze();
		this.onClean();
	},
	/**
	 * Restituisce soltanto il nome della classe corrente, aggiungere informazioni utili per il debug
	 */
	toString: function(){
		return "[ch.exmachina.bravofly.RichField]";
	}
};

