function ImageViewer(config){
	config = config||{};
 	this.images = {};
 	this.thumbs = [];
 	this.elements = {};
 	this.currentSet = null;
 	this.currentImage = -1;
 	this.timer = null;
 	this.imageViewerActive = false;
  	this.initialWidth = 230;
  	this.initialHeight = 230;
  	this.minWidth = 460;
  	this.minHeight = 180;
  	this.page = {};
  	this.replacePic = null;
  	this.lastid = -1;
  	this.blankImageURL = 'images/blank.gif'||config.blankImageURL;
  	this.title = {
  		prev: 'Vorige afbeelding',
  		next: 'Volgende afbeelding'
  	};
  	this.className = config.className || 'imageviewer';
	this.sthumb = config.sthumb || false;
  	this.defaultOptions = {
			slideshow: false,
			transitionspeed: 5,
			thumbview: true
		};
  	this.options = {};
  	if(config.set){
    	this.set = config.set;
  	}else{
  		this.set = 'images';
  	}
  	this.init();
};
ImageViewer.prototype = {
  	init: function(){
		$('#imageOverlay').remove();
		$('#imageViewer').remove();
		$('body').append('<div id="imageOverlay"></div>');
		$('body').append('<div id="imageViewer">'+
						  '<div id="outerImageContainer">'+
						   '<div id="imageContainer">'+
						    '<img id="imageViewerImage"/>'+
						    '<div id="loadingContainer">' +
						     '<img id="loadingImage" src="'+this.blankImageURL+'"/>'+
						    '</div>'+
						   '</div>'+
						   '<div id="imageDataContainer">'+
						    '<div id="thumbContainer">' +
						     '<div id="thumbPrev" class="thumbPrev" title="'+this.title.prev+'"></div>'+
						     '<div id="thumbNext" class="thumbNext" title="'+this.title.next+'"></div>'+
						     '<div id="thumbView"></div>'+
						    '</div>'+
							'<div class="imageFbar">'+
						    '<img id="closeImage" class="closeBtn" src="'+this.blankImageURL+'"/>'+
						    '<div id="imageDetails">' +
						     '<span id="numberDisplay"></span>'+
						     '<span id="imageCaption"></span><div class="clear"></div>'+
						    '</div><div class="clear"></div>'+	
							'</div>'+
						   '</div>'+
						  '</div>'+
						 '</div>');
		var Es = this.elements;						 
		Es.imageOverlay = $('#imageOverlay')[0];
		Es.imageViewer = $('#imageViewer')[0];
		Es.outerImageContainer = $('#outerImageContainer', Es.imageViewer)[0];
		Es.imageContainer = $('#imageContainer', Es.outerImageContainer)[0];
		Es.imageViewerImage = $('#imageViewerImage', Es.imageContainer)[0];
		Es.loadingContainer = $('#loadingContainer', Es.imageContainer)[0];
		Es.loadingImage = $('#loadingImage', Es.loadingContainer)[0];
		Es.imageDataContainer = $('#imageDataContainer', Es.outerImageContainer)[0];
		Es.closeImage = $('#closeImage', Es.imageDataContainer)[0];
		Es.numberDisplay = $('#numberDisplay', Es.imageDataContainer)[0];
		Es.imageCaption = $('#imageCaption', Es.imageDataContainer)[0];
		Es.thumbContainer = $('#thumbContainer', Es.imageDataContainer)[0];
		Es.thumbPrev = $('#thumbPrev', Es.imageDataContainer)[0];
		Es.thumbNext = $('#thumbNext', Es.imageDataContainer)[0];
		Es.thumbView = $('#thumbView', Es.imageDataContainer)[0];
		
		var rate = 0.85;
		$(Es.imageOverlay).css({
			"opacity": rate,
			"-moz-opacity": rate,
			"filter": "alpha(opacity="+(rate*100)+")"							   
		});
		$(Es.imageOverlay).hide();
		$(Es.imageViewer).hide();
		$(Es.imageViewerImage).hide();
		$(Es.imageDataContainer).hide();

		$(Es.closeImage).hover(function(){
			$(this).addClass('closeBtn-hover');
		}, function(){
			$(this).removeClass('closeBtn-hover');
		});
		$(Es.thumbPrev).hover(function(){
			$(this).addClass('thumbPrev-hover');
		}, function(){
			$(this).removeClass('thumbPrev-hover');
		});	
		$(Es.thumbNext).hover(function(){
			$(this).addClass('thumbNext-hover');
		}, function(){
			$(this).removeClass('thumbNext-hover');
		});		
		//add events on imageoverlay and imageviewer
		var p = this;
		$(Es.imageOverlay).click(function(e){
			p.stop(e);
		});
		$(Es.imageViewer).click(function(e){
			p.stop(e);
		});
		$(window).resize(function(e){
			p.setImageViewerPosition();
		});
		$(window).unload(function(e){
			p.cleanUp();
		});
		$(Es.thumbPrev).click(function(e){
			p.prevImage();
		});
		$(Es.thumbNext).click(function(e){
			p.nextImage();
		});		
		this.run();
	  }
	 ,run: function(){
	 	var images = $('.' + this.className);
	 	if(images.length > 0){
	 		var set = images.length == 1 ? 'single': 'images';
	 		for(var i = 0; i < images.length; i++){
	 			var img = images[i];
				var imageSrc = $(img).attr('href');
				imageSrc = imageSrc.split('.');
				var thumbSrc = '';
				var largeSrc = $(img).attr('href');
				if(this.sthumb){
					thumbSrc = $(img).attr('href').replace('.jpg', '') + '-thumb.jpg';
					largeSrc = $(img).attr('href').replace('.jpg', '') + '-large.jpg';
				}
				else{
					thumbSrc = imageSrc[0]+'-sthumb.'+imageSrc[1];
				}
				this.addImage(set, {
					anchor: img,
					src: largeSrc,
					thumbsrc: thumbSrc,
					caption:$(img).attr('title')
				});	 		
	 		}
	 	}
	 }
 	 ,cleanUp: function(){
    	this.images = null;
    	this.thumbs = null;
    	this.elements = null;
  	} 	 
  	,toggleFlash: function(visibility){
  		$('embed, object, select').css({'visibility': visibility});
  	}
  	,setImageViewerPosition: function(){
		if(this.imageViewerActive){
 			var Es = this.elements;	
			$(Es.imageOverlay).hide();
			$(Es.imageViewer).hide(); 			
  			this.page = this.getPageDimensions();
  			$(Es.imageViewer).css({'left': this.page.offsetX+'px',
  									 'top': Math.round(this.page.offsetY)+'px'
  									});
  			$(Es.imageOverlay).css({'width': (this.isIE6()?(this.page.scrollWidth - 20):this.page.scrollWidth) + 'px',
  									 'height': this.page.scrollHeight + 'px'
  									 });			
			$(Es.imageOverlay).show();
			$(Es.imageViewer).show(); 
		}
  	}  
	,setImageViewerSize: function(width,height){
		width += 20;	
		height += 20;
		var Es = this.elements;
		$(Es.outerImageContainer).css({width: (this.isIE6()?(width-20): width) + 'px'});
		$(Es.imageContainer).css({height: (height-20)+'px'});
		$(Es.loadingContainer).css({width: width+'px', height: height + 'px'});
		$(Es.loadingImage).css({marginTop: (Math.round(height/2)-16)+'px'});
				
	}
	,reposition: function(){
		var Es = this.elements;
  		var top = $(Es.imageViewer).css('top').replace('px', '');
		var height = $(Es.imageViewer).height();
  		//$(Es.imageViewer).css({'top': $(Es.imageOverlay).height()-height+'px'});		
	}
	,changeImage: function(num){
		var Es = this.elements;
		var p = this;
		if(num != this.currentImage){
  			if(this.timer){
    			clearTimeout(this.timer);
    			this.timer = null;
  			}
  			$(Es.loadingContainer).show();
  			var image = this.images[this.currentSet][num];
  			var preloadImage = new Image();
  			preloadImage.onload = function(){
  				p.showImage(preloadImage, num);
  			}
  			preloadImage.src = image.src;
		}
	}	
	,showImage: function(preloadImage,num){
		var Es = this.elements;
		var originalWidth = preloadImage.width;
		var originalHeight = preloadImage.height;
		preloadImage.onload=function(){
		};
		$(Es.imageViewerImage).attr('src', preloadImage.src);
		$(Es.imageViewerImage).attr('originalWidth', originalWidth);
		$(Es.imageViewerImage).attr('originalHeight', originalHeight);
		this.setImageSize(originalWidth,originalHeight,'smallSize');
		$(Es.imageCaption).html(this.images[this.currentSet][num]['caption']||'&nbsp;');
		if(this.currentSet!='single'){
			$(Es.numberDisplay).html('(Afbeelding '+(num+1)+' van ' + this.images[this.currentSet].length+') ');
		}
		$(Es.loadingContainer).hide();
		$(Es.imageViewerImage).show();
		$(Es.imageDataContainer).show();
		if(this.options.thumbview){
 			if(this.currentImage > -1)this.thumbs[this.currentImage].className = '';
 			var scrollLeft = this.thumbs[num].offsetLeft-
 			((Math.max(Es.imageViewerImage.width, this.minWidth) - this.thumbs[num].width)/2);
 			Es.thumbView.scrollLeft = scrollLeft;
  			this.thumbs[num].className = 'current';
		}
		this.currentImage = num;
		if(this.options.slideshow){
			this.timer = setTimeout(this.nextImage(this),this.options.transitionspeed*1000);
		}
		this.reposition();
	}	
	,setImageSize: function(width,height,size){
		var resized = size == 'fullSize';
		var Es = this.elements;
		if(!resized){
			var hRatio = this.page.innerWidth/width;
			var vRatio = this.page.innerHeight/height;
			vRatio *= this.options.thumbview?0.7:0.8;
			if(hRatio<1||vRatio<1){
				width = Math.floor(width*Math.min(hRatio,vRatio));
				height = Math.floor(height*Math.min(hRatio,vRatio));
				resized = true;
			}
		}
		this.setImageViewerSize(Math.max(width, this.minWidth),Math.max(height,this.minHeight));
		
		var diffHeight = height - $(Es.imageViewerImage).height();
		$(Es.imageViewerImage).css({width: width + 'px'});
		$(Es.imageViewerImage).css({height: height + 'px'});
		$(Es.imageOverlay).css({
						height: $(Es.imageOverlay).height() + diffHeight + 'px'
					});
				
		var p = this;
		if(resized){
			Es.imageViewerImage.className = size;
			Es.imageViewerImage.onclick = function(){
				p.toggleImageSize();
			};
		}
		else{
			Es.imageViewerImage.className = '';
			Es.imageViewerImage.onclick = function(){};
		}
	}
	,toggleImageSize: function(){
		var Es = this.elements;
		this.setImageSize($(Es.imageViewerImage).attr('originalWidth'),
					  $(Es.imageViewerImage).attr('originalHeight'),
		              Es.imageViewerImage.className == 'smallSize'?'fullSize':'smallSize');
	}	
	,nextImage: function(){
		var Es = this.elements;
		var num = this.currentImage + 1;
		if(!this.images[this.currentSet][num])num = 0;
		$(Es.loadingContainer).show();
		this.changeImage(num);
	}
	,prevImage: function(){
		var Es = this.elements;
		var num= this.currentImage - 1;
		if(!this.images[this.currentSet][num])num = this.thumbs.length - 1;
		$(Es.loadingContainer).show();
		this.changeImage(num);
	}
	,addImage: function(set){
		var i=1,image,num,l;
		if(!set)set = 'single';
		if(!this.images[set])this.images[set]=[];
		while((image = arguments[i++])){
			for(num = 0,l = this.images[set].length; num<l; num++){
				if(this.images[set][num].src == image.src){
					break;
				}
			}
  			if(num == l){
    			if(!image.thumbsrc)image.thumbsrc=image.src;
    			image.thumbsrc = image.thumbsrc.replace(/\/ext\/i(\/(thumblarge|thumbsmall|thumbmini|imagemedium))?\/(\d+\.(jpe?g|png|gif))$/,'/ext/i/thumb/$3');
    			this.images[set][num] = {
      						src:image.src,
      						thumbsrc:image.thumbsrc,
      						caption:image.caption
    					}
  			}
  			if(image.anchor){
  				var p = this;
  				$(image.anchor).click(function(e){
  					p.start(set, num, false, e);
  					return false;
  				});
  			}
		}
	}
	,generateThumbView: function(set,num){
		var img = null;
		var Es = this.elements;
		Es.thumbView.innerHTML = '';
		this.thumbs = [];
		var p = this;
		for(var i = 0; i< this.images[set].length; i++){
			img = document.createElement('img');
			img.src = this.images[set][i].thumbsrc;
			if(i == num)img.className='current';
			$(img).bind('click', {index: i}, function(e){
				p.changeImage(e.data.index);
			});
  			this.thumbs[i] = img;
  			$(Es.thumbView).append(img);
		}
		$(Es.thumbContainer).show();
	}	
	,giveBack:function(){
		if(this.replacePic){
			var Es = this.elements;
  			this.currentImage = Es.imageViewerImage.src;
  			var a = $(this.replacePic)[0];
  			a.setAttribute("src", Es.imageViewerImage.src);
  			$(Es.imageOverlay).hide();
  			$(Es.imageViewer).hide();
  			$(Es.imageViewerImage).hide();
  			$(Es.imageDataContainer).hide();
  			this.imageViewerActive = false;
  			this.currentImage = -1.0;
  			this.toggleFlash('');
		}
	}
  	,keyHandler: function(e){
    	switch(e.keyCode){
      		case 27:
      			this.stop();
      			break;
      		case 37:
      			if(this.images[this.currentSet].length>1){
      				this.prevImage();
      			}
      			break;
      		case 39:
      			if(this.images[this.currentSet].length>1){
      				this.nextImage();
      			}
      			break;
    	}
 	}
 	,start: function(set,num,options,e){
		if(!this.imageViewerActive){
			var Es = this.elements;
      		this.imageViewerActive = true;
      		this.currentSet = set;
      		if(!(set in this.images)){
      			this.images[set]=[];
      		}
      		this.toggleFlash('hidden');
      		$(Es.loadingContainer).show();
      		this.setImageViewerSize(this.initialWidth, this.initialHeight);
      		this.setImageViewerPosition();
      		this.options = options||{
      		};
      		$.extend(this.options, this.defaultOptions); 
      		if(!num)num = 0;
      		if(set == 'single'){
      			$(Es.numberDisplay).hide();
      			$(Es.thumbContainer).hide();
      		}else{
        		$(Es.numberDisplay).show();
        		if((this.options.thumbview && this.images[set].length>1)){
          			this.generateThumbView(set, num);
        		}else{
          			this.options.thumbview = false;
          			$(Es.thumbContainer).hide();
        		}
      		}
      		var p = this;
      		$(document).keydown(function(e){
      			p.keyHandler(e);
      		});
      		this.changeImage(num);
    	}
    	if(e)e.preventDefault();
	} 
	,stop: function(e){
		var target = e&&(e.target||e.srcElement);
    	if(!target||(target.id&&
    		$.inArray(target.id, new Array('imageOverlay','imageViewer','loadingContainer','loadingImage','closeImage')) > -1)){
    		var Es = this.elements;
     	 	this.imageViewerActive = false;
     	 	this.currentImage = -1;
     	 	if(this.timer){
     		   	clearTimeout(this.timer);
      		  	this.timer=null;
      		}
      		$(Es.imageOverlay).hide();
      		$(Es.imageViewer).hide();
      		$(Es.imageViewerImage).hide();
      		$(Es.imageDataContainer).hide();
      		document.onKeydown = function(){};
      		this.toggleFlash('');
    	}
    	if(e)e.stopPropagation();
	}
	,getPageDimensions: function(){
  		var dE = document.documentElement||document.body;
  		return{
    			scrollWidth: this.isIE6()? dE.offsetWidth: dE.scrollWidth,
    			scrollHeight:Math.max(dE.scrollHeight,dE.clientHeight),
    			innerWidth:window.innerWidth||(dE.offsetWidth-2*(dE.clientLeft||0)),
    			innerHeight:window.innerHeight||(dE.offsetHeight-2*(dE.clientTop||0)),
    			availWidth:dE.clientWidth,availHeight:dE.clientHeight,
    			offsetX:window.pageXOffset||dE.scrollLeft,offsetY:window.pageYOffset||dE.scrollTop
  			};		
	}
	,getPageSize: function(){
		var xScroll, yScroll;
		if (window.innerHeight && window.scrollMaxY) {	
			xScroll = window.innerWidth + window.scrollMaxX;
			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
			if(document.documentElement.clientWidth){
				windowWidth = document.documentElement.clientWidth; 
			} else {
				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 = xScroll;		
		} else {
			pageWidth = windowWidth;
		}
		arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight);
		return arrayPageSize;		
	}
	,isIE6: function(){
		return $.browser.msie && $.browser.version == '6.0';
	}
};
