/**
 * ChainedSelect - slick & sexy chained select
 *
 * @version		1.0.1
 *
 * @license		MIT-style license
 * @author		Constantin Boiangiu <constantin [at] php-help.ro>
 * @copyright	Author
 */

var ChainedSelect = new Class({
							  
	Implements: [Options],
	options: {
		element: null, // div element to inject select
		optionsContainer: null, // the id of the element containing all the options
		selectName:null, // the POST/GET variable name
		selectedValue: null, // the value of the select in page refreshed or you want a default selected value
		selectedMessage: null, // the elected option name if page refreshed and option keeped
		defaultMessage: 'Choisir une option', // default message displayed
		navHome: 'Cliquez sur la fl&eacute;che',
		optionsURL: null, // the url from where the script gets the JSON string
		fromTop: 15, // distance from top
		keepSelection: false, // when set, after making a selection, it will keep it active is clicked again
		displayHistory: false // if set, after making a selection it will display the full path to it
	},

	initialize: function(options) {
		this.setOptions(options);
		if(!this.options.element || !this.options.optionsContainer) return;
		
		this.isVisible = false; // state of select
		this.currentKey = 0; // stores the current parent id
		this.history = new Array(); // stores all parent ids clicked
		this.historyPath = [];
		this.container = $(this.options.element);
		this.start();
	},
	
	start: function(){
		this.container.set({'html':this.options.selectedMessage||this.options.defaultMessage, 'class':this.options.element});
		this.inject();
				
		this.listEffect = new Fx.Morph(this.listContainer, {duration: 600, wait:false, transition: Fx.Transitions.Sine.easeOut});
		this.wrapEffect = new Fx.Morph(this.wrapper, {duration: 600, wait:false, transition: Fx.Transitions.Sine.easeOut});
		/* event on container click */
		this.container.addEvent('click', this.getOptions.bind(this));		
	},
	
	inject: function(){
		/* an input[type=hidden] to hold the selection */
		this.selectedOption = new Element('input', {
			'type': 'hidden',
			'name': this.options.selectName,
			'value': this.options.selectedValue
		}).injectAfter(this.container);		
		/* the options container */
		this.listContainer = new Element('div',{
			'id':this.options.optionsContainer,
			'styles':{
				'position':'absolute',
				'opacity':0,
				'z-index':100000
			}
		}).injectInside(document.body);
		new Element('div',{
			'class':'pointer',
			'html':'<!--design purposes-->'
		}).injectInside(this.listContainer);
		/* top navigator to enable back */
		this.navigator = new Element('div',{
			'class':'navigator'
		}).injectInside(this.listContainer);
		/* current category holder */
		this.title = new Element('span',{
			'class':'title'
		}).injectInside(this.navigator);
		/* the return link */
		this.returnLink = new Element('a',{
			'class':'returnLink',
			'href':'#',
			'styles':{
				'display':'none'
			}
		}).injectInside(this.navigator).addEvent('click', this.goBack.bind(this));
		/* entries wrapper */
		this.wrapper = new Element('div',{
			'class':'scrollWrapper'
		}).injectInside(this.listContainer);
	},
	
	getOptions: function(){
		if ( this.isVisible ) { 
			this.hideList();
			return;			
		}else this.showList();
		
		$defined( this.responseResult ) ? this.populateList() : this.makeRequest();
	},
	
	showList: function(){
		var position = this.container.getCoordinates();
		this.listContainer.set({
			'styles':{
				'top':position['top'] + position['height']+this.options.fromTop, 
				'left':position['left'],
				'display':'block'
			}			
		});
		this.listEffect.start({'opacity':1});
		this.isVisible = true;
	},
	
	hideList: function(){
		this.listEffect.start({'opacity':0}).chain(function(){ 
			this.listContainer.setStyle('display','none'); 
			if(!this.options.keepSelection){
				this.currentKey = 0;
				this.history.empty();
				$clear(this.previousKey);
				this.returnLink.setStyle('display','none');
				this.populateList();
			}
		}.bind(this));
		
		this.isVisible = false;
	},
	
	populateList: function(){
		if( $defined(this.previousKey) && this.previousKey == this.currentKey && this.options.keepSelection ) return;
		
		this.wrapper.empty();
		/* add navigatioon back home */
		if( this.currentKey == 0 && this.history.length == 0 ){
			this.historyLink(this.options.navHome,0);
		}	
		/* list current items */
		var items = new Hash(this.responseResult.get(this.currentKey));
		items.map(function(value, key){
			this.makeEntry(value, key);
			if(this.responseResult.get(key))
				this.addNavigation(value, key);			
		}.bind(this));
		this.wrapEffect.start({'opacity':[0,1]});
	},
	
	makeEntry: function(text, id){
		new Element('div',{
			'class':'entry',
			'text':text,
			'id':'key_'+id
		}).injectInside(this.wrapper).addEvent('click', function(event){
			this.hideList();
			this.selectedOption.set({'value':id});
			
			if( this.options.displayHistory ){
				this.setPath(id);
				text = '';
				for( var l = this.historyPath.length-1; l>=0; l-- ){
					text +=  this.historyPath[l]+( l>0?' - ' : '' );
				}
				this.historyPath.empty();
			}
			
			this.container.set({'html':text});
		}.bind(this));
	},
	
	setPath: function(selectedIndex){
		
		this.responseResult.map(function(el, key){
			var h = new Hash(this.responseResult.get(key));
			if(h.has(selectedIndex))
			{
				this.historyPath.push(h.get(selectedIndex));
				this.setPath(key);
			}
		}.bind(this))
		
	},
	
	addNavigation: function(value, id){
		var link = new Element('a',{
						'class':'nav',
						'href':'#'
					}).injectInside($('key_'+id));
		link.addEvent('click', function(event){
			new Event(event).stop();
			this.setCurrentKey(id);
			this.returnLink.setStyle('display','block');
			this.populateList();
			this.historyLink(value, id);			
		}.bind(this));
	},
	
	historyLink: function(value, key){
		/* if function called then link was clicked so add key to history array */
		this.history.include(key);
		this.title.set({'html':value});			
	},
	
	goBack: function(event){
		new Event(event).stop();
		/* erase last entry from history */
		this.history.erase(this.currentKey);
		/* set currentKey and previousKey */
		this.currentKey = $defined(this.previousKey) ? this.previousKey : 0;
		var prevIndex = this.history.indexOf(this.previousKey);		
		this.previousKey = prevIndex <= 0 ? null : this.history[prevIndex-1];		
		/* disable back if on first panel */
		if( this.currentKey == 0 ){
			this.returnLink.setStyle('display','none');
		}
		/* update the title */
		this.title.set({'html': this.responseResult[this.previousKey || 0][this.currentKey] || this.options.navHome });
		/* populate the list */
		this.populateList();
	},
	
	setCurrentKey: function(key){
		this.previousKey = this.currentKey;
		this.currentKey = key;
	},
	
	makeRequest: function(){
		this.listContainer.addClass('loading');
		var jsonRequest = new Request.JSON({
			url: this.options.optionsURL, 
			onComplete: function(response){
				this.responseResult = new Hash(response);
				this.listContainer.removeClass('loading');
				this.populateList();
			}.bind(this)
		}).get();	
	}
	
});
