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

function addObjectMethods(targetClass, methodObject) {
	for (var method in methodObject) {
		targetClass.prototype[method]=methodObject[method];
	}
}

//////////////////////////
// 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);
			}
		}
	}
};

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) {
			eventObj.stopPropagation();
		} else {
			eventObj.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;
	}
};

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 Math.max(document.body.scrollWidth,document.body.offsetWidth);
		},
		
		getPageHeight: function () {
			var height=(typeof document.documentElement != "undefined" && typeof document.documentElement.offsetHeight != "undefined") ? document.documentElement.offsetHeight : 0;
			return Math.max(document.body.scrollHeight,document.body.offsetHeight,height);
		}
	
	},
	
	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();
	}
};

/////////////////////////
// class FormValidator //
/////////////////////////

/*
formFields = {required: [id1, id2, ...], email: [id1, id2, ...], numeric: [id1, id2, ...], confirm: [[id1, id1a,...],[id2, id2a,...],]}
errorMessages = {required: string, email: string, numeric: string, confirm: string}
cssStyles = {invalidEntryField : string}
*/

function FormValidator(formElement,errorMsgContainerDiv,submitButtonElement,formFields,cssStyles,errorMessages,onSubmitCallBack) {
	this.formElement=formElement;
	this.errorMsgContainerDiv=errorMsgContainerDiv;
	this.cssStyles=cssStyles;
	if (typeof formFields.required !="undefined") {
		this.requiredFields=this.getElementsById(formFields.required);
	} else {
		this.requiredFields={};
	}
	if (typeof formFields.email !="undefined") {
		this.emailFields=this.getElementsById(formFields.email);
	} else {
		this.emailFields={};
	}
	if (typeof formFields.numeric !="undefined") {
		this.numericFields=this.getElementsById(formFields.numeric);
	} else {
		this.numericFields={};
	}
	if (typeof onSubmitCallBack !="undefined") {
		this.onSubmitCallBack=onSubmitCallBack;
	}
	this.confirmFields=[];
	if (typeof formFields.confirm !="undefined") {
		for (var i=0; i<formFields.confirm.length; i++) {
			if (formFields.confirm[i].length>1) {
				this.confirmFields[i]=this.getElementsById(formFields.confirm[i]);
			}
		}
	}
	this.submitButtonElement=submitButtonElement;
	this.errorMessages=errorMessages;
	this.init();
}

FormValidator.prototype.init=function () {
	var obj=this;
	DOMEvent.addDomListener(this.submitButtonElement,"click",function (eventObj) {
		DOMEvent.preventDefault(eventObj);
		obj.submit();
	});
};

FormValidator.prototype.getElementsById=function (elementIdArray) {
	var elements={};
	for (var i=0; i<elementIdArray.length; i++) {
		elements[elementIdArray[i]]=document.getElementById(elementIdArray[i]);
	}
	return elements;
};

FormValidator.prototype.checkRequiredField=function(inputElement) {
	return !((inputElement.value.search(/\w/)==-1) ? true : false);
};

FormValidator.prototype.checkEmailField=function(inputElement) {
	return (inputElement.value!="" && inputElement.value.search(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,6}$/i)==-1) ? false : true;
};

FormValidator.prototype.checkNumericField=function(inputElement) {
	return (inputElement.value!="" && inputElement.value.search(/^[-+]?[0-9]*\.?[0-9]+$/)==-1) ? false : true;
};

FormValidator.prototype.checkConfirmField=function(inputElementObject) {
	var value;
	for (var id in inputElementObject) {
		value=inputElementObject[id].value;
		break;
	}
	for (var id in inputElementObject) {
		if (value!=inputElementObject[id].value) return false;
	}
	return true;
};

FormValidator.prototype.checkFields=function (inputFieldsObject,checkFunction) {
	var isOK=true;
	for (var id in inputFieldsObject) {
		if (checkFunction(inputFieldsObject[id])) {
			this.markFieldOK(inputFieldsObject[id]);
		} else {
			this.markFieldBad(inputFieldsObject[id]);
			isOK=false;
		}
	}
	return isOK;
};

FormValidator.prototype.markFieldOK=function (inputField) {
	DHTMLApi.CSS.setClass(inputField,[],new Array(this.cssStyles.invalidEntryField));
};

FormValidator.prototype.markFieldBad=function (inputField) {
	DHTMLApi.CSS.setClass(inputField,new Array(this.cssStyles.invalidEntryField),[]);
};

