// Copyright (C) 2004-2008 Zenfolio, Inc. All rights reserved.
// $Id: frame.js 94 2008-06-12 18:31:24Z alexf $

//---------------------------------------------------------------------------
// zf_MulticastDelegate object.
//
//	class zf_MulticastDelegate
//	{
//		public:
//			zf_MulticastDelegate(Object owner);
//			void attach(function handler);
//			void detach(function handler);
//			void invoke(...);
//		private:
//			Object owner;
//			Array list;
//	};

// constructor
function zf_MulticastDelegate(owner)
{
	this.owner = owner;
	this.list = [];
}

// attaches a handler to the delegate
zf_MulticastDelegate.prototype.attach = function(handler)
{
	this.list.push(handler);
};

// detaches a handler from the delegate
zf_MulticastDelegate.prototype.detach = function(handler)
{
	for (var i = 0; i < this.list.length; i++)
	{
		if (this.list[i] == handler)
		{
			this.list.splice(i, 1);
			return;
		}
	}
};

// invokes the delegate on the specified object
zf_MulticastDelegate.prototype.invoke = function()
{
	for (var i = 0; i < this.list.length; i++)
		this.list[i].apply(this.owner, arguments);
};

//---------------------------------------------------------------------------
// zf_Frame object.
//
//	class zf_Frame
//	{
//		public:
//			zf_Frame();
//			void dispose();
//			void recalcLayout();
//			void attachEvent(string name, function handler);
//			void detachEvent(string name, function handler);
//		public:
//			int minLeft;
//			int minRight;
//			int minMiddle;
//			int cxWidth;
//			int cyHeight;
//		private:
//			HTMLDivElement domFrame;
//			HTMLDivElement domLeft;
//			HTMLDivElement domLeftBox;
//			HTMLDivElement domRight;
//			HTMLDivElement domRightBox;
//			HTMLDivElement domMiddle;
//			HTMLDivElement domMiddleBox;
//			zf_MulticastDelegate onlayoutchange;
//	};

// constructor
function zf_Frame()
{
	this.minLeft = -1;
	this.minRight = -1;
	this.minMiddle = -1;
	this.cyHeight = -1;
	this.showFooter = false;
	this.onlayoutchange = new zf_MulticastDelegate();

	this.domFrame = document.getElementById("frame");
	this.domLeft = document.getElementById("CommonSidebarLeft");
	this.domLeftBox = this._getBox(this.domLeft);
	this.domRight = document.getElementById("CommonSidebarRight");
	this.domRightBox = this._getBox(this.domRight);
	this.domMiddle = document.getElementById("CommonContent");
	this.domMiddleBox = this._getBox(this.domMiddle);

	zf_stdAttachEvent(window, "load", zf_Frame_staticWindowOnLoad);
	zf_stdAttachEvent(window, "resize", zf_Frame_staticWindowOnLoad);
}

// destructor
zf_Frame.prototype.dispose = function()
{
	this.domFrame = null;
	this.domLeft = null;
	this.domLeftBox = null;
	this.domRight = null;
	this.domRightBox = null;
	this.domMiddle = null;
	this.domMiddleBox = null;
	this.onlayoutchange = null;
};

// recalculates frame layout
zf_Frame.prototype.recalcLayout = function()
{
	var cyHeightInit = zf_stdGetClientHeight() - (this.showFooter ? 140 : 80);
	var cxWidthInit = zf_stdGetClientWidth();
	
	if (cxWidthInit < 990)
		cxWidthInit = 990;

	for (var i = 0; i < 3; i++)
	{	
		var cxWidth = cxWidthInit;
		var cyHeight = cyHeightInit;

		if (this.minLeft != -1)
			cyHeight = Math.max(cyHeight, this.minLeft);
		else if (this.domLeftBox != null)
			cyHeight = Math.max(cyHeight, this.domLeftBox.offsetHeight);
			
		if (this.minRight != -1)
			cyHeight = Math.max(cyHeight, this.minRight);
		else if (this.domRightBox != null)
			cyHeight = Math.max(cyHeight, this.domRightBox.offsetHeight);

		if (this.minMiddle != -1)
			cyHeight = Math.max(cyHeight, this.minMiddle);
		else if (this.domMiddleBox != null)
			cyHeight = Math.max(cyHeight, this.domMiddleBox.offsetHeight);

		if (cyHeight == this.cyHeight && cxWidth == this.cxWidth)
			break;

		if (this.domLeft != null)
			this.domLeft.style.height = cyHeight + "px";
		if (this.domMiddle != null)
			this.domMiddle.style.height = cyHeight + "px";
		if (this.domRight != null)
			this.domRight.style.height = cyHeight + "px";
		this.cxWidth = cxWidth;
		this.cyHeight = cyHeight;

		this.onlayoutchange.invoke(cxWidth, cyHeight);
	}
	
	return i > 0;
};

