/*
 * StyleSelect
 * An additional layer to style selects however you like
 * 
 * @author Kirk Bushell
 * @date 20/08/2008
 */
var openCont = '';
var WFStyleSelect = Class.create();
WFStyleSelect.prototype = {

	selects: '',
	selectId: '',
	ids: [],
	currentId: 0,
	pubVar: '',
	itemCallback: '',
	idSuffix: '-styleIt',
	
	/*
	 * @param string pubVar Publicly accessible variable that will be used for referencing the instance
	 * @param string select Not necessary, but useful if you want to style just one select, not all selects on a page
	 * @param string itemCallback Name of the function to be called when an item is selected. Function will be passed an array of elements: the id of the current selected drop-down (id), the option's selected text and value (optionText/optionValue), as well as the public variable (pubVar)
	 */
	initialize: function( pubVar, select, itemCallback ) {
		this.pubVar = pubVar;
		this.itemCallback = itemCallback;
		this.selectId = select;
		
		if (select) {
			// user is wanting to generate only the one select drop-down
			this.selects = new Array($(select));
		}
		else {
			this.selects = $$('select.styleIt');
		}
		
		this.ids = new Array();
		for (var i = 0; i < this.selects.length; i++) {
			select = this.selects[i];
			if (select != null) {
				var c = this._createContainer(select, this._getClasses(select));
				select.replace(c);
			}
		}
	},
	
	toggleSelect: function( id ) {
		// open the div that is hidden
		var c = $( 'SSI' + id );
		var shown = c.getStyle('display');
		var cid = 'SSC' + id;
		var pos = this._findPos( $( cid ) );
		
		if (shown == 'none' || !shown) {
			c.show();
			openCont = 'SSI' + id;
		}
		else {
			c.hide();
			openCont = '';
		}
		c.setStyle( { position: 'absolute', top: pos[1] + 'px', left: pos[0] + 'px' } );
	},
	/*
 	 * select
 	 * For selecting individual items within the stylised select box
 	 * @param id
 	 * @param option
 	 */
	select: function( id, option ) {
		var selected = this.selects[this.ids.indexOf(id)].options[option];
		$('SSC' + id).firstDescendant().update( selected.text );
		this.toggleSelect( id );
		$('SSV' + id).writeAttribute('value', selected.value);
		
		if (this.itemCallback) {
			var callBackArray = { id: id, pubVar: this.pubVar, optionText: selected.text, optionValue: selected.value, select: this.selectId };
			eval(this.itemCallback + "(callBackArray)" );
		}
	},
	
	/* Creates the drop-down container, also stores the selected value */
	_createContainer: function( ele, classes ) {
		// create the child container, and the list items
		this._generateID( ele.readAttribute('name') );
		items = this._createSelectable( ele , classes );
		$(document.body).insert( { top: items} );
		var sOption = this._getSelected(ele);
		
		// new container
		var c = new Element('div');
		classes.each(function( klass ) {
			c.addClassName( klass );
		});
		c.writeAttribute( 'id', 'SSC' + this.currentId );
		c.setStyle( { zIndex: 1000 } );
		var currentId = this.currentId;
		c.observe('click', function(event) { eval(this.pubVar + '.toggleSelect(\'' + currentId + '\');'); Event.stop(event); }.bindAsEventListener(this) );
		c.appendChild( new Element('span').update(sOption[0]) ); // text node
		c.appendChild( new Element('input', { type: 'hidden', value: sOption[1], name: this.selectId, id: 'SSV' + this.currentId } ) ); // text node
		
		// append the children
		
		return c;
	},
	
	/* Creates the popup drop-down */
	_createSelectable: function( ele, classes ) {
		// create the container for the items
		var div = new Element('div');
		div.writeAttribute('id', 'SSI' + this.currentId);
		div.setStyle( { display: 'none', zIndex: 10000 } ); // we set it here so that it's apart of the DOM, as setting it in the CSS means it never enters the DOM
		div.addClassName('style-select-items');
		classes.each(function( klass ) {
			div.addClassName( klass + '-drop-down' );
		});
		
		// create the links
		for (var i = 0; i < ele.options.length; i++) {
			var a = this._createItem( ele.options[i], i );
			div.appendChild( a );
		}
		
		return div;
	},
	
	/* Create the individual select items */
	_createItem: function( option, current ) {
		var option = Element.extend(option);
		
		// if the value of the option is a URL string, then use that for the href value, else assign a non-existent anchor
		var oValue = option.readAttribute('value')
		var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/
   		var ahref = ( regexp.test(oValue) ) ? oValue : 'javascript:void(0);';
		
		var a = new Element( 'a', { href: ahref } ).update( option.text );
		var currentId = this.currentId;
		a.observe('click', function(e) {
			eval(this.pubVar + '.select(\'' + currentId + '\', \'' + current + '\')');
			e.stop(); // stop the event from bubbling up/down 
		}.bindAsEventListener(this));
		return a;
	},
	
	_getClasses: function( ele ) {
		ele.removeClassName( 'styleIt' ); // this is only  used as a flag, not for styling
		return ele.classNames();
	},
	
	_getSelected: function( ele ) {
		for (var i = 0; i < ele.options.length; i++) {
			var o = Element.extend(ele.options[i]);
			if ((o.readAttribute('selected') == 'selected') || (o.readAttribute('selected') == true)) {
				return [o.text, o.value];
			}
		}
		
		// return first value, as none are selected
		if (ele.options[0] != null) {
			return [ele.options[0].text, ele.options[0].value];
		} else {
			return ['', '']; // There is no content
		}
 	},
	
	_generateID: function( name ) {
		//var id = ( Math.floor( Math.random() * 1000 + 0.5 ) );
		var id = name + this.idSuffix;
		this.ids.push( id );
		this.currentId = id;
		return;
	},
	
	_findPos: function( obj ) {
		var curleft = curtop = 0;
		if (obj.offsetParent) {
			do {
				curleft += obj.offsetLeft;
				curtop += obj.offsetTop;
			} while (obj = obj.offsetParent);
			
			return [curleft, curtop];
		}
	}
}
