var Expand = Class.create(
{
	initialize: function(inElement, inOptions)
	{
		this.element = $(inElement);
		
		if(!this.element)
		{
			return;
		}
		
		this.options = {
			select: 'expandable',
			expandedClass: 'expanded',
			collapsedClass: 'collapsed',
			latchClass: 'latch',
			multiple: true,
			required: false,
			latchOnly: false,
			table: false,
			animate: true,
			assumeChildren: true,
			cookie: null,
			expanded: [],
			onExpand: null,
			onCollapse: null
		};
	
		Object.extend(this.options, inOptions);
		
		this.element.expanded = this.getExpanded.bind(this);

		this.expanded = [];
		
		// -------
		
		var expandedID = "expanded_" + this.element.identify();
		
		this.expandedElement = $(expandedID);
		
		if(!this.expandedElement)
		{
			this.expandedElement = this.element.insert({before: "<input type='hidden' name='" + expandedID + "'>"}).previous();
		}

		// -------
		
		if(this.options.cookie)
		{
			this.options.expanded = getCookie(this.options.cookie).split(",");
		}
		
		// -------
	
		var expandable = this.getExpandable();
		
		for(var i = 0; i < expandable.length; i++)
		{
			expandable[i].latch = (expandable[i].select('.' + this.options.latchClass) || []).first();

			if(expandable[i].latch && this.options.latchOnly)
			{
				expandable[i].latch.observe('click', this.click.bindAsEventListener(this));
			}
			else
			{
				expandable[i].observe('click', this.click.bindAsEventListener(this));
			}
			
			expandable[i].child = $(expandable[i].identify() + "_child");
			
			var shouldExpand = this.options.expanded.indexOf(expandable[i].identify()) >= 0;
			
			if(!expandable[i].child && this.options.assumeChildren || (this.options.table && shouldExpand && !this.options.assumeChildren))
			{
				expandable[i].child = expandable[i].next();
			}

			if(this.options.expanded)
			{
				this.setExpanded(expandable[i], shouldExpand, false);
			}
		}
		
		this.update();
		
		if(this.options.required && this.expanded.length != 1)
		{
			for(var i = 0; i < expandable.length; i++)
			{
				this.setExpanded(expandable[i], i == 0, false);
			}
			
			this.update();
		}
	},
	
	getExpandable: function()
	{
		if(!this.expandable)
		{
			this.expandable = this.element.select('.' + this.options.select);
			
			if(this.expandable.length == 0 && !this.options.table)
			{
				this.expandable[0] = this.element;
				this.expandable[0].addClassName(this.options.select);
			}
		}
		
		return this.expandable;
	},
	
	getExpanded: 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;
	},
	
	setExpanded: function(inElement, inExpanded, inAnimate)
	{
		if(inElement)
		{
			if(inExpanded)
			{
				if(inElement.latch)
				{
					inElement.latch.innerHTML = '&#9660;';
				}
				
				if(inElement.child && !inElement.hasClassName(this.options.expandedClass))
				{
					if(inAnimate)
					{
						this.animating = true;
						
						Effect.BlindDown(inElement.child, { duration:0.4, afterFinish: this.doneAnimating.bind(this) });
					}
					else
					{
						inElement.child.setStyle({display:''});
						
						document.fire('behavior:update');
					}
				}
				
				inElement.addClassName(this.options.expandedClass);
				inElement.removeClassName(this.options.collapsedClass);
				
				if(this.options.onExpand)
				{
					this.options.onExpand(inElement, inElement.child);
				}
			
				if(inElement.tagName.toLowerCase() == "input")
				{
					inElement.checked = "checked";
				}
				
				if(!inElement.child)
				{
					this.update();
					
					Forms.submit();
				}
				
				return true;
			}
			else
			{
				if(inElement.latch)
				{
					inElement.latch.innerHTML = '&#9658;';
				}
				
				if(inElement.child && !inElement.hasClassName(this.options.collapsedClass))
				{
					if(inAnimate)
					{
						this.animating = true;
						Effect.BlindUp(inElement.child, { duration:0.4, afterFinish: this.doneAnimating.bind(this)});
					}
					else
					{
						inElement.child.setStyle({display:'none'});
						document.fire('behavior:update');
					}
				}
				
				inElement.addClassName(this.options.collapsedClass);
				inElement.removeClassName(this.options.expandedClass);

				if(this.options.onCollapse)
				{
					this.options.onCollapse(inElement, inElement.child);
				}
				
				if(inElement.tagName == "input")
				{
					inElement.checked = null;
				}
				
				return false;
			}
		}
	},
	
	doneAnimating: function()
	{
		document.fire('behavior:update');
		
		this.animating = false;
	},
	
	update: function()
	{
		var expandable = this.getExpandable();
			
		this.expanded = [];
		
		for(var i = 0; i < expandable.length; i++)
		{
			if(expandable[i].hasClassName(this.options.expandedClass))
			{
				this.expanded.push(expandable[i].identify());
			}
		}
		
		this.expandedElement.value = this.expanded.join(",");
		
		if(this.options.cookie)
		{
			setCookie(this.options.cookie, this.expanded.join(","));
		}
	},
	
	click: function(inEvent)
	{
		if(this.animating)
		{
			return;
		}
		
		var element = inEvent.element();
		
		if(!element.hasClassName(this.options.select))
		{
			element = element.up('.' + this.options.select);
		}

		if(!element)
		{
			return;
		}
	
		if(!this.options.multiple)
		{
			var expandable = this.getExpandable();
		
			for(var i = 0; i < expandable.length; i++)
			{
				if(expandable[i] != element)
				{
					this.setExpanded(expandable[i], false, this.options.animate);
				}
			}
		}
		
		if(this.options.required && element.hasClassName(this.options.expandedClass) && this.expanded.length == 1)
		{
			return;
		}
	
		this.setExpanded(element, element.checked || !element.hasClassName(this.options.expandedClass), this.options.animate);
				
		this.update();
		
		document.fire('behavior:input');
	}
});