//////////////////////////
// Interface Observable //
//////////////////////////

Observable = {
	addListener : function(listenerObj) {
		if (typeof this.listeners == 'undefined') {
			this.listeners=[];
		}
		for (var i=0; i<this.listeners.length; i++) {
			if (this.listeners[i]==listenerObj) return;
		}
		this.listeners[this.listeners.length]=listenerObj;
	},

	removeListener : function(listenerObj) {
		for (var i=0; i<this.listeners.length; i++) {
			if (this.listeners[i]==listenerObj) {
				this.listeners.splice(i,1);
				return;
			}
		}
	},
	
	notifyListeners : function (eventName,eventObj) {
		if (typeof this.listeners == 'undefined') return;
		for (var i=0; i< this.listeners.length; i++) {
			if (typeof this.listeners[i][eventName]!="undefined") {
				this.listeners[i][eventName](eventObj);
			}
		}
	}
};

DHTMLApi = {
	
	CSS : {
		getStyle: function (element, name) {
			var styleObj;
			if (element.style[name]) return element.style[name];
			if (element.currentStyle) {	
				name=name.replace(/-([a-z])/g, function (matched) {
					return matched.toUpperCase().slice(1, matched.length);
				});
				return element.currentStyle[name];
			}
			if (document.defaultView && document.defaultView.getComputedStyle) {
				name=name.replace(/([A-Z])/g,"-$1");
				name=name.toLowerCase();
				styleObj=document.defaultView.getComputedStyle(element,"");
				return styleObj && styleObj.getPropertyValue(name);
			} else {
				return null;
			}
		},
		
		setProperties: function (element, properties) {
			var oldProperties={};
			for (var i in properties) {
				oldProperties[i]=element.style[i];
				element.style[i]=properties[i];
			}
			return oldProperties;
		},
		
		setClass:function (element,addClassesArray,removeClassesArray) {
			var currentClasses=new Array();
			var newClasses=new Array();
			var removedClasses=new Array();
			findWordsExp=new RegExp("\\w+", "g");
			var result;
			while ((result= findWordsExp.exec(element.className))!= null) currentClasses.push(result[0]); 
			for (var i=0; i<addClassesArray.length; i++) {
				var classExists=false;
				for (var j=0; j<currentClasses.length; j++) {
					if (currentClasses[j]==addClassesArray[i]) {
						classExists=true;
						break;
					}					
				}
				if (!classExists) newClasses.push(addClassesArray[i]);
			}
			currentClasses=currentClasses.concat(newClasses);
			if (removeClassesArray==null) return removedClasses;
			for (var i=0; i<removeClassesArray.length; i++) {
				for (var j=0; j<currentClasses.length; j++) {
					if (currentClasses[j]==removeClassesArray[i]) {
						removedClasses=removedClasses.concat(currentClasses.splice(j,1));
						break;
					}					
				}
			}
			element.className=currentClasses.join(" ");
			return removedClasses;
		}
	},
	
	Position : {
		getXPosOnPage: function (element) {
			return element.offsetParent?element.offsetLeft+DHTMLApi.Position.getXPosOnPage(element.offsetParent):element.offsetLeft;
		},
		
		getYPosOnPage: function (element) {
			return element.offsetParent?element.offsetTop+DHTMLApi.Position.getYPosOnPage(element.offsetParent):element.offsetTop;
		},
		
		getXPosInElement: function (element,container) {
			return DHTMLApi.Position.getXPosOnPage(element)-DHTMLApi.Position.getXPosOnPage(container);
		},
		
		getYPosInElement: function (element,container) {
			return DHTMLApi.Position.getYPosOnPage(element)-DHTMLApi.Position.getYPosOnPage(container);
		},
		
		setXPosOnPage: function (element,posX) {
			var propertiesArray={};
			if (element.parentNode!=document.body) {
				element=element.parentNode.removeChild(element);
				document.body.appendChild(element);
			}
			if (DHTMLApi.CSS.getStyle(element,"position")!="absolute") {
				propertiesArray={position: "absolute"};
			}
			propertiesArray.left=posX+"px";
			DHTMLApi.CSS.setProperties(element,propertiesArray);
		},
		
		setYPosOnPage: function (element,posY) {
			var propertiesArray={};
			if (element.parentNode!=document.body) {
				element=element.parentNode.removeChild(element);
				document.body.appendChild(element);
			}
			if (DHTMLApi.CSS.getStyle(element,"position")!="absolute") {
				propertiesArray={position: "absolute"};
			}
			propertiesArray.top=posY+"px";
			DHTMLApi.CSS.setProperties(element,propertiesArray);
		},
		
		setXPos: function (element, posX, relativeToElement) {
			if (relativeToElement==undefined) {
				element.style.left=posX+"px";
			} else {
				if(DHTMLApi.CSS.getStyle(element.parentNode,"position")=="static"){
					element.parentNode.style.position="relative";
				}
				element.style.position="absolute";
				element.style.left=(posX-DHTMLApi.Position.getXPosInElement(element.parentNode,relativeToElement))+"px";
			}
		},
		
		setYPos: function (element, posY, relativeToElement) {
			if (relativeToElement==undefined) {
				element.style.top=posY+"px";
			} else {
				if(DHTMLApi.CSS.getStyle(element.parentNode,"position")=="static"){
					element.parentNode.style.position="relative";
				}
				element.style.position="absolute";
				element.style.top=(posY-DHTMLApi.Position.getYPosInElement(element.parentNode,relativeToElement))+"px";
			}
		}
		
	},
	
	Size : { 
		
		getElementWidth : function (element) {
			var tempProperties, width;
			if (DHTMLApi.CSS.getStyle(element, "display" ) != "none") {
				return element.offsetWidth || parseInt(DHTMLApi.CSS.getStyle(element, "width"));
			}
			tempProperties=DHTMLApi.CSS.setProperties(element, {display: "block", visibility: "hidden", position: "absolute"});
			width=element.clientWidth || parseInt(DHTMLApi.CSS.getStyle(element, "width"));
			DHTMLApi.CSS.setProperties(element, {display: "", visibility: "", position: ""});
			DHTMLApi.CSS.setProperties(element,tempProperties);
			return width;		
		},
		
		getElementHeight : function (element) {
			var tempProperties, height;
			if (DHTMLApi.CSS.getStyle(element, "display" ) != "none") {
				return element.offsetHeight || parseInt(DHTMLApi.CSS.getStyle(element, "height"));
			}
			tempProperties=DHTMLApi.CSS.setProperties(element, {display: "block", visibility: "hidden", position: "absolute"});
			height=element.clientHeight || parseInt(DHTMLApi.CSS.getStyle(element, "height"));
			DHTMLApi.CSS.setProperties(element, {display: "", visibility: "", position: ""});
			DHTMLApi.CSS.setProperties(element,tempProperties);
			return height;
		},
		
		getPageWidth: function () {
			return document.body.scrollHeight;
		},
		
		getPageHeight: function () {
			return Math.max(document.body.scrollHeight,document.body.offsetHeight);
		}
	
	},
	
	Visibility: {
		
		show: function (element) {
			element.style.display=element.__display__ || 'block';
		},
		
		hide: function (element) {
			var currentDisplay=DHTMLApi.CSS.getStyle(element,"display");
			if (currentDisplay != 'none') element.__display__=currentDisplay;
			element.style.display='none';
		},
		
		setOpacity: function (element,percent) {
			if (element.filters) {	
				element.style.filter='alpha(opacity='+percent+')';
			} else {
				element.style.opacity=percent/100;
			}
		}
		
	},
	
	Browser : {
		
		getViewportWidth: function () {
			return self.innerWidth || (document.documentElement && document.documentElement.clientWidth) || document.body.clientWidth;
		},
		
		getViewportHeight: function () {
			return self.innerHeight || (document.documentElement && document.documentElement.clientHeight) || document.body.clientHeight;
		},
		
		getScrollX: function () {
			return self.pageXOffset || (document.documentElement && document.documentElement.scrollLeft) || document.body.scrollLeft;
		},
		
		getScrollY: function () {
			return self.pageYOffset || (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
		}		
	}
};

MousePositionOnPage = {
	getX: function (mouseEvent) {
		return mouseEvent.pageX || mouseEvent.clientX+DHTMLApi.Browser.getScrollX();
	},
	getY: function (mouseEvent) {
		return mouseEvent.pageY || mouseEvent.clientY+DHTMLApi.Browser.getScrollY();
	}
};

function DOMEventHandle(element, type, handler) {
	this.element=element;
	this.type=type;
	this.handler=handler;
}

DOMEvent = {	

	// public
	
	addDomListener: function (element, type, handler) {
		var handlers;
		if (!handler.__id__) handler.__id__ = DOMEvent.currentId++;
		if (!element.events) element.events = {};
		handlers = element.events[type];
		if (!handlers) {
    		handlers = element.events[type] = {};
		    if (element["on" + type]) {
      			handlers[0] = element["on" + type];
    		}
  		}
		handlers[handler.__id__] = handler;
		element["on" + type] = DOMEvent.handleEvent;
		return new DOMEventHandle(element, type, handler);
	},
	
	removeListener: function (domEventHandleObj) {
		var element,type,handler;
		element=domEventHandleObj.element;
		type=domEventHandleObj.type;
		handler=domEventHandleObj.handler;
		if (element.events && element.events[type]) {
   			delete element.events[type][handler.__id__];
  		}
	},
	
	preventDefault: function (eventObj) {
		if (eventObj.preventDefault) {
			eventObj.preventDefault();
		} else {
			eventObj.returnValue=false;
		}
	},
	
	stopPropagation: function (eventObj) {
		if (eventObj.stopPropagation) {
			e.stopPropagation();
		} else {
			e.cancelBubble=true;
		}
	},
	
	// private
	
	currentId: 1,
	
	handleEvent: function (event) {
  		var handlers;
		event = event || window.event;
  		handlers = this.events[event.type];
  		for (var i in handlers) {
    		this.__handleEvent = handlers[i];
    		this.__handleEvent(event);
  		}
		this.__handleEvent=null;
	}
};


MousePositionOnPage = {
	getX: function (mouseEvent) {
		return mouseEvent.pageX || mouseEvent.clientX+DHTMLApi.Browser.getScrollX();
	},
	getY: function (mouseEvent) {
		return mouseEvent.pageY || mouseEvent.clientY+DHTMLApi.Browser.getScrollY();
	}
};

///////////////////////////
// ScaledBackgroundImage //
///////////////////////////

ScaledBackgroundImage = {
	create : function (imagePath) {
		var obj=this;
		this.imagePath=imagePath;
		this.preloader=new ImagePreloader([imagePath]);
		this.preloader.addListener(this);
		this.preloader.start();		
		var bodyElement=document.getElementsByTagName("BODY")[0];
		this.container=document.createElement("DIV");
		bodyElement.insertBefore(this.container,bodyElement.firstChild);
		DHTMLApi.CSS.setProperties(this.container, {overflow: "hidden", width: DHTMLApi.Browser.getViewportWidth()+"px", height: DHTMLApi.Browser.getViewportHeight() + "px"});
		/*this.imageElement=document.createElement("IMG");
		this.container.appendChild(this.imageElement);
		DHTMLApi.Visibility.hide(this.imageElement);
		this.imageElement.onload=function () {
			DHTMLApi.Visibility.show(obj.imageElement);
			DHTMLApi.Visibility.setOpacity(obj.imageElement, 1);
			obj.animation=new Animation.Fade(obj.imageElement, 1);
			obj.animation.setFade(100, 15);
		};
		
		this.imageElement.src=imagePath;
		this.ratio=1.0*DHTMLApi.Size.getElementHeight(this.imageElement)/DHTMLApi.Size.getElementWidth(this.imageElement);
		DHTMLApi.CSS.setProperties(this.imageElement, {width: DHTMLApi.Browser.getViewportWidth()+"px", height: Math.round(this.ratio*DHTMLApi.Browser.getViewportWidth())+"px"});
		
		DOMEvent.addDomListener(window, "resize", function () {
			DHTMLApi.CSS.setProperties(obj.container, {width: DHTMLApi.Browser.getViewportWidth()+"px", height: DHTMLApi.Browser.getViewportHeight() + "px"});
			DHTMLApi.CSS.setProperties(obj.imageElement, {width: DHTMLApi.Browser.getViewportWidth()+"px", height: Math.round(obj.ratio*DHTMLApi.Browser.getViewportWidth())+"px"});
		});
		*/
	},
	
	onImageLoad : function (eventObject) {
		var obj=this;
		this.imageElement=document.createElement("IMG");
		this.imageElement.setAttribute("src",this.imagePath);
		this.container.appendChild(this.imageElement);
		
		DHTMLApi.Visibility.setOpacity(this.imageElement, 1);
		this.ratio=1.0*DHTMLApi.Size.getElementHeight(this.imageElement)/DHTMLApi.Size.getElementWidth(this.imageElement);
		DHTMLApi.CSS.setProperties(this.imageElement, {width: DHTMLApi.Browser.getViewportWidth()+"px", height: Math.round(this.ratio*DHTMLApi.Browser.getViewportWidth())+"px"});
		
		DOMEvent.addDomListener(window, "resize", function () {
			DHTMLApi.CSS.setProperties(obj.container, {width: DHTMLApi.Browser.getViewportWidth()+"px", height: DHTMLApi.Browser.getViewportHeight() + "px"});
			DHTMLApi.CSS.setProperties(obj.imageElement, {width: DHTMLApi.Browser.getViewportWidth()+"px", height: Math.round(obj.ratio*DHTMLApi.Browser.getViewportWidth())+"px"});
		});
		
		this.animation=new Animation.Fade(this.imageElement, 1);
		this.animation.setFade(100, 15);
	}
}

////////////////////
// Class Rollover //
////////////////////

function Rollover(imageElement,rolloverPicPath) {
	var rolloverImage;

	this.imageObject=imageElement;
	rolloverImage= new Image();
	rolloverImage.src=rolloverPicPath;
	this.rolloutImageSrc=this.imageObject.src;
	this.rolloverImageSrc=rolloverPicPath;
	this.init();
}

Rollover.prototype.setNormalStateImage=function (normalStatePicPath) {
	this.imageObject.src=normalStatePicPath;
	this.rolloutImageSrc=this.imageObject.src;
}

Rollover.prototype.init=function () {
	var obj=this;
	DOMEvent.addDomListener(this.imageObject, "mouseover", function () {
		this.src=obj.rolloverImageSrc;
	});
	DOMEvent.addDomListener(this.imageObject, "mouseout", function () {
		this.src=obj.rolloutImageSrc;
	});	
}

function implementsInterface() {
	var prototypeObj=new Object();
	for (var i=0; i<arguments.length; i++) {
		for (var method in arguments[i]) {
			prototypeObj[method]=arguments[i][method];
		}	
	}
	return prototypeObj;
}

//////////////////////////
// Interface Observable //
//////////////////////////

Observable = {
	addListener : function(listenerObj) {
		if (typeof this.listeners == 'undefined') {
			this.listeners=new Array();
		}
		for (var i=0; i<this.listeners.length; i++) {
			if (this.listeners[i]==listenerObj) return;
		}
		this.listeners[this.listeners.length]=listenerObj;
	},

	removeListener : function(listenerObj) {
		for (var i=0; i<this.listeners.length; i++) {
			if (this.listeners[i]==listenerObj) {
				this.listeners.splice(i,1);
				return;
			}
		}
	},
	
	notifyListeners : function (eventName,eventObj) {
		if (typeof this.listeners == 'undefined') return;
		for (var i=0; i< this.listeners.length; i++) {
			if (typeof this.listeners[i][eventName]!="undefined") {
				this.listeners[i][eventName](eventObj);
			}
		}
	}
}

/////////////////////////////////////////////
// Class Draggable (implements Observable) //
/////////////////////////////////////////////

/************************************
 listenerObj must implement methods:	
 onDragStop(DraggableEventObj event)
 onDrag(DraggableEventObj event)
************************************/

DraggableMode= {HORIZONTAL : 1,VERTICAL : 2,HORIZONTAL_VERTICAL : 3};

function Draggable(dragObj,dragHandleObj,boundingObj,dragMode) {
	this.dragObj=dragObj;
	if (dragHandleObj==null) {
		this.dragHandle=this.dragObj;
	} else {
		this.dragHandle=dragHandleObj;
	}
	this.mode=dragMode;
	this.boundingObj = boundingObj;			
	this.boundingBox = this.getBoundingBox();
	
	this.mousePosXOnHandle=null;
	this.mousePosYOnHandle=null;
	
	this.mouseDownHandler=null;
	this.mouseUpHandler=null;
	this.mouseMoveHandler=null;
};

Draggable.prototype = implementsInterface(Observable);

Draggable.prototype.set=function() {
	var obj=this;
	
	function dragStart(e) {
		obj.notifyListeners("onDragStart",obj.getDraggableEventObj());
		obj.boundingBox = obj.getBoundingBox();
		obj.mousePosXOnHandle=MousePositionOnPage.getX(e)-DHTMLApi.Position.getXPosOnPage(obj.dragObj);
		obj.mousePosYOnHandle=MousePositionOnPage.getY(e)-DHTMLApi.Position.getYPosOnPage(obj.dragObj);
		obj.mouseMoveHandler=DOMEvent.addDomListener(document, "mousemove" , drag);
		obj.mouseUpHandler=DOMEvent.addDomListener(document, "mouseup" , dragEnd);
		DOMEvent.preventDefault(e);
	}
	
	function dragEnd(e) {
		DOMEvent.removeListener(obj.mouseMoveHandler);
		DOMEvent.removeListener(obj.mouseUpHandler);
		obj.notifyListeners("onDragStop",obj.getDraggableEventObj());
	}
	
	function drag(e) {
		var dragObjPosX,dragObjPosY;
		DOMEvent.preventDefault(e);
		dragObjPosX=obj.calculatePosX(MousePositionOnPage.getX(e));
		dragObjPosY=obj.calculatePosY(MousePositionOnPage.getY(e));
		if (obj.mode!=DraggableMode.VERTICAL) {
			if (obj.boundingBox.tlX<=dragObjPosX && dragObjPosX<=obj.boundingBox.brX) {
				DHTMLApi.Position.setXPos(obj.dragObj, dragObjPosX-obj.boundingBox.tlX, obj.boundingObj);
			} else if (obj.boundingBox.tlX>dragObjPosX) {
				DHTMLApi.Position.setXPos(obj.dragObj, 0, obj.boundingObj);
			} else {
				DHTMLApi.Position.setXPos(obj.dragObj, obj.boundingBox.brX-obj.boundingBox.tlX, obj.boundingObj);
			}
		}		
		if (obj.mode!=DraggableMode.HORIZONTAL) {
			if (obj.boundingBox.tlY<=dragObjPosY && dragObjPosY<=obj.boundingBox.brY) {
				DHTMLApi.Position.setYPos(obj.dragObj, dragObjPosY-obj.boundingBox.tlY, obj.boundingObj);
			} else if (obj.boundingBox.tlY>dragObjPosY) {
				DHTMLApi.Position.setYPos(obj.dragObj, 0, obj.boundingObj);
			} else {
				DHTMLApi.Position.setYPos(obj.dragObj, obj.boundingBox.brY-obj.boundingBox.tlY, obj.boundingObj);
			}
		}
		obj.notifyListeners("onDrag",obj.getDraggableEventObj());
	}
	
	this.mouseDownHandler=DOMEvent.addDomListener(this.dragHandle, "mousedown" , dragStart);
};

Draggable.prototype.unset=function() {
	DOMEvent.removeListener(this.mouseDownHandler);
	DOMEvent.removeListener(this.mouseMoveHandler);
	DOMEvent.removeListener(this.mouseUpHandler);	
};

Draggable.prototype.getXBounds=function() {
	return (this.boundingBox.brX-this.boundingBox.tlX);
}

Draggable.prototype.getYBounds=function() {
	return (this.boundingBox.brY-this.boundingBox.tlY);
}

Draggable.prototype.setDragObjXPos=function(xPos) {
	DHTMLApi.Position.setXPos(this.dragObj, xPos, this.boundingObj);
}

Draggable.prototype.setDragObjYPos=function(yPos) {
	DHTMLApi.Position.setYPos(this.dragObj, yPos, this.boundingObj);
}

Draggable.prototype.getDragObjXPos=function() {
	return  DHTMLApi.Position.getXPosOnPage(this.dragObj)-DHTMLApi.Position.getXPosOnPage(this.boundingObj);
}

Draggable.prototype.getDragObjYPos=function() {
	return  DHTMLApi.Position.getYPosOnPage(this.dragObj)-DHTMLApi.Position.getYPosOnPage(this.boundingObj);
}

Draggable.prototype.refreshAfterResize=function() {
	this.boundingBox = this.getBoundingBox();
}

// private

Draggable.prototype.calculatePosX=function (mousePosX) {
	return mousePosX-this.mousePosXOnHandle;
};

Draggable.prototype.calculatePosY=function (mousePosY) {
	return mousePosY-this.mousePosYOnHandle;
};

Draggable.prototype.getBoundingBox= function () {
	return {
		tlX: DHTMLApi.Position.getXPosOnPage(this.boundingObj), 
		tlY: DHTMLApi.Position.getYPosOnPage(this.boundingObj),
		brX: DHTMLApi.Position.getXPosOnPage(this.boundingObj)+DHTMLApi.Size.getElementWidth(this.boundingObj)-DHTMLApi.Size.getElementWidth(this.dragObj),
		brY: DHTMLApi.Position.getYPosOnPage(this.boundingObj)+DHTMLApi.Size.getElementHeight(this.boundingObj)-DHTMLApi.Size.getElementHeight(this.dragObj)};
}

Draggable.prototype.getDraggableEventObj=function() {
	return new DraggableEventObj(DHTMLApi.Position.getXPosInElement(this.dragObj,this.boundingObj), DHTMLApi.Position.getYPosInElement(this.dragObj,this.boundingObj), this.boundingBox.brX-this.boundingBox.tlX, this.boundingBox.brY-this.boundingBox.tlY);
}

/////////////////////////////
// Class DraggableEventObj //
/////////////////////////////

function DraggableEventObj (objPosX, objPosY, boundWidth, boundHeight) {
	this.posX=objPosX;
	this.posY=objPosY;
	this.boundWidth=boundWidth;
	this.boundHeight=boundHeight;
}

///////////////////
// Class VSlider //
///////////////////

/************************************
 listenerObj must implement methods:	
 onChange(ChangeEventObj event)
 onUpperSliderBarClick(ChangeEventObj event)
 onLowerSliderBarClick(ChangeEventObj event)
************************************/

function VSlider(dragObj,boundingObj,topValue,bottomValue,initValue) {
	this.topValue=topValue;
	this.bottomValue=bottomValue;
	this.sliderBar=boundingObj;
	this.sliderBarClickHandler=null;
	this.draggableObject=new Draggable(dragObj,null,boundingObj,DraggableMode.VERTICAL);
	this.draggableObject.set();
	this.draggableObject.addListener(this);
	if (typeof initValue!= 'undefined') {
		this.setValue(initValue);
	}
	this.initSliderBar();
}

VSlider.prototype = implementsInterface(Observable);

VSlider.prototype.initSliderBar=function() {
	var obj=this;
	this.sliderBarClickHandler=DOMEvent.addDomListener(this.sliderBar, "click" , function (e) {
		var clickPosY=MousePositionOnPage.getY(e)-DHTMLApi.Position.getYPosOnPage(obj.sliderBar);
		if (clickPosY<obj.draggableObject.getDragObjYPos()) {
			obj.notifyListeners("onUpperSliderBarClick",new SliderEventObj(obj.getValue(obj.draggableObject.getDraggableEventObj())));
		}
		if (clickPosY>obj.draggableObject.getDragObjYPos()+DHTMLApi.Size.getElementHeight(obj.draggableObject.dragObj)) {
			obj.notifyListeners("onLowerSliderBarClick",new SliderEventObj(obj.getValue(obj.draggableObject.getDraggableEventObj())));
		}
	});
}

VSlider.prototype.getValue=function(draggableEventObj) {
	return this.topValue+(draggableEventObj.posY/draggableEventObj.boundHeight)*1.0*(this.bottomValue-this.topValue); 
}

VSlider.prototype.setBoundaryValues=function(topValue,bottomValue) {
	this.topValue=topValue;
	this.bottomValue=bottomValue;
}

VSlider.prototype.setValue=function(value) {
	var dragObjYPos=Math.round((value-this.topValue)*this.draggableObject.getYBounds()/(this.bottomValue-this.topValue));
	this.draggableObject.setDragObjYPos(dragObjYPos);
}

VSlider.prototype.onDragStop = function (draggableEventObj) {
	this.notifyListeners("onChange",new SliderEventObj(this.getValue(draggableEventObj)));
}

VSlider.prototype.onDrag = function (draggableEventObj) {
	this.notifyListeners("onChange",new SliderEventObj(this.getValue(draggableEventObj)));
}

function SliderEventObj (value) {
	this.value=value;
}

///////////////////
// Class VScroll //
///////////////////

function VScroll(containerElement,contentElement,sliderbarElement,sliderElement,viewport,upButton,downButton, scrollIncrement) {
	this.containerElement=containerElement;
	this.contentElement=contentElement;
	this.sliderbarElement=sliderbarElement;
	this.sliderElement=sliderElement;
	this.upButton=upButton;
	this.downButton=downButton;
	this.viewportWidth=viewport.width;
	this.viewportHeight=viewport.height;
	this.viewportPosX=viewport.x;
	this.viewportPosY=viewport.y;
	this.bottomViewportPadding=DHTMLApi.Size.getElementHeight(this.containerElement)-this.viewportHeight-this.viewportPosY;
	this.rightViewportPadding=DHTMLApi.Size.getElementWidth(this.containerElement)-this.viewportWidth-this.viewportPosX;
	this.invisibleContentHeight=null;
	this.scrollIncrement=scrollIncrement;
	this.slider=null;
	this.mask=this.buildMask();
	this.animation=new Animation.SmoothVMove(this.contentElement, this.mask);
	this.initSlider();
	this.initButtons();
	if (this.viewportHeight>DHTMLApi.Size.getElementHeight(this.contentElement)) {
		this.hideControls();
		this.controlsHidden=true;
	} else {
		this.controlsHidden=false;
	}
}

VScroll.prototype.buildMask=function() {
	var maskDiv=document.createElement("div");
	DHTMLApi.CSS.setProperties(maskDiv, {position: "absolute", left: this.viewportPosX+"px", top: this.viewportPosY+"px", width: this.viewportWidth+"px", height: this.viewportHeight+"px", overflow:'hidden'});
	this.contentElement=this.containerElement.replaceChild(maskDiv,this.contentElement);
	maskDiv.appendChild(this.contentElement);
	return maskDiv;
}

VScroll.prototype.initSlider=function() {
	var obj=this;
	this.invisibleContentHeight=DHTMLApi.Size.getElementHeight(this.contentElement)-this.viewportHeight;
	this.slider=new VSlider(this.sliderElement,this.sliderbarElement,0,-this.invisibleContentHeight,0);
	this.slider.onDragStop = function (draggableEventObj) {
		var value=this.getValue(draggableEventObj);
		obj.animation.setPosition(value);
		this.notifyListeners("onChange",new SliderEventObj(value));
	}
	this.slider.onDrag=function (draggableEventObj) {
		if (obj.animation.getAnimationStep()===null || obj.animation.getAnimationStep()>0) {
			obj.animation.setPosition(this.getValue(draggableEventObj));
		}
		this.notifyListeners("onChange",new SliderEventObj(this.getValue(draggableEventObj)));
	}
	this.slider.addListener(this);
}

VScroll.prototype.initButtons=function() {
	var obj=this;
	var mousedownInterval;
		
	DOMEvent.addDomListener(this.downButton,"mousedown",function() {
		mousedownInterval=window.setInterval(function () {obj.scrollDown(obj.scrollIncrement, true)},10);
	});
	
	DOMEvent.addDomListener(this.downButton,"mouseout",function() {
		window.clearInterval(mousedownInterval);
	});
	
	DOMEvent.addDomListener(this.downButton,"mouseup",function() {
		window.clearInterval(mousedownInterval);
	});
		
	DOMEvent.addDomListener(this.upButton,"mousedown",function() {
		mousedownInterval=window.setInterval(function () {obj.scrollUp(obj.scrollIncrement, true)},10);
	});
	
	DOMEvent.addDomListener(this.upButton,"mouseup",function() {
		window.clearInterval(mousedownInterval);
	});
	
	DOMEvent.addDomListener(this.upButton,"mouseout",function() {
		window.clearInterval(mousedownInterval);
	});
}

VScroll.prototype.hideControls=function () {
	DHTMLApi.Visibility.hide(this.upButton);
	DHTMLApi.Visibility.hide(this.downButton);
	DHTMLApi.Visibility.hide(this.sliderElement);
	DHTMLApi.Visibility.hide(this.sliderbarElement);
	DHTMLApi.Visibility.hide(this.sliderbarElement.parentNode);
}

VScroll.prototype.showControls=function () {
	DHTMLApi.Visibility.show(this.sliderbarElement.parentNode);
	DHTMLApi.Visibility.show(this.sliderbarElement);
	DHTMLApi.Visibility.show(this.sliderElement);
	DHTMLApi.Visibility.show(this.downButton);
	DHTMLApi.Visibility.show(this.upButton);
}

VScroll.prototype.setPosition=function (numOfPixels) {
	DHTMLApi.Position.setYPos(this.contentElement, -1*numOfPixels, this.containerElement);
	this.slider.setValue(-1*numOfPixels);
}

VScroll.prototype.setBottomPosition=function () {
	this.setPosition(this.invisibleContentHeight);
}

VScroll.prototype.resize=function (width, height) {
	if (height<DHTMLApi.Size.getElementHeight(this.contentElement)) {
		if (this.controlsHidden) {
			DHTMLApi.CSS.setProperties(this.mask, {overflow:'hidden'});
			this.showControls();
			this.controlsHidden=false;
		}
		this.resizeElements(width, height);
		this.recalculateAfterResize(width, height);
	} else {
		if (!this.controlsHidden) {
			this.hideControls();
			this.setPosition(0);
			this.controlsHidden=true;
			DHTMLApi.CSS.setProperties(this.mask, {overflow:'visible'});
		}
	}
}

VScroll.prototype.resizeElements=function(width, height) {
	var heightDifference,widthDifference;
	heightDifference=height-DHTMLApi.Size.getElementHeight(this.containerElement);
	widthDifference=width-DHTMLApi.Size.getElementWidth(this.containerElement);
	DHTMLApi.CSS.setProperties(this.containerElement, {width: width+"px", height: height+"px"});
	DHTMLApi.CSS.setProperties(this.mask, {width: (width-this.rightViewportPadding-this.viewportPosX)+"px", height: (height-this.bottomViewportPadding-this.viewportPosY)+"px"});
	DHTMLApi.CSS.setProperties(this.sliderbarElement, {height: (DHTMLApi.Size.getElementHeight(this.sliderbarElement)+heightDifference)+"px"});
	DHTMLApi.CSS.setProperties(this.sliderbarElement.parentNode, {height: height+"px"});
	DHTMLApi.CSS.setProperties(this.downButton, {top: (height-(DHTMLApi.Size.getElementHeight(this.downButton)))+"px", height: DHTMLApi.Size.getElementHeight(this.downButton)+"px", width: DHTMLApi.Size.getElementWidth(this.downButton)+"px"});
	DHTMLApi.CSS.setProperties(this.contentElement, {width: (DHTMLApi.Size.getElementWidth(this.contentElement)+widthDifference)+"px"});
}

VScroll.prototype.recalculateAfterResize=function(width, height) {
	this.viewportWidth=width-this.rightViewportPadding-this.viewportPosX;
	this.viewportHeight=height-this.bottomViewportPadding-this.viewportPosY;
	this.invisibleContentHeight=DHTMLApi.Size.getElementHeight(this.contentElement)-this.viewportHeight;
	this.slider.setBoundaryValues(0,-this.invisibleContentHeight);
	this.slider.draggableObject.refreshAfterResize();
	if (DHTMLApi.Position.getYPosInElement(this.contentElement,this.containerElement)<-1*this.invisibleContentHeight) {
		DHTMLApi.Position.setYPos(this.contentElement, -1*this.invisibleContentHeight, this.containerElement);
	} 
	this.slider.setValue(DHTMLApi.Position.getYPosInElement(this.contentElement,this.containerElement));
	
}

VScroll.prototype.scrollUp=function (scrollIncrement, refreshSliderPos) {
	var targetPosY;
	if ((this.getCurrentScrollPosition()+scrollIncrement) >= 0) {
			targetPosY=0;
		} else {
			targetPosY=this.getCurrentScrollPosition()+scrollIncrement;
		}
		if (refreshSliderPos) {
			this.animation.setPosition(targetPosY);
			this.slider.setValue(targetPosY);
		} else {
			this.animation.setPosition(targetPosY);
			this.animation.addListener(this);
		}
}

VScroll.prototype.scrollDown=function (scrollIncrement, refreshSliderPos) {
	var targetPosY;
	if ((this.getCurrentScrollPosition() - scrollIncrement) < -this.invisibleContentHeight) {
			targetPosY=-this.invisibleContentHeight;
		} else {
			targetPosY=this.getCurrentScrollPosition()- scrollIncrement;
		}
		if (refreshSliderPos) {
			this.animation.setPosition(targetPosY);
			this.slider.setValue(targetPosY);
		} else {
			this.animation.setPosition(targetPosY);
			this.animation.addListener(this);
		}
}

VScroll.prototype.getCurrentScrollPosition=function() {
	return DHTMLApi.Position.getYPosInElement(this.contentElement,this.mask);
}

VScroll.prototype.scrollToTop=function() {
	this.scrollTo(0);
}

VScroll.prototype.scrollTo=function (pixelValue) {
	if (pixelValue<this.invisibleContentHeight) {
		this.animation.setPosition(-1*pixelValue);
	} else {
		this.animation.setPosition(-1*this.invisibleContentHeight);
	}
	this.animation.addListener(this);
}

VScroll.prototype.onUpperSliderBarClick=function(event) {
	this.scrollUp(this.viewportHeight,false);
}

VScroll.prototype.onLowerSliderBarClick=function(event) {
	this.scrollDown(this.viewportHeight,false);
}

VScroll.prototype.onAnimationStep=function() {
	this.slider.setValue(this.getCurrentScrollPosition());
}

VScroll.prototype.onAnimationEnd=function() {
	//if (this.initialAnimation===null) {
		this.animation.removeListener(this);
	//}
}

///////////////////////
// Package Animation //
///////////////////////

Animation= new Object();

Animation.FRAME_RATE=50; // miliseconds

/////////////////////////////////
// Class Animation.SmoothVMove //
/////////////////////////////////

Animation.SmoothVMove=function(movingObject, relativeToObject) {
	this.movingObject=movingObject;
	this.relativeToObject=relativeToObject;
	this.currentYPos=DHTMLApi.Position.getYPosInElement(movingObject,relativeToObject);
	this.targetYPos=null;
	this.interval=null;
	this.numOfAnimationStep=null;
}

Animation.SmoothVMove.prototype=implementsInterface(Observable);

Animation.SmoothVMove.prototype.setPosition=function (targetPosition) {
	this.currentYPos=DHTMLApi.Position.getYPosInElement(this.movingObject,this.relativeToObject);
	if (this.interval!==null) {
		window.clearInterval(this.interval);
		this.notifyListeners("onAnimationEnd",null);
	}
	var animationObject=this;
	this.targetYPos=targetPosition;
	this.numOfAnimationStep=0;
	this.notifyListeners("onAnimationStart",null);
	this.animate();
	this.interval=window.setInterval(function() {animationObject.animate()},Animation.FRAME_RATE);
}

Animation.SmoothVMove.prototype.animate=function () {
	var stepDistance=(this.targetYPos-this.currentYPos)/3;
	if (Math.abs(stepDistance)>0.3) {
		this.currentYPos+=stepDistance;
		DHTMLApi.Position.setYPos(this.movingObject, this.currentYPos, this.relativeToObject);
		++this.numOfAnimationStep;
		this.notifyListeners("onAnimationStep",this.numOfAnimationSteps);
		return this.numOfAnimationStep;
	} else {
		this.currentYPos=this.targetYPos;
		DHTMLApi.Position.setYPos(this.movingObject, this.currentYPos, this.relativeToObject);
		this.notifyListeners("onAnimationStep",++this.numOfAnimationSteps);
		window.clearInterval(this.interval);
		this.notifyListeners("onAnimationEnd",null);
		this.numOfAnimationStep=null;
		return false;
	}
}

Animation.SmoothVMove.prototype.getAnimationStep=function () {
	return this.numOfAnimationStep;
}


//////////////////////////
// Class Animation.Fade //
//////////////////////////

Animation.Fade=function (fadeObject, currentOpacityPercentage) {
	this.fadeObject=fadeObject;
	this.currentOpacityPercentage=currentOpacityPercentage;
	this.interval=null;
	this.targetOpacityPercentage=null;
	this.currentAnimationStep=null;
	this.numOfAnimationSteps=null;
	DHTMLApi.Visibility.setOpacity(this.fadeObject,Math.round(this.currentOpacityPercentage));
}

Animation.Fade.prototype=implementsInterface(Observable);

Animation.Fade.prototype.setFade=function (targetOpacityPercentage, numOfSteps) {
	this.stop();
	var animationObject=this;
	this.targetOpacityPercentage=targetOpacityPercentage;
	this.opacityStep=1.0*(targetOpacityPercentage-this.currentOpacityPercentage)/numOfSteps;
	this.numOfAnimationSteps=numOfSteps;
	this.currentAnimationStep=0;
	this.notifyListeners("onAnimationStart",null);
	this.animate();
	this.interval=window.setInterval(function() {animationObject.animate()},Animation.FRAME_RATE);
}

Animation.Fade.prototype.animate=function () {
	if (this.currentAnimationStep<this.numOfAnimationSteps) {
		this.currentOpacityPercentage+=this.opacityStep;
		DHTMLApi.Visibility.setOpacity(this.fadeObject,Math.round(this.currentOpacityPercentage));
		this.notifyListeners("onAnimationStep",this.currentAnimationStep);
		++this.currentAnimationStep;
		return this.numOfAnimationStep;
	} else {
		this.currentOpacityPercentage=this.targetOpacityPercentage;
		DHTMLApi.Visibility.setOpacity(this.fadeObject,Math.round(this.currentOpacityPercentage));
		this.notifyListeners("onAnimationStep",this.currentAnimationStep);
		window.clearInterval(this.interval);
		this.notifyListeners("onAnimationEnd",null);
		this.numOfAnimationStep=null;
		return false;
	}
}

Animation.Fade.prototype.stop=function() {
	if (this.interval!==null) {
		window.clearInterval(this.interval);
		this.notifyListeners("onAnimationEnd",null);
	}
}

//////////////////////////
// Class ImagePreloader //
//////////////////////////

/* broadcasts
	onImageLoad - event Object - img url string
	onAllImagesLoad + event Object - array of imgs url string
*/

function ImagePreloader(imgUrlArray) {
	this.imgUrlArray=imgUrlArray;
	this.imgPreloadingIndex=0;
	this.isPreloading=false;
	this.preloadInterval=null;
	this.imageIsPreloaded=false;
}

ImagePreloader.prototype=implementsInterface(Observable);

ImagePreloader.prototype.preload=function() {
	
	var obj=this;
	if (this.imgPreloadingIndex>=this.imgUrlArray.length) return; 
	this.preloadInterval=window.setInterval(function () {
		if (obj.imageIsPreloaded===false && obj.isPreloading==false) {
			obj.preloadImage(obj.imgPreloadingIndex);
			return;
		}
		if (obj.imgPreloadingIndex==(obj.imgUrlArray.length-1)) {
			window.clearInterval(obj.preloadInterval);
		} else {
			if (obj.imageIsPreloaded===true) {
				obj.imgPreloadingIndex++;
				obj.preloadImage(obj.imgPreloadingIndex);
			}
		}
													  
	}, 150);	
}

ImagePreloader.prototype.preloadImage=function (imageNum) {
	var obj=this;
	this.isPreloading=true;
	var img=new Image();
	this.imageIsPreloaded=false;
	img.onload=img.onerror=function () {
		obj.notifyListeners("onImageLoad",obj.imgUrlArray[obj.imgPreloadingIndex]);
		obj.imageIsPreloaded=true;
		if ((obj.imgUrlArray.length-1)==obj.imgPreloadingIndex) {
			obj.notifyListeners("onAllImagesLoad",obj.imgUrlArray);
		}
	}
	img.src=this.imgUrlArray[imageNum];
}

ImagePreloader.prototype.start=function () {
	this.preload();
}

ImagePreloader.prototype.stop=function () {
	this.isPreloading=false;
	this.imageIsPreloaded=false;
	if (this.preloadInterval!==null) {
		window.clearInterval(this.preloadInterval);
		this.preloadInterval=null;
	}
}