
var Replacement = Class.create(
{
	inputs	: null,

	type	: '',

	options	:
	{
		hoverClass	: 'jsui_hover',
		activeClass	: 'jsui_active'
	},

	initialize: function( options )
	{
		this.options = options;

		// apply all default settings if not stated otherwise
		if( !this.options.onReplaced )	this.options.onReplaced		= function() {};
		if( !this.options.onMouseover )	this.options.onMouseover	= function() {};
		if( !this.options.onMouseout )	this.options.onMouseout		= function() {};

		if( !this.options.hoverClass )	this.options.hoverClass = 'jsui_hover';
		if( !this.options.activeClass )	this.options.activeClass= 'jsui_active';


		this.inputs = new Array();
		this.replace();
	},


	// [PUBLIC]
	replace: function()
	{
		if( typeof this.options.type != 'undefined' )
		{
			this.type = this.options.type;
		}

		$$( '.' + this.type ).each
		(
			function( el, index )
			{
				// remove square brackets etc (everything that would cause the selector to not match properly)
				var id = this.type + '_' + el.readAttribute( 'name' ).replace( /[^a-zA-Z 0-9]+/g, '' );

				// create a input field in case none has been created yet
				if( typeof this.inputs[id] == 'undefined' )
				{
					this.createInput( el, id );
				}

				// get the replacement for the actual input and ..
				var container = this.createReplacement( el, id );

				// .. use it instead of the old ui element
				Element.replace( el, container );

				// finally let everyone we are done
				this.options.onReplaced( container );
			},
			this
		);
	},

	// [PRIVATE] - create a hidden input field for each coherent group of inputs (regardless of their type)
	createInput: function( el, identifier )
	{
		var hidden = new Element
		(
			'input',
			{
				'type'	: 'hidden',
				'name'	: el.readAttribute( 'name' ),
				'value'	: ''
			}
		);

		this.inputs[identifier] = hidden;
		el.up( 0 ).insert( this.inputs[identifier] );
	},

	// [PROTECTED] - abstract method
	createReplacement: function() {}
});


var Select_Replacement = Class.create( Replacement,
{
	// [PROTECTED] - we are dealing with <select>'s here
	type: 'select',

	// [PUBLIC] - defineable member attributes
	options:
	{
		selectedClass: 'jsui_selected',
		defaultCaption: ''
	},

	// [PROTECTED] - special replacement method for <select>'s
	createReplacement: function( el, identifier )
	{
		if( !this.options.onSelected ) this.options.onSelected = function() {};
		if( !this.options.selectedClass ) this.options.selectedClass = 'jsui_selected';

		var replacer = this;
		el.removeClassName( this.type );

		// create a wrapper for the new list
		var container = new Element
		(
			'div',
			{
				'id': el.readAttribute( 'id' ),
				'class': this.type + ' ' + identifier
			}
		);

		// check for the selected="selected" attribute and adopt it
		var selected_option = null;

		el.childElements().each
		(
			function( option )
			{
				if( option.readAttribute( 'selected' ) == 'selected' )
				{
					selected_option = option;
					return;
				}
			}
		);

		if( selected_option != null )
		{
			this.options.defaultCaption = selected_option.innerHTML;
			this.inputs[identifier].writeAttribute( 'value', selected_option.readAttribute( 'value' ) );
		}

		// the actual select field. holds the currently active value and is styled by CSS
		var selected = new Element
		(
			'div',
			{
				'class'	: 'jsui_input'
			}
		)
		.update( this.options.defaultCaption );

		selected.observe
		(
			'click',
			function( e )
			{
				// check whether the list is already shown and supposed to be closed or vice versa
				if( this.hasClassName( replacer.options.activeClass ) )
				{
					this.removeClassName( replacer.options.activeClass );
				}
				else
				{
					this.addClassName( replacer.options.activeClass );
				}

				this.next().toggleClassName( 'hide' );
			}
		);

		// insert the select field into the wrapper
		container.insert( selected );

		// create the acutal options-list
		var list = new Element
		(
			'ol',
			{
				'class': 'hide'
			}
		)
		.setStyle({ 'position': 'absolute' });

		// use all specifications from the old one and morph 'em to list-items
		el.childElements().each
		(
			function( opt, index )
			{
				list.insert( new Element
				(
					'li',
					{
						'class'		: ( opt.readAttribute( 'selected' ) ? 'selected' : '' ),
						'jsui_value': opt.readAttribute( 'value' )
					}
				)
				.update
				(
					( opt.innerHTML.length > 0 ) ? opt.innerHTML : '&nbsp;'
				)
				.observe
				(
					'click', function( e )
					{
						// trigger all registered listeners
						replacer.options.onSelected( this, this.readAttribute( 'jsui_value' ), this.innerHTML );


						// store the selected value hidden and ..
						replacer.inputs[identifier].writeAttribute( 'value', this.readAttribute( 'jsui_value' ) );

						// .. visible within the list-heading and ..
						selected.update( this.innerHTML );

						// .. highlight the selected list-item within the list
						list.childElements().each
						(
							function( el )
							{
								el.removeClassName( replacer.options.selectedClass );
							}
						);

						this.addClassName( replacer.options.selectedClass );

						// finally de-active the new list-heading and hide the list
						selected.removeClassName( replacer.options.activeClass );
						list.addClassName( 'hide' );
					}
				)
				.observe
				(
					'mouseover', function( e )
					{
						// trigger all registered listeners
						replacer.options.onMouseover( this, this.readAttribute( 'jsui_value' ), this.innerHTML );

						this.toggleClassName( replacer.options.hoverClass );
					}
				)
				.observe
				(
					'mouseout', function( e )
					{
						// trigger all registered listeners
						replacer.options.onMouseout( this, this.readAttribute( 'jsui_value' ), this.innerHTML );

						this.toggleClassName( replacer.options.hoverClass );
					}
				));
			}
		);

		// insert the wohle options-list into the wrapper
		return container.insert( list );
	},

	// [PUBLIC] - abstract method
	onSelected: function() {}
});



