﻿//Intends to abstract features of the browser for various DHTML activities like postioning
//opacity, zordering and custom special effects.

//ALL THINGS ELEMENTAL
function PageElement(obj)
{
	this.BrowserClass = BrowserDetect();
	this.SelectedElement = this.BrowserClass.getElement(obj);

	if(this.SelectedElement)
	{
		this.Style = this.BrowserClass.getElementStyleObject(this.SelectedElement);
		
		//open height and width are set via setOpenDimensions
		//for clipping activities. Stores the fully open dimension of the element that can be
		//referred to when resizing the element;
		this.openHeight = -1; 
		this.openWidth = -1;
		
		this.currentHeight = this.BrowserClass.getObjectHeight(this.SelectedElement); //Calculated full dimension at creation
		this.currentWidth = this.BrowserClass.getObjectWidth(this.SelectedElement);
	}
}

PageElement.prototype.setOpenDimensions = function(width, height)
{
	this.openWidth = width;
	this.openHeight = height;
};

PageElement.prototype.moveBy = function(deltaX, deltaY)
{
	if(this.BrowserClass.isCSS)
	{
		var units = (typeof this.Style.left == "string") ? "px" : 0;
		this.Style.left = parseInt(this.BrowserClass.getObjectLeft(this.SelectedElement)) + deltaX + units;
		this.Style.top =  parseInt(this.BrowserClass.getObjectTop(this.SelectedElement)) + deltaY + units;
	}
};

PageElement.prototype.moveTo = function(x, y)
{
	if(this.BrowserClass.isCSS)
	{
		var units = (typeof this.Style.left == "string") ? "px" : 0;
		this.Style.left = x + units;
		this.Style.top = y + units;
	}
};

PageElement.prototype.clone = function(deep)
{
	if(this.BrowserClass.isW3C)		{
		var temp = this.SelectedElement.cloneNode(deep);
		if(this.SelectedElement && this.SelectedElement.parentNode)
		{
			this.SelectedElement.parentNode.appendChild(temp);
		}
		else
		{
			document.body.firstChild.appendChild(temp)
		}
		var newPE = new PageElement(temp)
		newPE.Style.top = this.Style.top;
		newPE.Style.left = this.Style.left;
		newPE.Open = this.Open;
		newPE.isInMotion = this.isInMotion;
		newPE.openHeight = this.openHeight; 
		newPE.openWidth = this.openWidth;
		newPE.currentHeight = this.currentHeight;
		newPE.currentWidth = this.currentWidth;		
		return newPE;
	}
	else
	{
		return null;
	}
};

PageElement.prototype.setOpacity = function(decimalval)
{
	if(this.BrowserClass.isIE4)
	{
		this.Style.filter = "progid:DXImageTransform.Microsoft.Alpha('style=0, opacity=" + (decimalval * 100) + "')";
	}
	else if(this.BrowserClass.isW3C)
	{
		this.Style.opacity = decimalval;
	}
};

PageElement.prototype.setZIndex = function(zindex)
{
	this.Style.zIndex = zindex;
};


PageElement.prototype.getHeight = function()
{
	var val = parseInt(this.BrowserClass.getObjectHeight(this.SelectedElement))
	return isNaN(val) ? -1 : val;
};

PageElement.prototype.setHeight = function(val)
{
	var units = (typeof this.Style.height == "string") ? "px" : 0;
	if(val > -1)
	{
		this.Style.height = val + units;
		this.currentHeight = val;
	}
}

PageElement.prototype.getWidth = function()
{
	var val = parseInt(this.BrowserClass.getObjectWidth(this.SelectedElement))
	return isNaN(val) ? -1 : val;
};

PageElement.prototype.setWidth = function(val)
{
	var units = (typeof this.Style.width == "string") ? "px" : 0;
	if(val > -1)
	{
		this.Style.width = val + units;
		this.currentWidth = val;
	}
};

PageElement.prototype.show = function()
{
	this.Style.visibility = "visible";
};

PageElement.prototype.hide = function()
{
	this.Style.visibility = "hidden";
};

PageElement.prototype.displayBlock = function()
{
	this.Style.display = "block";
};

PageElement.prototype.displayInline = function()
{
	this.Style.display = "inline";
};

