// Inheritance method
if(!Function.inherits){
	Function.prototype.inherits = function(superclass){
		var x = function(){
		};
		x.prototype = superclass.prototype;
		this.prototype = new x();
	}
}

// An HTML display object class encapsulating various methods to allow style manipulation and hierarchy tracking

function DisplayObject(){

	this.domElement = null;// DOM object container;

	this.attributes = new Object();// Object to hold attributes.

	this.parentObj = null;// Object to hold parent DisplayObject

	this.opacity = 100;// default opacity

	this.transformations = new Array();// array to hold current list of
										// transformations
	this.transformationStarted = false;
	
	this.onTransformEndFunction = null;
	
	// Style Methods
	
	this.setClass = function(className){
		
		if (this.domElement != null) {
			this.domElement.className = className;
		}
				
	}

	this.setStyle = function(style, value){// method to set style of domElement (CSS styles e.g. border-width will be converted to javascript compatible).

		if(this.domElement != null){

			var pattern = /\-([a-z])/;

			while (String(style).match(pattern)){

				style = String(style).replace(pattern,
						String(RegExp.$1).toUpperCase());

			}

			this.domElement.style[style] = value;

		}

	}

	/*this.getStyle = function(style){

		if(this.domElement != null){

			var pattern = /\-([a-z])/;

			while (String(style).match(pattern)){

				style = String(style).replace(pattern,
						String(RegExp.$1).toUpperCase());

			}

			return this.domElement.style[style];

		}

		return null;

	}*/
	
	this.getStyle = function(strCssRule,domElement){
		if(!domElement){
			domElement = this.domElement;
		}
		var strValue = "";
		if(document.defaultView && document.defaultView.getComputedStyle){
			strValue = document.defaultView.getComputedStyle(domElement, "").getPropertyValue(strCssRule);
		}
		else if(domElement.currentStyle){
			strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
				return p1.toUpperCase();
			});
			strValue = domElement.currentStyle[strCssRule];
		}
		return strValue;
	}
	


	/// SIZE METHODS

	this.getWidth = function(domElement){
		if(domElement == null){
			domElement = this.domElement;
		}
		if (domElement != null) {
			if (domElement.style.pixelWidth) {
				return domElement.style.pixelWidth;
			}else if (domElement.offsetWidth){
				return domElement.offsetWidth;
			}else{
				return domElement.clientWidth;
			}
		}
		return null;
	}

	this.getHeight = function(domElement){
		if(domElement ==  null){
			domElement = this.domElement;
		}
		if (domElement != null) {
			if (domElement.style.pixelHeight) {
				return domElement.style.pixelHeight;
			}else if (domElement.offsetHeight){
				return domElement.offsetHeight;
			}else{
				return domElement.clientHeight;
			}
		}
		return null;
	}

	this.getPageSizeObject = function(){

		var xScroll, yScroll;

		if(window.innerHeight && window.scrollMaxY){
			xScroll = document.body.scrollWidth;
			yScroll = window.innerHeight + window.scrollMaxY;
		}else if(document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		}else{ // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}

		var windowWidth, windowHeight;
		if(self.innerHeight){ // all except Explorer
			windowWidth = self.innerWidth;
			windowHeight = self.innerHeight;
		}else if(document.documentElement
				&& document.documentElement.clientHeight){ // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		}else if(document.body){ // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}

		// for small pages with total height less then height of the viewport
		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		}else{
			pageHeight = yScroll;
		}

		// for small pages with total width less then width of the viewport
		if(xScroll < windowWidth){
			pageWidth = windowWidth;
		}else{
			pageWidth = xScroll;
		}

		return {
			pageWidth : pageWidth,
			pageHeight : pageHeight,
			windowWidth : windowWidth,
			windowHeight : windowHeight
		};
	}
	
	this.getYScroll = function(){
		

		var yScroll;

		if (self.pageYOffset) {
			yScroll = self.pageYOffset;
		} else if (document.documentElement && document.documentElement.scrollTop){	 // Explorer 6 Strict
			yScroll = document.documentElement.scrollTop;
		} else if (document.body) {// all other Explorers
			yScroll = document.body.scrollTop;
		}

		return yScroll;

	}

	// DOM element methods

	this.createDOMElement = function(tag, className){

		if(tag == null){
			tag = "div";
		}

		this.domElement = document.createElement(tag);

		if(className != null){
			this.domElement.className = className;

		}
		
		//this.domElement['displayObject'] = this;

	}

	this.setDOMElement = function(domElement){

		this.domElement = domElement;

	}

	this.getDOMElement = function(){

		return this.domElement;

	}

	this.setDOMAttribute = function(a, v){

		if(this.domElement != null){

			this.domElement.setAttribute(a, v);

		}

	}

	this.setID = function(id){

		this.setDOMAttribute("id", id);

	}

	this.setHTML = function(html){

		if(this.domElement != null){
			this.domElement.innerHTML = html;
		}

	}

	// Child methods

	this.addDisplayObject = function(tag){

		var displayObject = new DisplayObject();
		displayObject.setParent(this);
		displayObject.createDOMElement(tag);

		this.domElement.appendChild(displayObject.getDOMElement());

		return displayObject;

	}

	this.attachDisplayObject = function(displayObject){

		displayObject.setParent(this);

		this.domElement.appendChild(displayObject.getDOMElement());

		return displayObject;

	}

	this.addElement = function(tag, html){// method to add element. Arguments [2] onwards can be attribute pairs

		var element = document.createElement(tag);

		if(arguments.length > 2){

			for( var i = 2; i < arguments.length; i += 2){

				element.setAttribute(arguments[i], arguments[i + 1]);

			}

		}

		if(html != null){

			element.innerHTML = html;

		}

		this.domElement.appendChild(element);

		return element;

	}

	this.removeElement = function(element){

		this.domElement.removeChild(element);

	}

	this.addText = function(text){// method to add element.

		var textNode = document.createTextNode(text);

		this.domElement.appendChild(textNode);

		return textNode;

	}

	this.clearContents = function(){

		if(this.domElement != null){

			if(this.domElement.hasChildNodes()){
				while (this.domElement.childNodes.length >= 1){
					this.domElement.removeChild(this.domElement.firstChild);
				}
			}

		}
	}

	this.appendToElement = function(element){

		if(element != null && this.getDOMElement() != null){

			element.appendChild(this.getDOMElement());

		}

	}

	this.removeFromElement = function(element){

		if(element != null && this.getDOMElement() != null){

			element.removeChild(this.getDOMElement());

		}

	}
	
	this.appendChild = function(node){
		
		if(this.domElement != null){
			
			this.domElement.appendChild(node);
			
		}
	}

	// Parent methods

	this.getParent = function(){

		return this.parentObj;

	}

	this.setParent = function(parent){

		this.parentObj = parent;

	}

	// Settings methods

	this.setAttribute = function(attribute, value){

		this.attributes[attribute] = value;

	}

	this.getAttribute = function(attribute){

		if(this.attributes[attribute] != null){

			return this.attributes[attribute];

		}else if(this.parentObj != null){

			return this.parentObj.getAttribute(attribute);

		}

		return null;

	}

	// Transformation methods

	this.setOpacity = function(opacity){

		this.opacity = opacity;

		if(this.domElement != null){
			this.domElement.style.filter = "alpha(style=0,opacity:" + opacity + ")"; // IE
			if(opacity == 100 && this.domElement.style.removeAttribute != null){
				this.domElement.style.removeAttribute('filter'); 
			}
			this.domElement.style.KHTMLOpacity = opacity / 100; // Konqueror
			this.domElement.style.MozOpacity = opacity / 100; // Mozilla (old)
			this.domElement.style.opacity = opacity / 100; // Mozilla (new)
		}
	}

	this.changeOpacity = function(newOpacity, increment){

		increment = (increment == null) ? 10 : increment;
		var i = 0;
		// determine the direction for the blending, if start and end are the
		// same nothing happens
		if(this.opacity > newOpacity){
			for( var o = this.opacity; o >= newOpacity; o -= increment){// add opacities to transformation array
				if(this.transformations[i] == null){
					this.transformations[i] = {
						opacity : o
					};// create new transformation object
				}else{
					this.transformations[i]["opacity"] = o;// add opacity to
															// existing
															// transformation
															// object
				}
				i++;
			}
		}else if(this.opacity < newOpacity){
			for( var o = this.opacity; o <= newOpacity; o += increment){
				if(this.transformations[i] == null){
					this.transformations[i] = {
						opacity : o
					};
				}else{
					this.transformations[i]["opacity"] = o;
				}
				i++;
			}
		}

		this.startTransform();
	}
	
	this.changeDimension = function(dimension, newValue, steps){
		
		steps = (steps == null) ? 10 : steps;
		
		var oldValue = (this.domElement.style[dimension] != null) ? parseInt(this.domElement.style[dimension]) : 0;
		
		var increment = (newValue-oldValue)/steps;
		
		for(var i=0;i<steps;i++){
			if(this.transformations[i] == null){
				this.transformations[i] = new Object();
			}
			this.transformations[i][dimension] = oldValue + increment*(i+1);
		}
		
		this.startTransform();
	}
	

	this.startTransform = function(){

		if(!this.transformationStarted){

		var thisObj = this;

		window.setTimeout( function(){thisObj.doTransformation()}, 50);

		this.transformationStarted = true;

		}

	}

	this.show = function(){

		this.setStyle("display", "block");

	}

	this.hide = function(){

		this.setStyle("display", "none");

	}

	this.hideElement = function(element){

		this.setElementDisplay(element, "none");

	}

	this.showElement = function(element){

		this.setElementDisplay(element, "block");

	}

	this.setElementDisplay = function(element, display){

		if(element != null){
			element.style.display = display;
		}
	}

	this.doTransformation = function(){

		if(this.transformations.length > 0){

			var transformation = this.transformations.shift();

			for( var i in transformation){
				switch(i){
				case "opacity":
					this.setOpacity(transformation[i]);
					break;
				case "left":
				case "right":
				case "top":
				case "bottom":
				case "width":
				case "height":
					this.setStyle(i, transformation[i]+"px");
					break;
				}
			}

			if(this.transformations.length > 0){
				var thisObj = this;
				window.setTimeout( function(){thisObj.doTransformation()}, 50);
			}else{
				this.transformationStarted = false;
				if(this.onTransformEndFunction != null){
					this.onTransformEndFunction(this);
				}
			}

		}

	}

	// listening methods

	this.addEventListener = function(event, func){

		if(this.domElement != null){

			this.domElement[event] = func;

		}

	}

	// Mouse methods

	this.getMousePosition = function(event){
		return {
			x : event.clientX,
			y : event.clientY
		};
	}
	
	this.getPosition = function(element){
		
		if (element == null) {
			element = this.domElement;
		}
		
		if (element != null) {
		
			var x = y = width = height = 0;
			
			if (element.style.pixelWidth) {
				width = element.style.pixelWidth;
				height = element.style.pixelHeight;
			} else 
				if (element.offsetWidth) {
					width = element.offsetWidth;
					height = element.offsetHeight;
				} else {
					width = element.clientWidth;
					height = element.clientHeight;
				}
			
			if (element.offsetParent) {
				do {
					x += element.offsetLeft;
					y += element.offsetTop;
				} while (element = element.offsetParent);
				
			} else {
				return null;
			}
			
			return {
				x: x,
				y: y,
				width: width,
				height: height
			};
			
		}
		
		return null;

	}		
	
}