FormValidator.prototype.checkRequiredFields=function() {
	var okInput=this.checkFields(this.requiredFields,this.checkRequiredField);	
	if (!okInput) {
		this.displayErrorMessage(this.errorMessages.required);
		return false;
	} else {
		this.clearErrorMessage();
		return true;
	}
};

FormValidator.prototype.checkEmailFields=function() {
	var okInput=this.checkFields(this.emailFields,this.checkEmailField);	
	if (!okInput) {
		this.displayErrorMessage(this.errorMessages.email);
		return false;
	} else {
		this.clearErrorMessage();
		return true;
	}
};

FormValidator.prototype.checkNumericFields=function() {
	var okInput=this.checkFields(this.numericFields,this.checkNumericField);	
	if (!okInput) {
		this.displayErrorMessage(this.errorMessages.numeric);
		return false;
	} else {
		this.clearErrorMessage();
		return true;
	}
};

FormValidator.prototype.checkConfirmFields=function() {
	var okInput;
	for (var i=0; i<this.confirmFields.length; i++) {
		for (var id in this.confirmFields[i]) this.markFieldOK(this.confirmFields[i][id]);
	}
	this.clearErrorMessage();
	for (var i=0; i<this.confirmFields.length; i++) {
		okInput=this.checkConfirmField(this.confirmFields[i]);
		if (okInput===false) {
			for (var id in this.confirmFields[i]) this.markFieldBad(this.confirmFields[i][id]);
			this.displayErrorMessage(this.errorMessages.confirm);
			return false;
		} 
	}
};

FormValidator.prototype.displayErrorMessage=function(errorString) {
	this.errorMsgContainerDiv.innerHTML=errorString;
};

FormValidator.prototype.clearErrorMessage=function () {
	this.errorMsgContainerDiv.innerHTML="";
};

FormValidator.prototype.check=function() {
	if (this.checkRequiredFields()===false) {
		return false;
	}
	if (this.checkConfirmFields()===false) {
		return false;
	}
	if (this.checkEmailFields()===false) {
		return false;
	}
	if (this.checkNumericFields()===false) {
		return false;
	}
	return true;
};

FormValidator.prototype.submit=function() {
	if (this.check()) {
		if (typeof onSubmitCallBack !="undefined") {
			(this.onSubmitCallBack)();
		} 
		this.formElement.submit();
	}
};



/////////////////////
// Class SlideShow //
/////////////////////

function SlideShow(imagesUrlArray, containerElement, slideDurationInSec, numOfTransitionIterations, numOfTransitionMixIterations) {
	this.container=containerElement;
	this.imagesUrlArray=imagesUrlArray;
	this.numOfImagesPreloaded=1;
	this.preloader=new ImagePreloader(this.imagesUrlArray.slice(1));
	this.currentSlide=1;
	this.slideDuration=Math.round(slideDurationInSec*1000);
	this.numOfTransitionIterations=numOfTransitionIterations;
	this.playInterval=null;
	this.foregroundSlide=document.createElement("IMG");
	this.backgroundSlide=document.createElement("IMG");
	this.fadeOutAnimation=null;
	this.fadeInAnimation=null;
	this.slideShowIsPlaying=false;
	this.numOfStartFadeInIteration=numOfTransitionIterations-numOfTransitionMixIterations;
	if (this.numOfStartFadeInIteration<1) {
		this.numOfStartFadeInIteration=1;
	}
	if (this.numOfStartFadeInIteration>=this.numOfTransitionIterations) {
		this.numOfStartFadeInIteration=this.numOfTransitionIterations-1;
	}
	this.preloader.addListener(this);
	this.init();
}

SlideShow.prototype.init=function() {
	var obj=this;
	DHTMLApi.CSS.setProperties(this.container, {position:"relative", overflow:"hidden"});
	this.container.appendChild(this.foregroundSlide);
	this.container.appendChild(this.backgroundSlide);
	DHTMLApi.CSS.setProperties(this.foregroundSlide, {position:"absolute", zIndex:2});
	DHTMLApi.CSS.setProperties(this.backgroundSlide, {position:"absolute", zIndex:1});
	DHTMLApi.Visibility.hide(this.foregroundSlide);
	DHTMLApi.Visibility.hide(this.backgroundSlide);
	this.displaySlide(this.foregroundSlide,this.currentSlide, 100);
}

SlideShow.prototype.displaySlide=function(slide, slideNum, opacity) {
	var obj=this;
	var img=new Image();
	img.onload=function () {
		DHTMLApi.Visibility.show(slide);
		slide.setAttribute("src",obj.imagesUrlArray[slideNum-1]);
		obj.setOpacity(slide,1);
		obj.centerSlide(slide,this.width,this.height);
		obj.setOpacity(slide,opacity);
	}
	img.src=this.imagesUrlArray[slideNum-1];
}