PageElement.prototype.displayNone = function()
{
	this.Style.display = "none";
};

PageElement.prototype.setClippingFrame = function(obj)
{
//	var units = (typeof this.Style.left == "string") ? "px" : 0;
	if(obj.Style)
	{
		this.ClippingFrame = obj;
	}
	else
	{
		this.ClippingFrame = new PageElement(this.BrowserClass.getElement(obj));
	}
//	var units = (typeof this.Style.left == "string") ? "px" : 0;
	this.ClippingFrame.Style.postion = "absolute";
	this.ClippingFrame.Style.overflow = "hidden";
	this.ClippingFrame.Style.zIndex = 1;
	this.Style.zIndex = 0;
	this.ClippingFrame.Open = true;
	this.ClippingFrame.isInMotion = false;
};

PageElement.prototype.createClippingFrame = function(height, width, border)
{
	if(this.BrowserClass.isW3C)
	{
		this.Open = true;
		var clip = document.createElement("div");
		clip.id = this.SelectedElement.id + "_frame";
		
		clip.style.position = "absolute";
		
		var units = (typeof this.Style.left == "string") ? "px" : 0;
	
		clip.style.top = this.BrowserClass.getObjectTop(this.SelectedElement) + units;
		clip.style.left = this.BrowserClass.getObjectLeft(this.SelectedElement) + units;
		clip.style.height = height;
		clip.style.width = width;
		
		if(border)
		{
			clip.style.border = border;
		}
		clip.style.zIndex = 1;
		clip.style.overflow = "hidden";

		if(this.SelectedElement.parentNode)
		{
			this.SelectedElement.parentNode.appendChild(clip);
		}
		else
		{
			document.appendChild(clip);
		}
		clip.appendChild(this.SelectedElement);
		this.Style.top = 0 + units;
		this.Style.left = 0 + units;

		this.Style.zIndex = clip.style.zIndex - 1;
		this.ClippingFrame = new PageElement(clip);
	}
};

PageElement.prototype.makeWindowShade = function(delay, stepcount, direction)
{
	//delay: milliseconds between steps
	//stepcount: the number of steps until closed
	//direction: left, right, up, down
	
	this.shadeDelay = delay;
	this.stepCount = stepcount;
	this.direction = direction;
	this.isInMotion = false;
	this.currentTimeoutId;
	
	this.Open = true;
	this.isInMotion = false;
	
	if(!this.ClippingFrame)
	{
		this.createClippingFrame(this.Style.height, this.Style.width);
		this.ClippingFrame.Open = true;
	}
};

PageElement.prototype.snapShadeClosed = function()
{//will force shade to open or closed state without the animation
	var direction = this.direction;
	if(direction == "left")
	{
		this.ClippingFrame.setWidth(0);
	}
	else if(direction == "bottom")
	{
		this.ClippingFrame.setHeight(0);
	}
	else
	{
		alert('not implemented');
	}
	/* not implemented
	else if(direction == "right")
	{
		this.ClippingFrame.Style.width = 0;
		this.ClippingFrame.currentWidth = 0;
		this.ClippingFrame.Style.left = this.BrowserClass.getObjectLeft(obj.ClippingFrame) + pixels + units;
	}
	else if(direction == "top")
	{
		this.ClippingFrame.Style.height = 0;
		this.ClippingFrame.currentHeight = 0;
		this.ClippingFrame.Style.top = this.BrowserClass.getObjectTop(obj.ClippingFrame) + pixels + units;
	} */
	this.ClippingFrame.Open = false;
};

