// warning: actual implementation can't handle getKey when there are
// identical values (the first key is returned)
if(!ch){
	var ch = {};
}
if(!ch.exmachina){
	ch.exmachina = {};
}
if(!ch.exmachina.bravofly){
	ch.exmachina.bravofly = {};
}
/**
 * @constructor
 * @description Select con aspetto personalizzato, con uno slider custom per far scorrere la lista delle opzioni
 * @param {Object} ctorArgs
 */
ch.exmachina.bravofly.ComplexSelect = function(/* object */ctorArgs){
    ch.exmachina.bravofly.ComplexSelect.baseConstructor.call(this, ctorArgs);
	Element.setStyle(this.listNode,{
		width: parseInt(Element.getStyle(this.selectFieldNode, "width")) - 5 + "px"
	});
    this.makeSlider({
        height: 200,
        width: 10
    });
};

ch.exmachina.bravofly.inherits(ch.exmachina.bravofly.ComplexSelect,
        ch.exmachina.bravofly.Select);


/**
 * @description Template del nodo che fa da slider
 */
ch.exmachina.bravofly.ComplexSelect.prototype.sliderTemplate = "<div class='slider'></div>";
/**
 * @type {Object}
 * @description Oggetto di tipo Control.Slider (scriptaculous) agganciato alla lista dei risultati
 */
ch.exmachina.bravofly.ComplexSelect.prototype.slider = null;
ch.exmachina.bravofly.ComplexSelect.prototype.innerHeight = 0;

// dipende dalle dimensioni dell'handle
/**
 * @type {Number}
 * @description Parametro di valore massimo da passare al costruttore
 * di Control.Slider, nell'attributo values
 * @default 178
 * */
ch.exmachina.bravofly.ComplexSelect.prototype.maxVal = 178;
/**
 * @type {String}
 * @description Nome della classe
 * */
ch.exmachina.bravofly.ComplexSelect.prototype.cName = "ComplexSelect";

/**
 * @description Metodo che si occupa di costruire lo slider per questa select
 * @param {Object} args Contiene height e width per il nodo dello slider
 */
ch.exmachina.bravofly.ComplexSelect.prototype.makeSlider = function(args){
    this.sliderNode = new Element("div", {
       'class': 'ta_slider'
    }).update('<div class="ta_slider_handle"><div class="ta_sliderHead"></div><div class="ta_sliderBody"></div><div class="ta_sliderFoot"></div>');
    this.sliderNode.setStyle({
        height: args.height + "px",
        width: args.width + "px",
        top: "19px",
        zIndex: "200",
        display: "none"
     });
    
    //IE9 prototype fix
    this.sliderNode.setAttribute("class", "ta_slider");

    Element.insert(this.domNode, this.sliderNode);
    var self = this;
    this.slider = new Control.Slider(this.sliderNode.down(".ta_slider_handle"), this.sliderNode,{
        range: $R(0, 200),
        axis: "vertical",
        values: $R(0, this.maxVal),
        maximum: 100,
        minimum: 20,
        onSlide: function(value){
            self.listNode.scrollTop = (self.listNode.scrollHeight - 200) * value / self.slider.allowedValues.max();//self.maxVal;
	        ch.exmachina.bravofly.ComplexSelect._dragging = true;
        },
	    onChange: function(value){
	        self.listNode.scrollTop = (self.listNode.scrollHeight - 200) * value / self.slider.allowedValues.max();//self.maxVal;
	    }

    });
};

/**
 * @description Metodo che provvede ad agganciare i gestori agli eventi per questa ComplexSelect; si occupa inoltre
 * di invocare il metodo omonimo nella classe padre, in modo che siano gestiti anche gli eventi da essa previsti
 */
ch.exmachina.bravofly.ComplexSelect.prototype.bindEvents = function(){
	ch.exmachina.bravofly.ComplexSelect.superClass.bindEvents.call(this);
	Event.observe(this.listNode, "mousewheel", this.scrollHandler.bindAsEventListener(this));
	Event.observe(window, "DOMMouseScroll", this.scrollHandler.bindAsEventListener(this));
};
/**
 * @description Gestore dell'evento onScroll
 * @param {Event} evt Evento per questo handler
 */