SlideShow.prototype.centerSlide=function (slide,slideWidth,slideHeight) {
	var posX,posY;
	posX=Math.round((DHTMLApi.Size.getElementWidth(this.container)-slideWidth)/2);
	posY=Math.round((DHTMLApi.Size.getElementHeight(this.container)-slideHeight)/2);
	DHTMLApi.CSS.setProperties(slide, {position:"absolute", left: posX+"px", top: posY+"px"});
}

SlideShow.prototype.setOpacity=function(slide,opacity) {
	DHTMLApi.Visibility.setOpacity(slide,opacity);
}

SlideShow.prototype.display=function(slideNum) {
	this.stop();
	this.currentSlide=slideNum;
	this.displaySlide(this.foregroundSlide, this.currentSlide,100);
}

SlideShow.prototype.displayNextSlide=function() {
	this.stop();
	this.currentSlide=this.getNextSlide();
	this.displaySlide(this.foregroundSlide, this.currentSlide,100);
}

SlideShow.prototype.displayPreviousSlide=function() {
	this.stop();
	this.currentSlide=this.getPreviousSlide();
	this.displaySlide(this.foregroundSlide, this.currentSlide,100);
}

SlideShow.prototype.getNextSlide=function() {
	if (this.currentSlide==this.imagesUrlArray.length) {
		return 1;
	} else {
		return this.currentSlide+1;
	}
}

SlideShow.prototype.getPreviousSlide=function() {
	if (this.currentSlide==1) {
		return this.imagesUrlArray.length;
	} else {
		return this.currentSlide-1;
	}
}

SlideShow.prototype.play=function () {
	var obj=this;
	if (this.slideShowIsPlaying) return;
	this.preloader.start();
	this.slideShowIsPlaying=true;
	this.playInterval=window.setInterval(function () {obj.playTransition();}, this.slideDuration);
}

SlideShow.prototype.playTransition=function() {
	var fadeOutListener, fadeInListener, fadeOutChannel, fadeInChannel;
	if (this.currentSlide>=this.numOfImagesPreloaded && this.numOfImagesPreloaded!=this.imagesUrlArray.length) return;
	var obj=this;
	this.fadeInAnimation=null;
	fadeOutListener=new Object();
	fadeOutListener.onAnimationEnd=function () {
		obj.fadeOutAnimation.removeListener(this);
	}
	fadeOutListener.onAnimationStart=function() {
	}
	
	fadeOutListener.onAnimationStep=function (eventObj) {
		if (eventObj==obj.numOfStartFadeInIteration) {
			obj.currentSlide=obj.getNextSlide();
			obj.displaySlide(obj.foregroundSlide, obj.currentSlide, 1);
			obj.fadeInAnimation=new Animation.Fade(obj.foregroundSlide, 1);
			obj.fadeInAnimation.setFade(100,obj.numOfTransitionIterations);
		}
	}
	
	this.displaySlide(this.backgroundSlide,this.currentSlide,100);
	this.fadeOutAnimation=new Animation.Fade(this.backgroundSlide, 100);
	this.fadeOutAnimation.addListener(fadeOutListener);
	this.fadeOutAnimation.setFade(0,this.numOfTransitionIterations);
}

SlideShow.prototype.stop=function() {
	this.preloader.stop();
	if (this.fadeOutAnimation!=null) this.fadeOutAnimation.stop();
	if (this.fadeInAnimation!=null) this.fadeInAnimation.stop();
	this.slideShowIsPlaying=false;
	DHTMLApi.Visibility.hide(this.backgroundSlide);
	this.displaySlide(this.foregroundSlide, this.currentSlide, 100);
	
	window.clearInterval(this.playInterval);
}

SlideShow.prototype.onImageLoad=function (eventObject) {
	this.numOfImagesPreloaded++;
}

//////////////////////////
// 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);
			}
		}
													  
	}, 50);	
}

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;
	}
}

////////////////////////
// class ImageBrowser //
////////////////////////

function ImageBrowser(imagesArray, previousButtonElement, nextButtonElement, scrollContentContainer, imageViewPortWidth) {
	this.imagesArray=imagesArray;
	this.previousButtonElement=previousButtonElement;
	this.nextButtonElement=nextButtonElement;
	this.scrollContentContainer=scrollContentContainer;
	this.imageViewPortWidth=imageViewPortWidth;
	this.currentImage=0;
	this.currentPreloadedImage=0;
	this.animation=new Animation.SmoothHMove(this.scrollContentContainer, this.scrollContentContainer.parentNode);
	this.imagePreloader=new ImagePreloader(this.imagesArray);
	this.imagePreloader.addListener(this);
	this.init();
}