PageElement.prototype.toggleShade = function(forceToOpen)
{//open parameter is optional
	//open = true
	//closed = false
	
	if(this.ClippingFrame)
	{		
		if(this.ClippingFrame.isInMotion)
		{
			return;
		}
		
		if(this.ClippingFrame.Open == forceToOpen) //if the shade matches the state requested, return
		{
			return;
		}

		var width;
		var height;
		var stepunits;
		var visiblebar;
		var direction = this.direction;
		
		if(this.ClippingFrame.openHeight > -1)
		{	
			height = this.ClippingFrame.openHeight;
		}
		else
		{	
			height = this.BrowserClass.getObjectHeight(this.SelectedElement);
		}
		
					
		if(this.ClippingFrame.openWidth > -1)
		{	
			width = this.ClippingFrame.openWidth;
		}
		else
		{	
			width = this.BrowserClass.getObjectWidth(this.SelectedElement);
		}
		
		//if direction left or right, calculate units from width
		if(direction == "left")
		{
			stepunits = Math.round(width / this.stepCount);
			direction = 1;
			if(this.ClippingFrame.Open)
				stepunits = stepunits * -1; //Reverse the unit calculation to negative incrementor
				
		}
		else if(direction == "bottom")
		{
			stepunits = Math.round(height / this.stepCount);
			direction = 2;
			if(this.ClippingFrame.Open)
				stepunits = stepunits * -1; //Reverse the unit calculation to negative incrementor
		}
		else if(direction == "right")
		{
			stepunits = Math.round(width / this.stepCount);
			direction = 3;
			if(this.ClippingFrame.Open) //we'll be moving the clipping left
				stepunits = stepunits * -1; //Reverse the unit calculation to negative incrementor
		}
		else if(direction == "top")
		{
			stepunits = Math.round(height / this.stepCount);
			direction = 4;
			if(this.ClippingFrame.Open) //we'll be moving the clipping left
				stepunits = stepunits * -1; //Reverse the unit calculation to negative incrementor
		}

		this.ClippingFrame.isInMotion = true;

		if(this.ClippingFrame.Open == true)
		{	
			var handle = this;
			
			this.currentTimeoutId = setTimeout(function(){
							stepShadeClose(handle, width, height, direction, stepunits, handle.stepCount, handle.shadeDelay);
						},500);

		}
		else if(this.ClippingFrame.Open == false)
		{
			if(this.currentTimeoutId)
			{
				clearTimeout(this.currentTimeoutId);
				this.currentTimeoutId = 0;
			}

			stepShadeOpen(this, width, height, direction, stepunits, this.stepCount, this.shadeDelay);
		}
	}
	else
	{
		alert("window shade not initialized, please call makeWindowShade");
	}
};

PageElement.prototype.fly = function(startX, startY, destX, destY, clone, delay, stepcount, deletewhenfinished, zindex)
{
	clone = (clone) ? true : false; //(optional) false or null: false, true:true
	delay = (delay) ? delay : 5; //(optional) default 5ms pause
	stepcount = (stepcount) ? stepcount : 4; //(optional) default 4, number of steps from a to b
	
	var obj;
	
	if(clone)
	{
		obj = this.clone();
		obj.Style.position = "absolute";
	}
	else
	{
		obj = this;
	}
	
	if(zindex)
	{
		obj.setZIndex(zindex);
	}
	
	//calculate the distance between start and end x
	//subtract start from end
	var distanceX = destX - startX;
	var distanceY = destY - startY;
	
	//divide the distance by the number of steps
	var incrementX = Math.round(distanceX / stepcount);
	var incrementY = Math.round(distanceY / stepcount);
	
	var coordinates = new Array();
	
	//Create an array of x/y coordinates
	for(i = 0; i < stepcount; i++)
	{
		if(i < stepcount - 1)
		{
			coordinates[i] = new coordinate(startX + (incrementX * i), startY + (incrementY * i));
		}
		else
		{   //last position should be the destination
			//works around any rounding problems with incrementor
			coordinates[i] = new coordinate(destX, destY);
		}
	}
	//launch into a recursive routine to animate the icon
	obj.Style.left = startX;
	obj.Style.top = startY;
	
	flyStep(obj, coordinates, 0, delay, deletewhenfinished);
};

//EVENT WIREUP
PageElement.prototype.onMouseDown = function(func)
{
	this.SelectedElement.onmousedown = func;
};

PageElement.prototype.onMouseOver = function(func)
{
	this.SelectedElement.onmouseover = func;
};

PageElement.prototype.onMouseUp = function(func)
{
	this.SelectedElement.onmouseup = func;
};

PageElement.prototype.onMouseOut = function(func)
{
	this.SelectedElement.onmouseout = func;
};

PageElement.prototype.onMouseMove = function(func)
{
	this.SelectedElement.onmousemove = func;
};