ch.exmachina.bravofly.ComplexSelect.prototype.scrollHandler = function(evt){
	var trg = evt.target,
		list = trg.parentNode ? trg.parentNode.parentNode : null,
		delta
	;
	if(!list || list != this.listNode){
		return true;
	}
	delta = evt.wheelDelta ? -evt.wheelDelta / 12 : evt.detail / 3;

	this.listNode.scrollTop += delta*20;
	this.updateHandlerPosition();
	evt.stopPropagation();
	evt.preventDefault && evt.preventDefault();
	evt.returnValue = false; // IE
	return false;
//	console.log("delta: " + delta);
	
//	console.log("[mousewheel] target = " + trg);
};
/**
 * @description Si occupa di gestire lo scroll verticale del nodo della lista delle opzioni, poi procedere a invocare
 * la fillInData della classe parent.
 * @see ch.exmachina.bravofly.Select#fillInData
 * @param {Object} args
 */
ch.exmachina.bravofly.ComplexSelect.prototype.fillInData = function(args){
	this.listNode.setStyle({
		height: "auto"
	});
	this.listNode.scrollTop = 0;
	this.slider.handles[0].style.top = "0";
	ch.exmachina.bravofly.ComplexSelect.superClass.fillInData.call(this, args);
	this.setListStyle();
};
/**
 * @description Imposta lo stile del nodo della lista di opzioni in modo che, superati i 200 px, possa essere nascosto
 * lo slider nativo
 */
ch.exmachina.bravofly.ComplexSelect.prototype.setListStyle = function(){
    if(this.listNode.getHeight() > 200){
        this.listNode.setStyle({
            height: "200px",
            overflow: "hidden"
        });
    }
};
/**
 * @description Crea il nodo contenente la lista - usando la chiamata della classe Select - quindi invoca la {@link ch.exmachina.bravofly.ComplexSelect#setListStyle}
 */
ch.exmachina.bravofly.ComplexSelect.prototype.createList = function(){
   ch.exmachina.bravofly.ComplexSelect.superClass.createList.call(this);
	this.setListStyle();
};
/**
 * @description Imposta l'altezza del nodo DOM dello slider (sliderNode) in base al numero di opzioni presenti nella
 * lista
 */
ch.exmachina.bravofly.ComplexSelect.prototype.normalizeSliderDim = function(args){
	var ratio = 200 / this.listNode.scrollHeight,
		h = parseInt(200*ratio)
	;
	!isNaN(h) && this.sliderNode.firstChild.setStyle({
		height: (h - 4 - 10) + "px"
	});
	this.slider.allowedValues = $R(0, 200 - h).sortBy(Prototype.K);
};
/**
 * @description mostra e nasconde lo slider
 */
ch.exmachina.bravofly.ComplexSelect.prototype.toggleSlider = function(){
	var dis = this.sliderNode.style.display === "none" ? "block" : "none",
		mustShow = this.listNode.getHeight() >= 200 && dis === "block";
	mustShow && this.setListStyle();
	if(dis === "none" || mustShow){
		this.normalizeSliderDim();
		this.sliderNode.setStyle({
			display: dis
		});
	}
};
/**
 * @description Evidenzia l'opzione che si trova all'indice dato; rispetto alla implementazione nella classe Select,
 * si occupa anche di spostare lo scroll della lista in modo che l'opzione evidenziata si trovi all'interno della
 * porzione visibile del nodo
 * @param {Number} index L'indice dell'opzione da evidenziare
 */
