/*
Class: SplitPane
	Separates two divs with a draggable divider that you can use to resize the divs, kind of like
	a frame but without using frames! The two divs should be siblings, that is they should both
	have the same parent. You can have an arbitrary number of such siblings separated using different
	instances of this class, i.e. you can have any number of columns separated by a draggable divider
	that alows you to resize them at will.
	
	You can ask to be notified when the following events occur
	
	- A drag starts.
	- A drag occurs.
	- A drag ends.
	
	This allows you to perform any housekeepng not already performed for you.
	
	You can disable the	resizing.
	
	You can ask an instance to serialize itself as an HTTP POST argument list, this is useful in
	combination with onEnd hooking to save the current div sizes on the server.
	
NOTE:
	In IE all parent divs must have a width other than 'auto'.
	div1 and div2 should probably have overflow=hidden set.
*/
var SplitPane = Class.create();

/*
property: SplitPane.cache
	Holds all instances of SplitPane. Used to delay intialization until Window.onLoad().
*/
SplitPane.cache = new Array();
SplitPane.cacheIndex = 0;
SplitPane.handleHeight = 10;	// Height of the handle

SplitPane.prototype = {
	/*
	Constructor: intialize
	
	parameters:
		div1_id - a div, or the ID of a div notionally on the 'top' of the divider.
		div1_height - the initial height of div1 as a percentage of its parent's height
		div2_id - a div, or the ID of a div notionally on the 'right' of the divider.
		div2_top - the coordinate of the top edge of div2 relative to the parent div as a percentage.
		div2_height - the initial height of div2 as a percentage of its parent's height.
		options - an associative array of optional arguments which include
		
	options:
		onStart - a function to be called when a drag of the divider starts.
		onDrag - a function to be called when a drag occurs.
		onEnd - a function to call when a drag ends.
		active - if true then resizing can occur. If false then the two divs are set to
			the specified heights and that is that. Defaults to false.
	*/
	initialize: function(div1_id, div1_height, div2_id, div2_top, div2_height, options) {
		this.options = { 
			onStart:    Prototype.emptyFunction,
			onDrag:     Prototype.emptyFunction,
			onEnd:      Prototype.emptyFunction,
			active:		  false
		}
		
		Object.extend(this.options, options || {});
		
		this.div1 = $(div1_id);
		this.div2 = $(div2_id);
		this.container = this.div1.parentNode;	// This had better be the same for both divs
		this.div1_height = div1_height;	// as a percentage
		this.div2_top = div2_top;		// as a percentage
		this.div2_height = div2_height;	// as a percentage
		
		SplitPane.cache[SplitPane.cacheIndex] = this;
		SplitPane.cacheIndex = SplitPane.cacheIndex+1;
	},

	/*
		function: set
			create a divider. If its marked as 'active' then wire it up for events.
	*/
	set: function() {
		Element.makePositioned(this.container);	// Fix IE
		
		// Change heights to percents so that window resizing works
		this.div1.style.height = this.div1_height + "%";
		this.div2.style.height = this.div2_height + "%";
		this.div2.style.top  = this.div2_top + "%";
		
		// Create a divider and make it a child of container
		this.divider = document.createElement("DIV");
		this.container.appendChild(this.divider);
		this.divider.className="splitpane-divider";
		this.divider.style.position="absolute";
		this.divider.style.height=SplitPane.handleHeight + "px";
		this.divider.style.left="0px";
		this.divider.style.zIndex=1000;
		this.divider.style.cursor = "s-resize";		

		this.containerHeight = this.getHeight(this.container);
		
		this.setDividerY();
		this.setDividerWidth();

		if (this.options.active) {
			this.eventMouseDown    = this.startDrag.bindAsEventListener(this);
			this.eventMouseUp      = this.endDrag.bindAsEventListener(this);
			//this.eventChangeCursor = this.cursor.bindAsEventListener(this);
			this.eventMouseMove    = this.update.bindAsEventListener(this);
	
			Event.observe(this.divider, "mousedown", this.eventMouseDown);
			Event.observe(document, "mouseup", this.eventMouseUp);
			//Event.observe(this.divider, "mousemove", this.eventChangeCursor);
			Event.observe(document, "mousemove", this.eventMouseMove);
		}
	},
	
	/*
		function: serialize
			serialize the splitpane in a form suitable to be used in an HTTP request.
		
		serialized values:
			div1 - the id of div1
			div1_top - the top edge of div1 expressed as a percentage of the parent height
			div1_height - the height of div1 expressed as a percentage of the parent height
			div2 - the id of div2
			div1_top - the top edge of div2 expressed as a percentage of the parent height
			div1_height - the height of div2 expressed as a percentage of the parent height
	*/
	serialize: function() {
		return "div1=" + this.div1.id
		+ "&div1_top=" + this.getYPercent(this.div1)
		+ "&div1_height=" + this.getHeightPercent(this.div1)
		+ "&div2=" + this.div2.id
		+ "&div2_top=" + this.getYPercent(this.div2)
		+ "&div2_height=" + this.getHeightPercent(this.div2);
	},
	
	/*
		function: dispose
			unhook from events
	*/
	dispose: function() {
		Event.stopObserving(this.divider, "mousedown", this.eventMouseDown);
		Event.stopObserving(document, "mouseup", this.eventMouseUp);
		//Event.stopObserving(this.divider, "mousemove", this.eventChangeCursor);
		Event.stopObserving(document, "mousemove", this.eventMouseMove);
	},
	
	cursor: function(event) {
		//this.divider.style.cursor = "s-resize";		
	},

	startDrag: function(event) {
	    if(Event.isLeftClick(event)) {
			this.active = true;
			var offsets = Position.cumulativeOffset(this.divider); 
	    this.start_pointer  = [Event.pointerX(event), Event.pointerY(event)];
			this.inset = this.start_pointer[0] - offsets[0];
			this.containerHeight = this.getHeight(this.container);

			if (this.container.currentStyle) this.containerHeight -= 10; //thomas
			
			this.start_div1_height = this.getHeight(this.div1);
      this.start_div2_top = this.getY(this.div2);
			this.start_div2_height = this.getHeight(this.div2) ;
			this.start_divider_y = this.getY(this.divider);
			Event.stop(event);
			this.options.onStart(this, event);
		}
	},

	endDrag: function(event) {
		if (this.active) {

			this.div1.style.height = this.new_div1_height + "px"; // * 100.0 / this.containerHeight) + "%";			
			this.div2.style.top    = this.div1.style.height; //((this.start_div2_top + delta) * 100.0 / this.containerHeight) + "%";
			this.div2.style.height = (this.containerHeight-this.new_div1_height) + "px"; // * 100.0 / this.containerHeight) + "%";

			this.active = false;
			Event.stop(event);
			this.setDividerY();
			this.setDividerWidth();
			this.options.onEnd(this, event);
		}
	},

	update: function(event) {
		if (this.active) {
	    var pointer  = [Event.pointerX(event), Event.pointerY(event)];
			var delta = pointer[1] - this.start_pointer[1];
			//var delta_percent = delta * 100.0 / this.containerHeight;
			
			// Calculate new div1 height
			this.new_div1_height = this.start_div1_height + delta;
			// Limit height of div1
			if (this.new_div1_height < 0.0) {
				this.new_div1_height = 0.0;
				delta = -this.start_div1_height;
			}
						
			// Calculate new div2 height (in %)
			this.new_div2_height = this.start_div2_height - delta;
			// Limit height of div2
			if (this.new_div2_height < 0.0) {
				this.new_div2_height = 0.0;
				delta = this.start_div2_height;
				this.new_div1_height = this.start_div1_height + delta;
			}


      var new_divider_y =  this.start_divider_y + delta;


			// resize/position the divs
			//this.div1.style.height = this.new_div1_height + "px"; // * 100.0 / this.containerHeight) + "%";			
			//this.div2.style.top  = this.div1.style.height; //((this.start_div2_top + delta) * 100.0 / this.containerHeight) + "%";
			//this.div2.style.height = (this.containerHeight-this.new_div1_height) + "px"; // * 100.0 / this.containerHeight) + "%";



			// Set absolute position of divider - fix it up to be a % in endDrag().
			//this.divider.style.top = (this.start_divider_y + delta) + "px";
			this.divider.style.top = new_divider_y + "px";
      //this.setDividerY();

			
			Event.stop(event);
			this.options.onDrag(this, event);
		}
	},

	setDividerY: function() {
		// Place the center of 'divider' half way between div1 and div2
		var div1_bottom = this.getY(this.div1) + this.getHeight(this.div1);
		//var l = (((this.getY(this.div2)- div1_bottom - SplitPane.handleHeight)/2 + div1_bottom) * 100.0 / this.containerHeight) + "%";
		//this.divider.style.top = l;
		//this.divider.style.top = this.div1.style.height;
		this.divider.style.top = div1_bottom + "px";
	},

	setDividerWidth: function() {
		// Set the divider width to the greater of the widths of the two divs
		var w = Math.max(this.getWidth(this.div1), this.getWidth(this.div2));
		this.divider.style.width = w + "px";
	},

	getY: function(el) {
    	return el.y ? el.y : el.offsetTop;
	},
  
	getYPercent: function(el) {
		var y = "0";
		y = Element.getStyle(el,"top");
		if (y) {
			y = y.replace("%","");	//moz
		}
		
		return y ? parseFloat(y) : 0.0;
	},
  
	getHeightPercent: function(el) {
		var h = "0";
		h = Element.getStyle(el,"height");
		if (h) {
			h = h.replace("%","");	//moz
		}
		
		return h ? parseFloat(h) : 0.0;
	},
  
	getHeight: function(el) {
//		if (el.currentStyle){
			return el.getHeight();									//ie
//		} else {
//			return Element.getStyle(el,"height").replace("px","");	//moz
//		}
	},
  
	getWidth: function(el) {
//		if (el.currentStyle){
			return el.getWidth();									//ie
//		} else {
//			return Element.getStyle(el,"width").replace("px","");	//moz
//		}
	}
}

SplitPane.setAll = function () {
	for(i=0; i<SplitPane.cache.length; i++){
		SplitPane.cache[i].set();
	}
}

Event.observe(window, "load", SplitPane.setAll);
