var Select = Class.create(
{
	initialize: function(inElement, inOptions)
	{
		this.element = $(inElement);
		
		if(!this.element)
		{
			return;
		}
		
		this.options = {
			select: 'selectable',
			selectClass: 'selected',
			simple: false,
			multiple: true,
			selected: [],
			onSelect: null,
			onUnselect: null,
			onClick: null,
			onDoubleClick: null
		};
		
		Object.extend(this.options, inOptions);
		
		this.element.selected = this.getSelected.bind(this);
		
		this.element.selectElement = this.selectElement.bind(this);
		
		this.element.toggleAll = this.toggleAll.bind(this);
		
		this.selected = [];
		
		// -------
		
		var selectedID = "selected_" + this.element.identify();
		
		this.selectedElement = $(selectedID);
		
		if(!this.selectedElement)
		{
			this.selectedElement = this.element.insert({before: "<input type='hidden' name='" + selectedID + "'>"}).previous();
		}

		// -------
		
		var selectable = this.getSelectable();
		
		for(var i = 0; i < selectable.length; i++)
		{
			selectable[i].observe('mousedown', this.mousedown.bindAsEventListener(this));
			
			if(this.options.onDoubleClick)
			{
				selectable[i].observe('dblclick', this.dblclick.bindAsEventListener(this));
			}
			
			if(this.options.onClick)
			{
				selectable[i].observe('click', this.click.bindAsEventListener(this));
			}
		
			this.setSelected(selectable[i], this.options.selected.indexOf(selectable[i].identify()) >= 0);
		}
		
		this.element.observe('behavior:update', this.update.bindAsEventListener(this));

		this.update();
	},
	
	selectElement: function(inElement, inState) {
		
		this.setSelected(inElement, inState);
		
		this.update();
		
		document.fire('behavior:change');
	},
	
	toggleAll: function()
	{
		var selectable = this.getSelectable();
		
		var selected = this.getSelected();
		
		var state = !(selectable.length == selected.length);
		
		for(var i = 0; i < selectable.length; i++)
		{
			this.setSelected(selectable[i], state);
		}
		
		this.update();
	},
	
	getSelectable: function()
	{
		this.selectable = this.element.select('.' + this.options.select);
			
		if(this.selectable.length == 0)
		{
			this.selectable[0] = this.element;
		}
		
		for(var i = 0; i < this.selectable.length; i++)
		{
			this.selectable[i].position = i;
		}
		
		return this.selectable;
	},
	
	getSelected: function(inTrim)
	{
		if(inTrim)
		{
			var name = this.element.identify();
			var results = new Array(length);
			var length = this.selected.length;
			
			while(length--)
			{
				results[length] = this.selected[length]
				
				if(results[length].startsWith(name))
				{
					results[length] = results[length].substring(name.length + 1);
				}
			}
			
			return results;
		}
		
		return this.selected;
	},
	
	setSelected: function(inElement, inSelected)
	{
		if(inElement)
		{
			if(inSelected)
			{
				if(this.options.selectClass)
				{
					inElement.addClassName(this.options.selectClass);
				}

				if(this.options.onSelect)
				{
					this.options.onSelect(inElement);
				}
				
				return true;
			}
			else
			{
				inElement.removeClassName(this.options.selectClass);
				
				if(this.options.onUnselect)
				{
					this.options.onUnselect(inElement);
				}
				
				return false;
			}
		}
	},
	
	update: function()
	{
		var selectable = this.getSelectable();
			
		this.selected = [];
		
		for(var i = 0; i < selectable.length; i++)
		{
			if(selectable[i].hasClassName(this.options.selectClass))
			{
				this.selected.push(selectable[i].identify());
			}
		}
		
		this.selectedElement.value = this.selected.join(",");
	},
	
	selectSingle: function(inEvent, inSelected)
	{
		if(inSelected.hasClassName(this.options.selectClass))
		{
			return;
		}
	
		var selectable = this.getSelectable();
	
		for(var i = 0; i < selectable.length; i++)
		{
			if(selectable[i] == inSelected)
			{
				this.setSelected(selectable[i], true);
		
				this.lastSelection = inSelected;
				
				this.lastState = true;
			}
			else
			{
				this.setSelected(selectable[i], false);
			}
		}
	},
	
	selectMultiple: function(inEvent, inSelected)
	{
		var selectable = this.getSelectable();
	
		if(this.options.simple || inEvent.ctrlKey || inEvent.altKey || inEvent.metaKey)
		{
			for(var i = 0; i < selectable.length; i++)
			{
				if(selectable[i] == inSelected)
				{
					this.lastState = this.setSelected(selectable[i], !selectable[i].hasClassName('selected'));
					
					break;
				}
			}
			
			if(!inEvent.shiftKey)
			{
				this.lastSelection = inSelected;
			}
		}
		
		if(inEvent.shiftKey && this.lastSelection)
		{
			var start = this.lastSelection.position;
			
			var end = inSelected.position;
			
			if(start > end)
			{
				start = inSelected.position;
				
				end = this.lastSelection.position;
			}
			
			for(var i = 0; i < selectable.length; i++)
			{
				if(selectable[i].position >= start && selectable[i].position <= end)
				{
					this.setSelected(selectable[i], this.lastState);
				}
			}
		}
	},
	
	mousedown: function(inEvent)
	{
		var element = inEvent.element();
		
		if(element.hasClassName("input"))
		{
			return;
		}
		
		if(!element.hasClassName(this.options.select))
		{
			element = element.up('.' + this.options.select);
		}

		if(!element)
		{
			return;
		}
		
		Event.stop(inEvent);
		
		var modifierKey = inEvent.shiftKey || inEvent.ctrlKey || inEvent.altKey || inEvent.metaKey;
		
		if(this.options.multiple && ((this.options.simple && !modifierKey) || (!this.options.simple && modifierKey)))
		{
			this.selectMultiple(inEvent, element);
		}
		else
		{
			this.selectSingle(inEvent, element);
		}
		
		this.update();
		
		document.fire('behavior:input');
	},
	
	click: function(inEvent)
	{
		var element = inEvent.element();
		
		if(!element.hasClassName(this.options.select))
		{
			element = element.up('.' + this.options.select);
		}

		if(!element)
		{
			return;
		}
		
		if(element && this.options.onClick)
		{
			this.options.onClick(element, inEvent);
		}
	},
	
	dblclick: function(inEvent)
	{
		var element = inEvent.element();
		
		if(!element.hasClassName(this.options.select))
		{
			element = element.up('.' + this.options.select);
		}

		if(!element)
		{
			return;
		}
		
		if(element && this.options.onDoubleClick)
		{
			this.options.onDoubleClick(element, inEvent);
		}
	}
});