PageElement.prototype.onClick = function(func)
{
	this.SelectedElement.onclick = func;
};

function PostInitializationHandler()
{
	if(!window._postInitializeEvents)
	{
		window._postInitializeEvents = new HandlePostInitialize().create();
	}
	return window._postInitializeEvents;
}

function HandlePostInitialize()
{
	return this;
}

HandlePostInitialize.prototype.getHandler = function()
{
	if(!window._postInitializeEvents)
	{
		window._postInitializeEvents = this.create();
	}
	return window._postInitializeEvents;
};

HandlePostInitialize.prototype.create = function()
{
	this.PostInitializeEvents = new Array();
	return this;
};

HandlePostInitialize.prototype.add = function(func)
{
	this.PostInitializeEvents[this.PostInitializeEvents.length] = func;
};

HandlePostInitialize.prototype.executePostInitialzeEvents = function()
{
	if(this.PostInitializeEvents)
	{
		var i;
		for(i = 0; i < this.PostInitializeEvents.length; i++)
		{
			this.PostInitializeEvents[i]();
		}
	}
};

///////////////////////////////////////////////////////
//BROWSER DETECTION CLASSES
//Wraps and abstracts the Browser
//provides methods and properties with which you can
//interact with the Browser in a uniform manner
//regardless of the actual browser make/version
///////////////////////////////////////////////////////
function BrowserDetect()
{
	if(!window.BrowserClass.Initialized)
	{
		window.BrowserClass = new BrowserClass();
		window.BrowserClass.initialize();
	}
	return window.BrowserClass;
}

function BrowserClass(){}

BrowserClass.prototype.initialize = function()
{
	var uAgent = navigator.userAgent;
	this.isCSS = (document.styleSheets) ? true : false;
	this.isW3C = (this.isCSS && document.getElementById) ? true : false;
	this.isIE4 = (this.isCSS && document.all) ? true : false;
	this.isIE5 = (document.body.currentStyle) ? true : false;

	if(uAgent)
	{
		this.isSafari = uAgent.toLowerCase().indexOf("safari") > -1;
		this.isFF10 = uAgent.toLowerCase().indexOf("firefox/1.0") > -1;
	}
	else
	{
		this.isSafari = false;
		this.isFF10 = false;
	}
	
	this.isMAC = (this.isSafari) ? true : false; //add additional tests here if necessary
	this.isIECSS1 = (document.compatMode && document.compatMode.indexOf("CSS1") >= 0) ? true : false;
	this.isIEBackCompat = (document.compatMode && document.compatMode.indexOf("BackCompat") >= 0) ? true : false;
	this.Initialized = true;
};

BrowserClass.prototype.getElement = function(obj)
{
	var theObj;
	if(typeof obj == "string")
	{
		if(this.isW3C)
		{
			theObj = document.getElementById(obj);
		}
		else if(this.isIE4)
		{
			theObj = document.all(obj);
		}
	}
	else
	{
		theObj = obj;
	}
	return theObj;
};

BrowserClass.prototype.getElementStyleObject = function(obj)
{
	var theObj = this.getElement(obj);
	if(theObj)
	{
		theObj = theObj.style;
	}
	return theObj;
};

BrowserClass.prototype.getObjectLeft = function(elem)
{
	var result = 0;
	if(document.defaultView)
	{
		var style = document.defaultView;
		var cssDecl = style.getComputedStyle(elem, "");
		result = cssDecl.getPropertyValue("left");
	}
	else if(elem.currentStyle)
	{
		result = elem.currentStyle.left;
	}
	else if(elem.style)
	{
		result = elem.style.left;
	}
	if(isNaN(parseInt(result)))
		result = 0;
		
	return result;
};

BrowserClass.prototype.getObjectTop = function(elem)
{
	var result = 0;
	if(document.defaultView)
	{
		var style = document.defaultView;
		var cssDecl = style.getComputedStyle(elem, "");
		result = cssDecl.getPropertyValue("top");
	}
	else if(elem.currentStyle)
	{
		result = elem.currentStyle.top;
	}
	else if(elem.style)
	{
		result = elem.style.top;
	}
	if(isNaN(parseInt(result)))
		result = 0;

	return result;
};