ImageBrowser.prototype.init=function() {
	var obj=this;
	if (this.imagesArray.length == 0) return;
	
	DHTMLApi.CSS.setProperties(this.scrollContentContainer,{width: (this.imageViewPortWidth*this.imagesArray.length) + "px", position: "relative"});
	this.imagePreloader.start();
	this.setButtonVisibility();
	DOMEvent.addDomListener(this.previousButtonElement,"click", function () {			
		obj.currentImage--;
		obj.setButtonVisibility();
		obj.animation.setPosition(-obj.currentImage*obj.imageViewPortWidth);
	});
	DOMEvent.addDomListener(this.nextButtonElement,"click", function () {			
		obj.currentImage++;
		obj.setButtonVisibility();
		obj.animation.setPosition(-obj.currentImage*obj.imageViewPortWidth);
	});
};

ImageBrowser.prototype.setButtonVisibility=function () {
	if (this.currentImage==0) {
		DHTMLApi.Visibility.hide(this.previousButtonElement);			
	}
	if (this.currentImage==1) {
		DHTMLApi.Visibility.show(this.previousButtonElement);			
	}
	if (this.currentImage==(this.imagesArray.length-2)) {
		DHTMLApi.Visibility.show(this.nextButtonElement);			
	}
	if (this.currentImage==(this.imagesArray.length-1)) {
		DHTMLApi.Visibility.hide(this.nextButtonElement);			
	}
}

ImageBrowser.prototype.onImageLoad=function (eventObject) {
	this.addLoadedImage(eventObject);
	this.currentPreloadedImage++;
}

ImageBrowser.prototype.addLoadedImage=function(imageUrl) {
	var imageContainer;
	imageContainer=this.getImageSlide(imageUrl);
	this.scrollContentContainer.appendChild(imageContainer);
	DHTMLApi.CSS.setProperties(imageContainer,{position: "absolute", top: "0px", left: this.currentPreloadedImage*this.imageViewPortWidth+"px"});
};

ImageBrowser.prototype.getImageSlide=function (imageUrl) {
	var containerDiv, imageElement;
	containerDiv=document.createElement("DIV");
	DHTMLApi.CSS.setClass(containerDiv,["gallery_image_container"],[]);
	imageElement=document.createElement("IMG");
	imageElement.setAttribute("src",imageUrl);
	containerDiv.appendChild(imageElement);
	return containerDiv;
};

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

Animation= new Object();

Animation.FRAME_RATE=50; // miliseconds

//////////////////////////
// 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 Animation.SmoothHMove //
/////////////////////////////////

Animation.SmoothHMove=function(movingObject, relativeToObject) {
	this.movingObject=movingObject;
	this.relativeToObject=relativeToObject;
	this.currentXPos=DHTMLApi.Position.getXPosInElement(movingObject,relativeToObject);
	this.targetXPos=null;
	this.interval=null;
	this.numOfAnimationStep=null;
}

Animation.SmoothHMove.prototype=implementsInterface(Observable);

Animation.SmoothHMove.prototype.setPosition=function (targetPosition) {
	if (this.interval!==null) {
		window.clearInterval(this.interval);
		this.notifyListeners("onAnimationEnd",null);
	}
	var animationObject=this;
	this.targetXPos=targetPosition;
	this.numOfAnimationStep=0;
	this.notifyListeners("onAnimationStart",null);
	this.animate();
	this.interval=window.setInterval(function() {animationObject.animate()},Animation.FRAME_RATE);
}

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

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

/////////////////////////////
// Static Class PopUpLayer //
/////////////////////////////

