// delegate
// dependencies - none

function addDelegate(element, elementEvent, delegate)
{
	// multi-cast delegates are attached to the element as an Array;
	// ie - element['onclickDelegates'], element['onfocusDelegates'], etc
	var elementDelegates = elementEvent + 'Delegates';

	if (element[elementDelegates])
	{
		// there are already multi-cast delegates for this element
		// and this event; add this delegate
		element[elementDelegates].push(delegate);
	}
	else
	{
		// no multi-cast delegates for this element for this event;
		// create a multi-cast delegate list for the element
		element[elementDelegates] = [];

			if (element[elementEvent])
			{
				// this element has a delegate for this event already;
				// preserve the delegate and append it to the list of
				// multi-cast delegates
				element[elementEvent + 'Delegate'] = element[elementEvent];
				element[elementDelegates].push(element[elementEvent]);
			}

		// append the new delegate to the list of multi-cast delegates
		element[elementDelegates].push(delegate);

		// change the event to a function which will fire all
		// multi-cast delegates
		element[elementEvent] = (function() {
		return function()
						{
							for (var ii = 0; ii < this[elementDelegates].length; ++ii)
							{
								this[elementDelegates][ii].call(this);
							}
						}})();
	}
} // addDelegate()


function removeDelegate(element, elementEvent, delegate)
{
	// multi-cast delegates are attached to the element as an Array;
	// ie - element['onclickDelegates'], element['onfocusDelegates'], etc
	var elementDelegates = elementEvent + 'Delegates';

	if (element[elementDelegates])
	{
		// multi-cast delegates for this element were found
		var delegatesRemoved = 0;

		if (elementEvent == delegate)
		{
		// SPECIAL CASE: when the delegate to be removed is the same
		// String as the event, attempt to remove the preserved
		// original delegate for this element for this event;
		// this is done because the original delegate may be an
		// anonymous function built from the original HTML;
		// ie - <input ... onclick="...">
		delegate = element[elementEvent + 'Delegate'];
		}

		// iterate through the multi-cast delegates; when a matching
		// one is found, remove it from the list
		var ii = 0;
		while (ii < element[elementDelegates].length)
		{
			if (element[elementDelegates][ii] == delegate)
			{
				element[elementDelegates].splice(ii, 1);
				++delegatesRemoved;
			}
			else
			{
				++ii;
			}
		}

		// return the number of multi-cast delegates removed
		return delegatesRemoved;
	}
	// no multi-cast delegates were found for this element; return
	// something to give the caller this information
	return -1;
} // removeDelegate()


// panelroller
// dependencies - prototype.js, rico.js

PanelRoller = Class.create();
PanelRoller.prototype = {

   initialize: function(controllerRef, controlleeRef, imgExpandedSrc, imgCollapsedSrc, isExpanded, tooglingSpeed) {
   this.controllerRef = controllerRef;
   this.controlleeRef = controlleeRef;
   this.imgExpandedSrc = imgExpandedSrc;
   this.imgCollapsedSrc = imgCollapsedSrc;
   this.isExpanded = (typeof(isExpanded) == 'boolean')? isExpanded : false;
   this.tooglingSpeed = tooglingSpeed;
   
   // initialize node
   if(!this.isExpanded)
   {
		this.Collapse(1);
   }
   this.ToogleController();
  
   // hookup behaviour node
   this.AttachBehaviour();
   },
   
   AttachBehaviour : function(){
     addDelegate(this.controllerRef, "onclick",  this.ToogleControllee.bindAsEventListener(this));
     addDelegate(this.controllerRef, "onclick",  this.ToogleController.bindAsEventListener(this));
   },
   
   Expand : function(h) {
    controlleeRef = this.controlleeRef;
 	new Effect.Size(this.controlleeRef, null, this.controlleeRef.savedHeight, null, h, {complete: function() {controlleeRef.style.overflow = 'visible'; controlleeRef.style.height = "auto"; }} );
 	
   },
   
   Collapse : function(h) {
    this.controlleeRef.savedHeight = this.controlleeRef.offsetHeight;
	this.controlleeRef.style.overflow = 'hidden';
	new Effect.Size(this.controlleeRef, null, 1, null, h);
   },
   
   ToogleControllee : function() {
	// set controllee visibility
	if(this.isExpanded)
		this.Expand(this.tooglingSpeed);
	else
		this.Collapse(this.tooglingSpeed);
   },
   
   ToogleController : function(){
    this.controllerRef.src = (this.isExpanded = !this.isExpanded) ? this.imgCollapsedSrc : this.imgExpandedSrc ;
   }
   
};