//TODO
BrowserClass.prototype.getObjectWidth = function(elem)
{
	var result = 0;
	if(elem.offsetWidth)
	{
		if(elem.scrollWidth && (elem.offsetWidth != elem.scrollWidth))
		{
			result = elem.scrollWidth;
		}
		else
		{
			result = elem.offsetWidth;
		}
	}
	else if(elem.clip && elem.clip.width)
	{
		result = elem.clip.width;
	}
	else if(elem.style && elem.style.pixelWidth)
	{
		result = elem.style.pixelWidth;
	}
	return result;
};

BrowserClass.prototype.getObjectHeight = function(elem)
{
	var result = 0;
	if(elem.offsetHeight)
	{
		result = elem.offsetHeight;
	}
	else if(elem.clip && elem.clip.height)
	{
		result = elem.clip.height;
	}
	else if(elem.style && elem.style.pixelHeight)
	{
		result = elem.style.pixelHeight;
	}
	return result;
};

BrowserClass.prototype.onMouseDown = function(func)
{
	document.onmousedown = func;
};

BrowserClass.prototype.onMouseUp = function(func)
{
	document.onmouseup = func;
};

BrowserClass.prototype.onMouseOver = function(func)
{
	document.onmouseover = func;
};

BrowserClass.prototype.onMouseOut = function(func)
{
	document.onmouseout = func;
};

BrowserClass.prototype.onMouseMove = function(func)
{
	document.onmousemove = func;
};

BrowserClass.prototype.onClick = function(func)
{
	document.onclick = func;
};



///////////////////////////////////////////////////////
//LOCATION PARSER
//Wraps and abstracts the location object
//and parses the querystring into properties\
//example:
// var foo = ParsedLocation().Query.Get('bar');
// alert(foo); //alerts value of querystring item foo
///////////////////////////////////////////////////////
function ParsedLocation()
{
	if(!window.LocationParser.Parsed)
	{
		window.LocationParser = new LocationParser();
	}
	return window.LocationParser;
}

function LocationParser()
{
	this.parse();
	return this;
}