var Checkbox_Replacement = Class.create( Replacement,
{
	type: 'checkbox',

	options:
	{
		checkedClass: 'jsui_checked'
	},

	createReplacement: function( el, identifier )
	{
		if( !this.options.onChecked ) this.options.onChecked = function() {};
		if( !this.options.checkedClass ) this.options.checkedClass = 'jsui_checked';


		var replacer = this;
		el.removeClassName( this.type );


		// create the replacement for the current input
		var container = new Element
		(
			'div',
			{
				'id'			: el.readAttribute( 'id' ),
				'class'			: this.type + ' ' + identifier,
				'jsui_value'	: el.readAttribute( 'value' )
			}
		)
		.insert
		(
			new Element
			(
				'div'
			)
			.observe
			(
				'click', function( e )
				{
					// trigger all registered listeners
					replacer.options.onChecked( this, this.up( 0 ).readAttribute( 'jsui_value' ) );

					this.toggleClassName( replacer.options.checkedClass );

					// store the selected value in the hidden input
					replacer.inputs[identifier].writeAttribute( 'value', this.up( 0 ).readAttribute( 'jsui_value' ) );
				}
			)
			.observer
			(
				'mouseover', function( e )
				{
					// trigger all registered listeners
					replacer.options.onMouseover( this, this.up( 0 ).readAttribute( 'jsui_value' ) );

					this.toggleClassName( replacer.options.hoverClass );
				}
			)
			.observe
			(
				'mouseout', function( e )
				{
					// trigger all registered listeners
					replacer.options.onMouseout( this, this.up( 0 ).readAttribute( 'jsui_value' ) );

					this.toggleClassName( replacer.options.hoverClass );
				}
			)
		);


		// in case the checkbox we are about to replace is already checked, 'check' our replacement an store the currently selected value
		if( el.readAttribute( 'checked' ) == 'checked' )
		{
			container.down( 0 ).addClassName( this.options.checkedClass );
			this.inputs[identifier].writeAttribute( 'value', container.readAttribute( 'jsui_value' ) );
		}

		// insert the new checkbox into the DOM
		return container;
	},

	// [PUBLIC] - abstract method
	onChecked: function() {}
});



var Radio_Replacement = Class.create( Replacement,
{
	type: 'radio',

	options:
	{
		checkedClass: 'jsui_checked'
	},

	createReplacement: function( el, identifier )
	{
		if( !this.options.onChecked ) this.options.onChecked = function() {};
		if( !this.options.checkedClass ) this.options.checkedClass = 'jsui_checked';

		var replacer = this;
		el.removeClassName( this.type );


		// create the replacement for the current input
		var container = new Element
		(
			'div',
			{
				'id'			: el.readAttribute( 'id' ),
				'class'			: this.type + ' ' + identifier,
				'jsui_value'	: el.readAttribute( 'value' ),
				'jsui_caption'	: el.readAttribute( 'title' )
			}
		)
		.insert
		(
			new Element
			(
				'div',
				{
					'class'	: el.readAttribute( 'class' )
				}
			)
			.observe
			(
				'click', function( e )
				{
					// trigger all registered listeners
					replacer.options.onChecked( this, this.up( 0 ).readAttribute( 'jsui_value' ), this.up( 0 ).readAttribute( 'jsui_caption' ) );

					$$( '.' + identifier + ' div' ).each
					(
						function( el )
						{
							el.removeClassName( replacer.options.checkedClass );
						}
					);

					this.addClassName( replacer.options.checkedClass );

					// store the selected value in the hidden input
					replacer.inputs[identifier].writeAttribute( 'value', this.up( 0 ).readAttribute( 'jsui_value' ) );
				}
			)
			.observe
			(
				'mouseover', function( e )
				{
					// trigger all registered listeners
					replacer.options.onMouseover( this, this.up( 0 ).readAttribute( 'jsui_value' ), this.up( 0 ).readAttribute( 'jsui_caption' ) );

					this.toggleClassName( replacer.options.hoverClass );
				}
			)
			.observe
			(
				'mouseout', function( e )
				{
					// trigger all registered listeners
					replacer.options.onMouseout( this, this.up( 0 ).readAttribute( 'jsui_value' ), this.up( 0 ).readAttribute( 'jsui_caption' ) );

					this.toggleClassName( replacer.options.hoverClass );
				}
			)
		);

		// in case the checkbox we are about to replace is already checked, 'check' our replacement an store the currently selected value
		if( el.readAttribute( 'checked' ) == 'checked' )
		{
			container.down( 0 ).addClassName( this.options.checkedClass );
			this.inputs[identifier].writeAttribute( 'value', container.readAttribute( 'jsui_value' ) );
		}

		// insert the new checkbox into the DOM
		return container;
	},

	// [PUBLIC] - abstract method
	onChecked: function() {}
});