PopUpLayer= {
	
	containerZIndex: 10000,
	
	init: function (popUpDivNode,backgroundCssClass,backgroundAlpha,closeButtonElement,onCloseCallback) {
		this.popUpDivNode=popUpDivNode;
		this.parentpopUpDivNode=popUpDivNode.parentNode;
		this.nextSiblingpopUpDivNode=popUpDivNode.nextSibling;
		this.popupContainerNode=null;
		this.backgroundNode=null;
		this.backgroundCssClass=backgroundCssClass;
		this.backgroundAlpha=backgroundAlpha;
		this.closeButtonElement=null;
		this.onCloseCallback=null;
		if (typeof closeButtonElement != "undefined") {
			this.closeButtonElement=closeButtonElement;
		}
		if (typeof onCloseCallback != "undefined") {
			this.onCloseCallback=onCloseCallback;
		}
		this.resizeHandler=null;
		this.closeHandler=null;
		this.closeButtonHandler=null;
		this.tempPopUpDivNodeStyles={position: DHTMLApi.CSS.getStyle(this.popUpDivNode, "position"), top: DHTMLApi.CSS.getStyle(this.popUpDivNode, "top"), left: DHTMLApi.CSS.getStyle(this.popUpDivNode, "left"), zIndex: DHTMLApi.CSS.getStyle(this.popUpDivNode, "z-index"), display: DHTMLApi.CSS.getStyle(this.popUpDivNode, "display")};
	},
	
	initHandlers: function () {
		var obj=this;
		this.resizeHandler=DOMEvent.addDomListener(window, "resize", function () {
			obj.centerOnPage();
		});
		this.closeHandler=DOMEvent.addDomListener(this.backgroundNode, "click", function () {
			obj.hide();
			if (obj.onCloseCallback!==null) (obj.onCloseCallback)();
		});
		if (this.closeButtonElement!==null) {
			this.closeButtonHandler=DOMEvent.addDomListener(this.closeButtonElement, "click", function () {
				obj.hide();
				if (obj.onCloseCallback!==null) (obj.onCloseCallback)();
			});
		}
	},
	
	removeHandlers: function () {
		DOMEvent.removeListener(this.resizeHandler);
		DOMEvent.removeListener(this.closeHandler);
		this.resizeHandler=null;
		this.closeHandler=null;
	},
	
	build: function () {
		var popUpNode;
		this.popupContainerNode=document.createElement("DIV");
		document.body.appendChild(this.popupContainerNode);
		DHTMLApi.CSS.setProperties(this.popupContainerNode,{position: "absolute", top: "0px", left: "0px", width: DHTMLApi.Size.getPageWidth()+"px", height: DHTMLApi.Size.getPageHeight()+"px", zIndex: this.containerZIndex, overflow:"auto"});
		this.backgroundNode=document.createElement("DIV");
		this.popupContainerNode.appendChild(this.backgroundNode);
		DHTMLApi.CSS.setProperties(this.backgroundNode,{position: "absolute", top: "0px", left: "0px", zIndex: 1, cursor: "pointer", width: "100%", height: "100%"});
		DHTMLApi.CSS.setClass(this.backgroundNode,new Array(this.backgroundCssClass),new Array());
		
		popUpNode=this.parentpopUpDivNode.removeChild(this.popUpDivNode);
		this.popupContainerNode.appendChild(popUpNode);
		DHTMLApi.CSS.setProperties(popUpNode, {position: "absolute", zIndex: 2, display: "block"});
		DHTMLApi.Visibility.setOpacity(this.backgroundNode,this.backgroundAlpha);
		
		this.initHandlers();
	},
	
	restorePopUpNode: function() {
		if (this.nextSiblingpopUpDivNode!==null) {
			this.parentpopUpDivNode.insertBefore(this.popUpDivNode,this.nextSiblingpopUpDivNode);
		} else {
			this.parentpopUpDivNode.appendChild(this.popUpDivNode);
		}
		
		DHTMLApi.CSS.setProperties(this.popUpDivNode,this.tempPopUpDivNodeStyles);
	},
	
	centerOnPage: function () {
		var leftPos,topPos;
		leftPos=Math.round((DHTMLApi.Browser.getViewportWidth()-DHTMLApi.Size.getElementWidth(this.popUpDivNode))/2+DHTMLApi.Browser.getScrollX());
		topPos=Math.round((DHTMLApi.Browser.getViewportHeight()-DHTMLApi.Size.getElementHeight(this.popUpDivNode))/2+DHTMLApi.Browser.getScrollY());
		if (topPos+DHTMLApi.Size.getElementHeight(this.popUpDivNode)>DHTMLApi.Size.getPageHeight()) {
			topPos=DHTMLApi.Size.getPageHeight()-DHTMLApi.Size.getElementHeight(this.popUpDivNode);
		}
		DHTMLApi.CSS.setProperties(this.popUpDivNode, {left: leftPos+"px", top: topPos+"px"});
	},
	
	display: function (popUpDivNode,backgroundCssClass,backgroundAlpha,closeButtonElement,onCloseCallback) {
		this.init(popUpDivNode,backgroundCssClass,backgroundAlpha,closeButtonElement,onCloseCallback);
		this.build();
		this.centerOnPage();
	},
	
	hide: function () {
		this.removeHandlers();
		this.restorePopUpNode();
		document.body.removeChild(this.popupContainerNode);
	}	
}