LocationParser.prototype.parse = function()
{
	var query = document.location.search.substr(1);
	
	this.Location = document.location;
	this.Query = new GetQuery();
	this.Query.parse(query.replace(/<|<\//,'')); //no to xss
	this.Parsed = true;
};

LocationParser.prototype.isSecure = function()
{
	return this.Location.protocol == "https:";
};

LocationParser.prototype.go = function()
{
	//creates a new url based on the query items and executes
};


function GetQuery(){}

GetQuery.prototype.parse = function(qs)
{
	this.QueryString = (qs) ? qs : "";
	this.Items = new Array();
	
	if(this.QueryString != "")
	{
		var arquery = this.QueryString.split('&');
		for(i = 0; i < arquery.length; i++)
		{
			var aritem = arquery[i].split('=');
			if(aritem.length == 2)
			{
				this.addItem(aritem[0], aritem[1]);
			}
		}
	}
};

GetQuery.prototype.get = function(key)
{
	var obj = eval("this." + key);
	if(obj)
	{
		return obj;
	}
	else
	{
		return "";
	}
};

GetQuery.prototype.addItem = function(key, value)
{
	try
	{
		var newItem = new QueryItem().create(key, value);
		if(newItem.Key)
		{
			var oldItem = eval("this." + newItem.Key);
			if(!oldItem)
			{
				eval("this." + newItem.Key + " = newItem");
				this.Items[this.Items.length] = newItem;
			}
			else
			{
				oldItem.Value = oldItem.Value + "," + value;
			}
		}
	}
	catch(err){}
}

GetQuery.prototype.toString = function()
{
	//TODO: loop through this.Items and build up a new querystring.
	//return (this.QueryString) ? this.QueryString : "";
};

function QueryItem(){}

QueryItem.prototype.create = function(key, value)
{
	var newPropertyName = escape(key);
	if(newPropertyName.indexOf('%') == -1)
	{
		this.Key = key;
		this.Value = value;
	}
	else
	{
		this.Key = null;
		this.Value = "";
	}
	return this;
};

function coordinate(x, y)
{
	this.x = x;
	this.y = y;
}

////////////////////////////////////////////////////////////
//
//HELPER FUNCTIONS
//
////////////////////////////////////////////////////////////

function flyStep(obj, coordinates, currentindex, delay, deletewhenfinished)
{
	obj.moveTo(coordinates[currentindex].x, coordinates[currentindex].y);
	currentindex++;
	if(currentindex < coordinates.length)
	{
		setTimeout(function(){flyStep(obj, coordinates, currentindex, delay, deletewhenfinished);} , delay);
	}
	else if(deletewhenfinished)
	{
		obj.hide();
	//	obj.SelectedElement.parentNode.removeChild(obj.SelectedElement);
//		obj = null;
	}
}

function stepShadeClose(obj, width, height, direction, pixels, step, delay)
{
	if(direction == 1) //left
	{
		width = width + pixels;
		if(width < 0)
			width = 0;
			
		obj.ClippingFrame.setWidth(width);
	}
	else if(direction == 2) //bottom
	{
		height = height + pixels;
		if(height < 0)
			height = 1;
			
		obj.ClippingFrame.setHeight(height);
	}
	else if(direction == 3) //right
	{
		width = width + pixels;
		if(width < 0)
			width = 0;
		
		obj.ClippingFrame.setWidth(width);
		obj.ClippingFrame.Style.left = obj.BrowserClass.getObjectLeft(obj.ClippingFrame) + pixels + units;
	}
	else if(direction == 4) //top
	{
		height = height + pixels;
		if(height < 0)
			height = 0;
			
		obj.ClippingFrame.setHeight(height);
		obj.ClippingFrame.Style.top = obj.BrowserClass.getObjectTop(obj.ClippingFrame) + pixels + units;
	}

	if(step > 0)
	{
		setTimeout(function(){
						stepShadeClose(obj, width, height, direction, pixels, step, delay);
							}, delay);
		step--;
	}
	else
	{
		obj.ClippingFrame.Open = false;
		obj.ClippingFrame.isInMotion = false;
		obj.hide();
	}
}

function stepShadeOpen(obj, width, height, direction, pixels, step, delay)
{
	
	var shadewidth = obj.ClippingFrame.currentWidth;
	var shadeheight = obj.ClippingFrame.currentHeight;
	var units = (typeof obj.ClippingFrame.Style.width == "string") ? "px" : 0;
	if(direction == 1) //left
	{
		shadewidth = shadewidth + pixels;
		if(shadewidth > width)
			shadewidth = width;

		obj.ClippingFrame.Style.width = shadewidth + units;
		obj.ClippingFrame.currentWidth = shadewidth;
	}
	else if(direction == 2) //bottom
	{
		shadeheight = shadeheight + pixels;
		if(shadeheight > height)
			shadeheight = height;
	
		obj.ClippingFrame.Style.height = shadeheight + units;
		obj.ClippingFrame.currentHeight = shadeheight;
	}
	else if(direction == 3) //right
	{
		shadewidth = shadewidth + pixels;
		if(shadewidth > width)
			shadewidth = width;
		
		obj.ClippingFrame.Style.width = shadewidth + units;
		obj.ClippingFrame.currentWidth = shadewidth;
		obj.ClippingFrame.Style.left = obj.BrowserClass.getObjectLeft(obj.ClippingFrame) - pixels + units;
	}
	else if(direction == 4) //top
	{
		shadeheight = shadeheight + pixels;
		if(shadeheight > height)
		{
			shadeheight = height;
		}
			
		obj.ClippingFrame.Style.height = shadeheight + units;
		obj.ClippingFrame.currentHeight = shadeheight;
		obj.ClippingFrame.Style.top = obj.BrowserClass.getObjectTop(obj.ClippingFrame.Style.top) + pixels + units;
	}

	if(step > 0)
	{
		setTimeout(function(){
						stepShadeOpen(obj, width, height, direction, pixels, step, delay);
							}, delay);					
		step--;
	}
	else
	{

		if(obj.currentTimeoutId)
		{
			clearTimeout(obj.currentTimeoutId);
			obj.currentTimeoutId = 0;
		}
		else
		{
			obj.ClippingFrame.Open = true;
			obj.ClippingFrame.isInMotion = false;
		}
	}
}