ch.exmachina.bravofly.ComplexSelect.prototype.highlightOptionIndex = function(/** Number */ index){
	ch.exmachina.bravofly.ComplexSelect.superClass.highlightOptionIndex.call(this, index);
	var idx = this.selectedIndex,
		offset = Element.positionedOffset(this.options[idx])[1],
		h = Element.getHeight(this.options[idx])
	;
	if(offset > this.listNode.scrollTop + 200 - h){
		this.listNode.scrollTop = offset - 200 + h;
	}else if(offset < this.listNode.scrollTop){
		this.listNode.scrollTop = offset;
	}
	this.updateHandlerPosition();
};
/**
 * @description Aggiusta la posizione dell'handler in base a quella effettiva del nodo contenente la lista
 */
ch.exmachina.bravofly.ComplexSelect.prototype.updateHandlerPosition = function(){
	this.slider.handles[0].style.top = (this.listNode.scrollTop / this.listNode.scrollHeight * 200) + "px";
};

/**
 * @description Mostra e nasconde la lista di opzioni. Si limita a chiamare l'omologa funzione della classe parent e
 * in seguito esegue la stessa azione sul nodo slider
 * @param {Event} evt Evento
 */
ch.exmachina.bravofly.ComplexSelect.prototype.toggleList = function(evt){
	ch.exmachina.bravofly.ComplexSelect.superClass.toggleList.apply(this, arguments);
	this.toggleSlider();
};
/**
 * @description Mostra la lista di opzioni e lo slider collegato
 */
ch.exmachina.bravofly.ComplexSelect.prototype.showList = function(){
    ch.exmachina.bravofly.ComplexSelect.superClass.showList.call(this);
    this.sliderNode && this.sliderNode.setStyle({
        display: "block"
    });
};
/**
 * @description Nasconde la lista di opzioni e lo slider collegato
 */
ch.exmachina.bravofly.ComplexSelect.prototype.hideList = function(){
    ch.exmachina.bravofly.ComplexSelect.superClass.hideList.call(this);
    this.sliderNode && this.sliderNode.setStyle({
        display: "none"
    });
};
/**
 * @description Gestore della mouseover, evidenzia l'opzione che si trova sotto il puntatore
 * @param {Event} evt Evento
 */
ch.exmachina.bravofly.ComplexSelect.prototype.hilightOption = function(evt){
	if(ch.exmachina.bravofly.ComplexSelect._dragging){ return; }
	ch.exmachina.bravofly.ComplexSelect.superClass.hilightOption.call(this, evt);

};
/**
 * @returns La stringa contenente la classe corrente, key e value dell'opzione selezionata
 */
ch.exmachina.bravofly.ComplexSelect.prototype.toString = function(){
    return "[ch.exmachina.bravofly.ComplexSelect] key = " + this.getKey() + "; value = " + this.getValue();
};

// static objects

ch.exmachina.bravofly.ComplexSelect._instances = [];
ch.exmachina.bravofly.ComplexSelect._dragging = false;


ch.exmachina.bravofly.ComplexSelect.blurHandler = function(evt){
    var _inst = ch.exmachina.bravofly.ComplexSelect._instances,
        trg = evt.target
    ;
    // IE pNode hack. find a better way asap
    for(var i = 0; i < _inst.length; i++){
        (ch.exmachina.bravofly.ComplexSelect.events["open"] != _inst[i]) &&
        _inst[i].pNode != trg &&  trg != _inst[i].sliderNode && trg != _inst[i].slider.handles[0].firstChild.nextSibling && _inst[i].hideList();

    }
    if(ch.exmachina.bravofly.ComplexSelect.events["open"]){
        ch.exmachina.bravofly.ComplexSelect.events["open"] = null;
    }
};

ch.exmachina.bravofly.ComplexSelect.mouseUpHandler = function(evt){
	ch.exmachina.bravofly.ComplexSelect._dragging = false;
};




ch.exmachina.bravofly.ComplexSelect.events = {};
Event.observe(document, "click", ch.exmachina.bravofly.ComplexSelect.blurHandler);
Event.observe(document, "mouseup", ch.exmachina.bravofly.ComplexSelect.mouseUpHandler);
