function imageSlider( elm ) {
	this.loadNumeric = true;
	this.showStatus = true;
	this.imageFolder = "./";
	
	var jsObj = this;
	
	this.init = function( elm ) {
		this.DOMNodes.replaceElm = elm;
	}
	
	this.addImage = function( img ) {
		// Add the created image to the imagelist
		if( !this.images )
			this.images = [];
		
		this.images.push(img);
		
		
	}
	
	this.executeEvent = function( evt ) {
		if( typeof(evt) == "function" ) {
			var argStr = "";
			var argCount  = arguments.length;
			
			for( var i=1; i < argCount; i++ ) {
				argStr += "arguments["+ i +"]";
				
				if( i < (argCount -1) )
					argStr += ",";
			}
			
			eval("evt("+ argStr +")");
		}
	}
	
	this.imageExistsInList = function( img ) {
		if( this.images && img ) {
			var imgFound = false;
			
			for( var i=0; i < this.images.length; i++ ) {
				if( this.images[i].src == img.src ) {
					imgFound = true;
					break;
				}
			}
			
			return imgFound;
		} else
			return false;
	}
	
	this.preloadImages = function() {
		//debug("preloading images");
		
		this.buttons.disableAll();
		
		if( this.loadNumeric )
			this.numeric.loadImage();
		else
			this.predefined.preloadImages();
	}
	
	this.preloadImage = function( imgSrc, onLoad, onError ) {		
		if( !(imgSrc && String(imgSrc.nodeName).toLowerCase() == "img") ) {
			var img = new Image();
		} else {
			var img = imgSrc;
			imgSrc = img.src;
		}
		
		//debug("preloading image: "+ img.src);
		
		var jsObj = this;
		
		img.onerror = function() {
			//debug("image error")
			jsObj.imageError( this, onError );
		}
		
		img.onload = function() {
			//debug("image loaded");
			jsObj.imageComplete( this, onLoad );
		}
		
		img.src = imgSrc;
	}
	
	this.imageError = function( img, onError ) {
		clearTimeout(jsObj._imageCheck);
		this.executeEvent( onError, img );
		
		//debug("image onerror");
	}
	
	this.imageComplete = function( img, onLoad ) {
		//debug("start imagecheck: "+ typeof(img))
		
		if( img ) {
			//debug("checking image: "+ img.src);
			
			if( img.complete ) {
				//debug("image complete");
				
				var jsObj = this;				
				var func = function( image ) {
					jsObj.executeEvent( onLoad, image );
				}
				
				this.buildImage( img, func );
			} else {
				jsObj = this;
				func = function() { jsObj.imageComplete( img, onLoad ) }
				this._imageCheck = setTimeout( func, 50 );
			}	
		}
	}
	
	this.onImagesLoaded = function() {
		this.buttons.enableAll();
		this.loader.fade();
	}
	
	this.buildImage = function( img, onBuild ) {
		if( img && img.nodeName.toLowerCase() == "img" ) {
			if( !img.container ) {
				var imgArea = this.DOMNodes.imgArea();
				
				if( imgArea ) {
					if( !this.imageExistsInList(img) ) {
						var imgContainer = document.createElement("div");
							imgContainer.className = "image-container";
							imgContainer.style.cssText = "position: absolute; overflow: hidden; z-index: 0; width: "+ imgArea.clientWidth +"px; height: "+ imgArea.clientHeight +"px; zoom: 1;";
								
						// Insert elements
						imgContainer.appendChild(img);
						imgArea.appendChild(imgContainer);
						
						// Center image
						var top = (imgContainer.clientHeight / 2) - (img.offsetHeight / 2);
						var left = (imgContainer.clientWidth / 2) - (img.offsetWidth / 2);
						
						img.style.cssText = "position: relative; top: "+ top +"px; left: "+ left +"px";
						
						// Save the container reference on the image object for later access
						img.container = imgContainer;
						
						// Hide the image as default
						this.merger.setImageOpacity( img, 0 );
						
						img.style["position"] = "absolute";
						img.style["left"] = left +"px";
						img.style["top"] = top +"px";
						
						// Set width/height of imgContainer (height have to be reset so IE gets it right, as the 'filter' attribute resets the height)
						imgContainer.style["width"] = imgArea.clientWidth +"px";
						imgContainer.style["height"] = imgArea.clientHeight +"px";
						imgContainer.style["top"] = imgContainer.style["left"] = "0px";
						
						this.addImage( img );
					}
					
					var imgCount = this.images.length ;
					var jsObj = this;
					var _onBuild = function(image) { jsObj.loader.refresh( imgCount ); onBuild(image); }
					
					this.executeEvent( _onBuild, img );
				}
			}
		}
	}
	
	this.loader = {
		parent : jsObj,
		
		statusArea : function() {
			if( !this.parent.DOMNodes.statusArea ) {
				
				var area = document.createElement("div");
					area.className = "status-area";
					area.style["position"] = "absolute";
					area.style["zIndex"] = "1000";
				
				this.parent.DOMNodes.slider().appendChild(area);
				
				// Position it
				this.setStatusAreaPosition( area );
				
				// Save the status area in the DOM node collection
				this.parent.DOMNodes.statusArea = area;
			}
			
			return this.parent.DOMNodes.statusArea;
		},
		
		loadBar : function() {
			var sa = this.statusArea();
			
			if( !this.parent.DOMNodes.loadBar && sa ) {
				var bar = document.createElement("div");
					bar.className = "loadbar";
					
					// Append the bar to the status area
					sa.appendChild(bar);
					
					// Set style for calculation of the max width of the bar
					bar.style["width"] = "auto";
					bar.style["display"] = "block";
					bar.style["float"] = "none";
					
					// Save max width
					bar.maxWidth = bar.offsetWidth;
					
					// Reset calculation styles back to normal
					bar.style["width"] = "";
					bar.style["display"] = "";
					bar.style["float"] = "";
			} else if( !sa )
				this.parent.DOMNodes.loadBar = null;
			
			return this.parent.DOMNodes.loadBar;
		},
		
		refresh : function( current ) {
			//debug("<b>refreshing status</b>");
			
			if( this.parent.showStatus ) {
				if( !this.parent.loadNumeric )
					this.refreshBar( current );
				else
					this.refreshCounter( current );
			}
		},
		
		refreshBar : function( current, max ) {
			var lb = this.loadBar();
			
			if( lb ) {
				var onePercentWidth = lb.maxWidth / max;
				var w = onePercentWidth * current;
				
				lb.style["width"] = w +"px";
			}
		},
		
		refreshCounter : function( current ) {
			var sa = this.statusArea();
			
			if( sa ) {
				if( !sa.count ) {
					var c = document.createElement("span");
						c.className = "counter";
					
					sa.count = c;
					sa.innerHTML = '&nbsp;billeder hentet...';
					sa.insertBefore( c, sa.firstChild );
				}
				
				sa.count.innerHTML = current;
			}
		},
		
		fade : function( sec, opac ) {
			sec = parseFloat(sec);
				if( isNaN(sec) )
					sec = 1;
			
			opac = parseInt(opac);
				if( isNaN(opac) )
					opac = 100;
			
			var sa = this.statusArea();
			
			if( sa ) {
				if( opac >= 0 ) {
					setOpacity( sa, opac );
					
					this.setStatusAreaPosition( sa );
					
					var jsObj = this;
					var func = function() { jsObj.fade( 0.06, (opac-5) ) };
					
					setTimeout( func, (sec*1000) );
				}
			}
		},
		
		setStatusAreaPosition : function( statusArea ) {
			var sa = statusArea;
			
			if( sa ) {
				// Set top/left if not set in stylesheet
				var ia = this.parent.DOMNodes.imgArea();
				
				var top = getStyle(sa, "top");
				
				if( top == "0px" || top == "auto" )
					sa.style["top"] = (ia.offsetHeight + ia.offsetTop) +"px";
				
				var left = getStyle(sa, "left");
				
				if( left == "0px" || left == "auto" )
					sa.style["left"] = ia.offsetLeft +"px";
			}
		}
	}
	
	this.predefined = {
		parent : jsObj,
		
		preloadImages : function() {
			this.parent.buttons.disableAll();
			this.loadImage();
		},
		
		loadImage : function( index ) {
			if( index < 0 || isNaN(index) )
				index = 0;
			
			if( index < this.parent.images.length ) {
				var jsObj = this;
				
				var img = new Image();
					img.src = this.parent.images[index];
					img.onload = function() { jsObj.onImageLoaded(index); }
					img.onerror = function() { jsObj.onImageError(index); }
			} else
				this.onImagesLoaded();
		},
		
		onImageLoaded : function( index ) {
			var i = index +1;
			
			this.parent.loader.refresh( i, this.parent.images.length, "bar");
			this.loadImage(i);
		},
		
		onImageError : function( index ) {
			this.images.splice(index, 1);
			this.setLoadBar();
			
			this.loadImage(index);
		},
		
		onImagesLoaded : function() {
			this.parent.buttons.enableAll();
		}
	}
	
	this.numeric = {
		parent : jsObj,
				
		loadImage : function( imgNum ) {
			if( imgNum < 1 || isNaN(imgNum) )
				imgNum = 1;
				
			//debug( "loading image "+ imgNum );
						
			var imgSrc = (imgNum < 10)? "0"+ imgNum +".jpg" : imgNum +".jpg";
				imgSrc = this.parent.imageFolder +"/"+ imgSrc;
			
			var jsObj = this;
			var onLoad = function( image ) { jsObj.onImageLoaded(image, imgNum) }
			var onError = function() { jsObj.onImageError(); }
			
			this.parent.preloadImage( imgSrc, onLoad, onError )
		},
		
		onImageLoaded : function( img, imgNum ) {
			// Preload next image
			this.loadImage( ++imgNum );
		},
		
		onImageError : function() {
			this.onImagesLoaded();
		},
		
		onImagesLoaded : function() {
			this.parent.onImagesLoaded();
		}
	}
	
	this.slider = {
		parent : jsObj,
		currentImageIndex : 0,
		
		to : function( index ) {
			var imageList = this.parent.images;
			var imgCount = imageList.length;
			
			if( imgCount > 1 ) {
				if( index < 0 )
					index = imgCount -1;
				
				if( index >= imgCount )
					index = 0;
				
				var toImage = imageList[ index ];
				
				this.parent.merger.go( toImage );
				this.currentImageIndex = index;
			}
		},
		
		prev : function() {
			if( isNaN(this.currentImageIndex) )
				this.currentImageIndex = 0;
			
			this.to( (this.currentImageIndex -1) );
		},
		
		next : function() {
			if( isNaN(this.currentImageIndex) )
				this.currentImageIndex = 0;
			
			this.to( (this.currentImageIndex +1) );
		},
		
		slideshowicon : function() {

		},

		
		main : function() {
			if( !this.parent.DOMNodes._slider ) {
				var slider = document.createElement("div");
					slider.className = "image-slider";
					slider.sliderControl = this.parent;
					
				var imgArea = document.createElement("div");
					imgArea.className = "image-area";
				
				var slideshowicon = document.createElement("div");
					slideshowicon.className = "slideshowicon";
					slideshowicon.innerHTML = "&nbsp;";
				
				var prevBut = document.createElement("a");
					prevBut.className = "prev";
					prevBut.href = "javascript:void(0)";
					prevBut.title = "Forrige billede";
					prevBut.innerHTML = "&nbsp;";
					
				var nextBut = document.createElement("a");
					nextBut.className = "next";
					nextBut.href = "javascript:void(0)";
					nextBut.title = "N&aelig;ste billede";
					nextBut.innerHTML = "&nbsp;";
				
				slider.appendChild(imgArea);
				slider.appendChild(prevBut);
				slider.appendChild(slideshowicon);
				slider.appendChild(nextBut);
				
				this.parent.DOMNodes._slider = slider;
				
				this.parent.buttons.disableAll();
			}
			
			return this.parent.DOMNodes._slider;
		}
	}
	
	this.buttons = {
		parent : jsObj,
		
		disable : function( bn ) {
			var button = null;
				if(bn.match(/next|prev|slideshowicon/))
					eval("button = this."+ bn +"()");
			
			if( button ) {
				this.addDisabledClass( button, "disabledButton" );
				button.onclick = function() { return false; }
			}
		},
		
		disableAll : function() {
			this.disable( "next" );
			this.disable( "prev" );
			this.disable( "slideshowicon" );
		},
		
		enable : function( bn ) {
			var bnOK = bn.match(/next|prev|slideshowicon/i);
			var jsObj = this.parent;
			
			var func = null;
if(bnOK)
   eval("func = function() { jsObj.slider."+ bn +"();}")				
			var button = null;
				if(bnOK)
					eval("button = jsObj.buttons."+ bn +"()");
					//alert(""+ bn +"");
			
			if( button && func && this.parent.images.length > 1 ) {
				this.removeDisabledClass( button );
				button.onclick = function() { func(); this.blur(); return false; }
			}
		},
		
		enableAll : function() {
			this.enable( "next" );
			this.enable( "prev" );
			this.enable( "slideshowicon" );
		},
		
		addDisabledClass : function( elm, dcn ) {
			var cn = elm.className;
			
			if( cn.indexOf(dcn) < 0 )
				elm.className += " "+ dcn;
		},
		
		removeDisabledClass : function(elm) {
			var cn = elm.className;
			elm.className = cn.replace(/\b\w*disabled\w*\b/ig,"").replace(/^(\s| )*|(\s| )*$/, "");
		},
		
		prev : function() {
			return this.parent.DOMNodes.slider().childNodes[1];
		},
		
		slideshowicon : function() {
			return this.parent.DOMNodes.slider().childNodes[2];
		},
		
		next : function() {
			return this.parent.DOMNodes.slider().childNodes[3];
		}
	}
	
	this.merger = {
		parent : jsObj,
		currentImageIndex : 0,
		
		go : function( toImage ) {
			// Stop previous marge
			this.mergeComplete();
			
			// Prepare image for merging
			this.setMergeImage( toImage );
			
			// Start the merge
			this.merge( this );
		},
		
		merge : function( jsObj, opacity ) {
			var img = jsObj._mergeImage;
			
			if( img ) {
				opacity = parseInt( opacity );
					if( isNaN(opacity) || opacity < 0 )
						opacity = 0;
				
				var imgContainer = img.container;
				
				this.setImageOpacity( img, opacity );
				
				if( opacity < 100 ) {
					var func = function() { jsObj.merge( jsObj, (opacity + 15) ) };
					this._mergeTimer = setTimeout(func, 40);
				} else
					jsObj.mergeComplete();
			}
		},
		
		mergeComplete : function() {
			if( this._mergeTimer ) {
				clearTimeout( this._mergeTimer );
				this._mergeTimer = null;
			}
			
			this.setDisplayImage( this._mergeImage );
		},
		
		setMergeImage : function( img ) {
			if( img ) {
				// Prepare the image for merging
				this.setImageOpacity( img, 0 );
				img.container.style["zIndex"] = 10;
				
				// Save reference to the image being merged into
				this._mergeImage = img;
			} else
				this._mergeImage = null;
		},
		
		setDisplayImage : function( img ) {
			if( img && img.container ) {
				// If there already is a display image, hide that image and throw it into the background
				if( this._displayImage ) {
					this._displayImage.container.style["zIndex"] = 0;
					this.setImageOpacity( this._displayImage, 0 );
				}
				
				// Make the display image apepar on top of the hidden images
				img.container.style["zIndex"] = 5;
				this.setImageOpacity( img, 100 );
					
				this._displayImage = img;
			}
		},
		
		setImageOpacity : function( img, opac ) {
			if( img && img.container ) {
				setOpacity( img.container, opac );
				//setOpacity( img, 100 );
			}
		}
	}
	
	this.DOMNodes = {
		parent : jsObj,
		
		slider : function() {
			return this.parent.slider.main();
		},
		
		imgArea : function() {
			if( !this._imgArea && this.slider() )
				this._imgArea = this.slider().childNodes[0];
			
			return this._imgArea;
		},
		
		prevButton : function() {
			if( !this._prevButton && this.slider() )
				this._prevButton = this.parent.buttons.prev();
			
			return this._prevButton;
		},
		
		nextButton : function() {
			if( !this._nextButton && this.slider() )
				this._nextButton = this.parent.buttons.next();
			
			return this._nextButton;
		}
	}
	
	this.replace = function() {
		var elm = this.DOMNodes.replaceElm;
		
		this.controlElm = null;
		
		if( elm ) {
			// Get the slider control DOM node
			var slider = this.DOMNodes.slider();
			
			// Get the area where the image is shown
			var imgArea = this.DOMNodes.imgArea();
			
			// Insert the slider control just after the chosen DOM element
			var elmParent = elm.parentNode;
				elmParent.insertBefore( slider, elm.nextSibling );
			
			this.DOMNodes._slider = slider;
			
			// Examine whether the chosen element is an image or not
			if( elm.nodeName.toLowerCase() == "img" ) {
				var jsObj = this;
				var onLoad = function( image ) {
							// If it is an image, set it as the display image and insert it first in the array of images.
							jsObj.merger.setDisplayImage(image);
							jsObj.preloadImages();
						}
				
				// Make sure the image have the correct appearance
				this.preloadImage(elm, onLoad);
			} else
				// Else just remove the chosen elm, as it is no longer needed
				elm.parentNode.removeChild(elm);
		}
	}
	
	this.insert = function() {
		this.replace( this.DOMNodes.replaceElm );
	}
	
	this.init(elm);
}

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

function setOpacity( elm, opac ) {
	if( elm ) {
		// Correct opacity value
		if( isNaN(opac) || opac <= 0 || opac == "" )
			opac = 0;
		
		if( opac > 100 )
			opac = 100;
		
		// Remove current opacity settings and insert withnew ones
		var css = elm.style.cssText;
					
			css = String(css).replace(/((-moz-)?opacity[:]|filter[:]\s*alpha[(]opacity\s*=)\s*(\d|[.])+[)]?[;]/gi, "");
			css = String(css).replace(/(^\s+)|(\s+$)/, "");
			
			css += "-moz-opacity: "+ (opac / 100) +";";
			css += "filter: alpha(opacity="+ opac +");";
			
			elm.style.cssText = css;
			elm.style["opacity"] = (opac / 100);
	}
}

function getOpacity( elm ) {
	var opac = 100;
	
	if( elm ) {
		var regex = /(?:(?:-moz-)?opacity[:]|filter[:]\s*alpha[(]opacity\s*=)\s*((?:\d|[.])+)[)]?[;]/i;
		var m = String(elm.style.cssText).match(regex);
		
		if( m ) {
			opac = parseFloat(m[1]) * 100;
		}
	}
	
	return opac;
}