// attaches to an event
zf_Frame.prototype.attachEvent = function(name, handler)
{
	if (name == "layoutchange")
		this.onlayoutchange.attach(handler);
};

// detaches from an event
zf_Frame.prototype.detachEvent = function(name, handler)
{
	if (name == "layoutchange")
		this.onlayoutchange.detach(handler);
};

// finds a "box" DIV for a given column
zf_Frame.prototype._getBox = function(domCol)
{
	if (domCol == null)
		return null;

	var domBox = domCol.firstChild;
	while (domBox != null)
	{
		if (domBox.className == "frame-box")
			return domBox;
		domBox = domBox.nextSibling;
	}

	zf_assert(false);
	return null;
};

// static window onload handler
function zf_Frame_staticWindowOnLoad()
{
	zf_frame.recalcLayout();
}

//---------------------------------------------------------------------------
// zf_stdAttachEvent
//
//  Attaches a handler to the specified event of the specified element in a
//  browser-neutral fashion.
//
//  Prototype:
//
//		void zf_stdAttachEvent(
//				[in] HTMLElement dom,
//				[in] string evt,
//				[in] Function handler
//				);
//
//  Parameters:
//	  dom     - DOM element to which the handler is to be attached
//	  evt     - name of the event, e.g. "click"
//	  handler - event handler function
//
//  Returns:
//    no return value.
//
function zf_stdAttachEvent(dom, evt, handler)
{
	if (dom.attachEvent)
		dom.attachEvent("on" + evt, handler);
	else if (dom.addEventListener)
		dom.addEventListener(evt, handler, false);
}

//---------------------------------------------------------------------------
// zf_stdReplaceClassName
//
//  Removes a CSS class name from the specified element and replaces it
//  with another CSS class name.
//
//  Prototype:
//
//		void zf_stdReplaceClassName(
//				[in] HTMLElement elem,
//				[in, optional] string remove,
//				[in, optional] string add
//				);
//
//  Returns:
//	  no return value.
//
function zf_stdReplaceClassName(elem, remove, add)
{
	if (remove == add)
		return;
		
	if (typeof(elem) == "string")
		elem = document.getElementById(elem);
	if (elem == null)
		return;

	var classNames = elem.className.split(" ");
	var removeAt = -1;
	var foundAt  = -1;

	// check if this class name is assigned to the element
	for (var i = 0; i < classNames.length; i++)
	{
		if (classNames[i] == remove)
			removeAt = i;
		else if (classNames[i] == add)
			foundAt = i;
	}

	if (removeAt != -1)
		classNames.splice(removeAt, 1);
	if (foundAt == -1 && add != null)
		classNames.push(add);

	// assign combined string to the element
	elem.className = classNames.join(" ");
}

//---------------------------------------------------------------------------
// zf_stdHasClassName
//
//  Determines whether an element has the specified class name.
//
//  Prototype:
//
//		bool zf_stdHasClassName(
//				[in] HTMLElement elem,
//				[in] string className
//				);
//
//  Parameters:
//	  elem      - HTML element
//		className - class name to look for
//
//  Returns:
//	  true if the element has the specified class name assigned, or false
//		- otherwise.
//
function zf_stdHasClassName(elem, className)
{
	if (typeof(elem) == "string")
		elem = document.getElementById(elem);
	if (elem == null)
		return false;
		
	if (elem.className == null || elem.className == "")
		return false;

	var classNames = elem.className.split(" ");

	// check if this class name is assigned to the element
	for (var i = 0; i < classNames.length; i++)
	{
		if (classNames[i] == className)
			return true;
	}

	return false;
}