(function(){
	// import classes
	var Class = benignware.core.Class;
	var EventDispatcher = Class.require("benignware.events.EventDispatcher");
	var Event = Class.require("benignware.events.Event");
	var Element = Class.require("benignware.core.Element");
	var Component = Class.require("benignware.core.Component");
	
	var Delegate = Class.require("benignware.utils.Delegate");
	var CSS = Class.require("benignware.utils.CSS");
	var DOM = Class.require("benignware.utils.DOM");
	
	var Element = Class.require("benignware.core.Element");
	var StringUtils = Class.require("benignware.utils.StringUtils");
	var ArrayUtils = Class.require("benignware.utils.ArrayUtils");
	
	// define super
	var __super;
	
	
	// image loading
	var progressImage = Class.getRessource(ImageLoader, "ajax-loader.gif");
	CSS.setDefaultStyle(".benignware.ImageLoader .progress", "background-image", "url(" + progressImage + ")");
	CSS.setDefaultStyle(".benignware.ImageLoader .progress", "width", "16px");
	CSS.setDefaultStyle(".benignware.ImageLoader .progress", "height", "16px");
//	CSS.setDefaultStyle(".benignware.ImageLoader .progress", "border", "1px solid blue");
	
	
	
	/**
	 * Constructs a new form-element.
	 * @constructor
	 */
	function ImageLoader() {
		__super.call(this);
		initialize.call(this);
	}

	Class.registerClass("benignware.view.ImageLoader", ImageLoader);

	ImageLoader = Class(EventDispatcher, ImageLoader);
	
	__super = Class.getSuper(ImageLoader);
	
	ImageLoader.DEFAULT_IMAGE = "spacer.gif";
	
	ImageLoader.LOAD = "load";
	ImageLoader.ERROR = "error";
	ImageLoader.LOAD_START = "loadStart";
	ImageLoader.COMPLETE = "complete";
	
	ImageLoader.prototype.__queue = null;
	ImageLoader.prototype.__defaultImage = null;
	ImageLoader.prototype.__isLoading = false;
	
	// delegates
	ImageLoader.prototype.__loadHandlerDelegate = null;
	ImageLoader.prototype.__errorHandlerDelegate = null;

	function initialize() {
		this.__queue = [];
		this.__defaultImage = Class.getRessource(ImageLoader, ImageLoader.DEFAULT_IMAGE);
		this.__loadHandlerDelegate = Delegate.create(this, loadHandler);
		this.__errorHandlerDelegate = Delegate.create(this, errorHandler);
	}
	
	function getImages(elem) {
		if (elem) {
			if (elem.nodeName.toLowerCase() == "img") {
				return [elem];
			} else {
				return DOM.getElementsByTagName(elem, 'img');
			}
		}
		return [];
	}
	
	function isImageLoaded(img) {
		var src = img.getAttribute('src');
		if (!src && (img.__src || img.getAttribute("__src"))) {
			return false;
		}
		if (src == ImageLoader.DEFAULT_IMAGE) {
			return false;
		}
		return img.complete;
	}
	
	function next() {
		
		if (this.__queue.length) {
			var img = this.__queue.shift();
			if (!isImageLoaded.call(this, img)) {
				var src = img.getAttribute("src");
				if (!src || src == this.__defaultImage) {
					src = img.__src ? img.__src : img.getAttribute("__src");
					img.removeAttribute("__src");
					img.__src = undefined;
				}
				if (src) {
					Element.addEventListener(img, 'load', this.__loadHandlerDelegate, false);
					Element.addEventListener(img, 'error', this.__errorHandlerDelegate, false);
					img.setAttribute("src", src);
					
				} else {
					next.call(this);
				}
				
			} else {
				next.call(this);
			}
		} else {
			this.dispatchEvent(new Event(ImageLoader.COMPLETE));
		}
	}
	
	function loadHandler(event) {
		
		event = Event.getEvent(event);
		var img = event.target;
		Element.removeEventListener(img, 'load', this.__loadHandlerDelegate);
		Element.removeEventListener(img, 'error', this.__errorHandlerDelegate);
		if (img.getAttribute('src') != this.__defaultImage) {
			var imageEvent = new Event(ImageLoader.LOAD, false, false);
			imageEvent.image = img;
			this.dispatchEvent(imageEvent);
			next.call(this);
		}	
	}
	
	function errorHandler(event) {
		var img = event.target;
		Element.removeEventListener(img, 'load', this.__loadHandlerDelegate);
		Element.removeEventListener(img, 'error', this.__errorHandlerDelegate);
		if (img.getAttribute('src') != this.__defaultImage) {
			var errorEvent = new Event(ImageLoader.ERROR);
			errorEvent.image = img;
			this.dispatchEvent(errorEvent);
			next.call(this);
		}
	}
	
	ImageLoader.prototype.isLoadable = function(elem) {
		var images = getImages.call(this);
		return (images.length);
	}
	
	ImageLoader.prototype.isLoaded = function(elem) {
		var images = getImages(elem);
		if (images.length) {
			for (var i = 0; i < images.length; i++) {
				var img = images[i];
				if (!isImageLoaded.call(this, img)) {
					return false;
				}
			}
			return true;
		}
		return true;
	}
	
	ImageLoader.prototype.isLoading = function() {
		return this.__isLoading;
	}
	
	ImageLoader.prototype.remove = function(elem){
		var images = getImages(elem);
		for (var i = 0; i < images.length; i++) {
			var img = images[i];
			for (q = 0; q < this.__queue.length; q++) {
				if (img == this.__queue[q]) {
					this.__queue.splice(q++, 1);
				}
			}
		}
	}
	
	ImageLoader.prototype.add = function(elem) {
		this.remove(elem);
		var images = getImages(elem);
		
		for (var i = 0; i < images.length; i++) {
			var img = images[i];
			if (!isImageLoaded.call(this, img)) {
				this.__queue.push(img);
			} else {
				// is already loaded
			}
		}
	}
	
	ImageLoader.prototype.load = function(elem) {
		this.add(elem);
		this.start();
	}
	
	ImageLoader.prototype.unshift = function(elem) {
		this.remove(elem);
		var images = getImages(elem);
		var shiftImages = [];
		if (images.length) {
			for (var i = 0; i < images.length; i++) {
				var img = images[i];
				if (!isImageLoaded.call(this, img)) {
					shiftImages.push(img);
				}
			}
		}
		if (shiftImages.length) {
			shiftImages = shiftImages.reverse();
			for (var i = 0; i < shiftImages.length; i++) {
				var img = shiftImages[i];
				this.__queue.unshift(img);
			}
		}
	}
	
	ImageLoader.prototype.start = function() {
		if (!this.__isLoading) {
			this.stop();
			this.__isLoading = true;
			next.call(this);
		}
	}
	
	// aborting image-load doesn't work in safari
	ImageLoader.prototype.stop = function(elem) {
		var images = getImages(elem);
		for (var i = 0; i < images.length; i++) {
			var img = images[i];
			var src = img.getAttribute('src');
			if (src) {
//				if (!isImageLoaded.call(this, img)) {
					img.__src = src;
					img.setAttribute('src', this.__defaultImage);
//				}
			}
		}
	}
	
	return ImageLoader;
})();
/**
 * Extend this class to build custom form elements that can be placed on any html form.
 * Subclasses must implement the public method getValue in order to send the current value when submitting the form. 
 * Use the setName method or name property to set the key for this component.
 * @class benignware.controls.Slideshow
 * @extends benignware.core.Component
 * @see benignware.controls.Form
 */
(function(){
	// import classes
	var Class = benignware.core.Class;
	var Component = Class.require("benignware.core.Component");
	var Delegate = Class.require("benignware.utils.Delegate");
	var DOM = Class.require("benignware.utils.DOM");
	var CSS = Class.require("benignware.utils.CSS");
	var Event = Class.require("benignware.events.Event");
	var Element = Class.require("benignware.core.Element");
	var StringUtils = Class.require("benignware.utils.StringUtils");
	
	var Tween = Class.require("benignware.transitions.Tween");
	var Transition = Class.require("benignware.transitions.Transition");
	var Fade = Class.require("benignware.transitions.Fade");
	
	
	var Image = Class.require("benignware.core.Image");
	var ImageLoader = Class.require("benignware.view.ImageLoader");
	// define super
	var __super;

	/**
	 * Constructs a new form-element.
	 * @constructor
	 */
	function Slideshow() {
		var children = [];
		if (this.innerHTML) {
			for (var i = 0; i < this.childNodes.length; i++) {
				var child = this.childNodes[i];
				if (child.nodeType == 1) {
					if (child.nodeName.toLowerCase() != "script" && child.nodeName.toLowerCase() != "link") {
						children.push(child);
					}
				}
			}
		}
		__super.call(this);
		for (var i = 0; i < children.length; i++) {
			var child = children[i];
			if (child.nodeType == 1) {
				this.add(child);
			}
		}
	}
	
	Class.registerClass("benignware.view.Slideshow", Slideshow);

	Slideshow = Class(Component, Slideshow);
	__super = Class.getSuper(Slideshow);
	
	
	// styles
	//CSS.setDefaultStyle(".benignware.slideshow", "position", "relative");
	
	var progressImage = Class.getRessource(Slideshow, "ajax-loader.gif");
	CSS.setDefaultStyle(".benignware.slideshow .progress", "background-image", "url(" + progressImage + ")");
	CSS.setDefaultStyle(".benignware.slideshow .progress", "width", "16px");
	CSS.setDefaultStyle(".benignware.slideshow .progress", "height", "16px");
	
	// constants
	Slideshow.FORWARD = 1;
	Slideshow.REVERSE = -1;
	
	
	Slideshow.ALIGN_LEFT = "left";
	Slideshow.ALIGN_CENTER = "center";
	Slideshow.ALIGN_RIGHT = "right";
	Slideshow.ALIGN_TOP = "top";
	Slideshow.ALIGN_BOTTOM = "bottom";
	
	Slideshow.REVERSE = -1;
	
	// events
	Slideshow.POSITION_CHANGE = "positionChange";
	Slideshow.SLIDE = "slide";
	
	Slideshow.TRANSITION_START = "transitionStart";
	Slideshow.TRANSITION_COMPLETE = "transitionComplete";
	Slideshow.TRANSITION_END = "transitionFinish";
	
	Slideshow.TRANSITION_IN_START = "transitionInStart";
	Slideshow.TRANSITION_IN_FINISH = "transitionInFinish";
	Slideshow.TRANSITION_OUT_START = "transitionOutStart";
	Slideshow.TRANSITION_OUT_FINISH = "transitionOutFinish";
	
	
	// public
	Slideshow.prototype.loops = 0;
	Slideshow.prototype.progressImage = null;
	
	// protected
	Slideshow.prototype.__scaleMode = Image.BEST_FIT;
	Slideshow.prototype.__scaleBounds = false;
	
	Slideshow.prototype.__imageLoader = null;
	
	Slideshow.prototype.__autoLayout = true;
	
	Slideshow.prototype.__autoLayoutAlign = Slideshow.ALIGN_CENTER;
	Slideshow.prototype.__autoLayoutVAlign = Slideshow.ALIGN_CENTER;
	
	Slideshow.prototype.__autoPlay = true;
	Slideshow.prototype.__direction = Slideshow.FORWARD;
	
	Slideshow.prototype.__isPlaying = false;
	
	Slideshow.prototype.__transitionInPlaying = false;
	Slideshow.prototype.__transitionOutPlaying = false;
	
	Slideshow.prototype.__duration = 1;
	
	Slideshow.prototype.__items = null;
	
	Slideshow.prototype.__interruptible = false;
	Slideshow.prototype.__queueSlides = true;
	Slideshow.prototype.__slideQueue = null;
	Slideshow.prototype.__slideQueueMaxSize = 1;
	
	
	
	Slideshow.prototype.__transitionInType = Fade;
	Slideshow.prototype.__transitionOutType = Fade;
	
	Slideshow.prototype.__transitionDuration = 1.5;
	Slideshow.prototype.__transitionInDelay = 0;
	Slideshow.prototype.__transitionOutDelay = 0;
	
	Slideshow.prototype.__transitionIn = null;
	Slideshow.prototype.__transitionOut = null;
	
	Slideshow.prototype.__position = -1;
	Slideshow.prototype.__currentIndex = null;
	Slideshow.prototype.__currentElement = null;
	
	Slideshow.prototype.__initTimerRef = null;
	Slideshow.prototype.__delayTimerRef = null;
	Slideshow.prototype.__timerRef = null;
	
	Slideshow.prototype.__inTransitions = null;
	Slideshow.prototype.__outTransitions = null;
	
	Slideshow.prototype.__alwaysWaitForLoad = true;
	Slideshow.prototype.__waitingForLoadElement = null;
	
	Slideshow.prototype.__showProgressImage = true;
	
	/* Button Integration */
	Slideshow.prototype.__prevButton = null;
	Slideshow.prototype.__nextButton = null;
	
	Slideshow.prototype.__nextButtonDelegate = null;
	Slideshow.prototype.__prevButtonDelegate = null;
	Slideshow.prototype.__hideButtonsDelegate = null;
	Slideshow.prototype.__showButtonsDelegate = null;
	Slideshow.prototype.__layoutButtonsDelegate = null;
	
	
	Slideshow.prototype.__hideButtonsOnTransition = false;
	Slideshow.prototype.__snapButtonsToContent = false;
	
	Slideshow.prototype.__pausedOnMouseOver = false;
	
	Slideshow.prototype.__transitionOnInit = true;
	
	Slideshow.prototype.createChildren = function() {
		__super.createChildren.call(this);
		// progress feedback:
		this.progressImage = this.createElement('div');
		this.progressImage.className = "progress";
		this.progressImage.style.display = "none";
		this.progressImage.style.position = "absolute";
		
		this.appendChild(this.progressImage);
	}

	Slideshow.prototype.initialize = function() {
		__super.initialize.call(this);
		
		//
		this.addCSSName("slideshow");
		this.__slideQueue = [];
		this.__imageLoader = new ImageLoader();
		//
		this.__imageLoadDelegate = Delegate.create(this, imageLoadHandler);
		this.__imageLoader.addEventListener(ImageLoader.LOAD, this.__imageLoadDelegate);
		//
		this.__imageCompleteDelegate = Delegate.create(this, imageCompleteHandler);
		this.__imageLoader.addEventListener(ImageLoader.COMPLETE, this.__imageCompleteDelegate);
		//
		this.__inTransitions = [];
		this.__outTransitions = [];
		
		this.__items = [];
		
		window.setTimeout(Delegate.create(this, function(event) {
			if (this.__autoPlay) {
				this.start();
			}
		}), 1);
		//
		this.__initTimerDelegate = Delegate.create(this, initTimerHandler);
		
		this.__startTransitionInDelegate = Delegate.create(this, startTransitionIn);
		
		this.__startTransitionOutDelegate = Delegate.create(this, startTransitionOut);
		
		this.__autoPlayTimerDelegate = Delegate.create(this, autoPlayTimerHandler);
		
		this.__transitionInFinishedDelegate = Delegate.create(this, transitionInFinishHandler);
		
		this.__transitionOutFinishedDelegate = Delegate.create(this, transitionOutFinishHandler);

	}
	
	function imageLoadHandler(event) {
		if (this.__waitingForLoadElement) {
			var loaded = this.__imageLoader.isLoaded(this.__waitingForLoadElement);
			if (loaded) {
				this.__waitingForLoadElement = null;
				if (!this.__transitionInPlaying) {
					initTransitionIn.call(this);
					if (this.__alwaysWaitForLoad) {
						initTransitionOut.call(this);
					}
				}
			}
		}
	}
	
	function imageCompleteHandler(event) {
		this.progressImage.style.display = "none";
	}
	
	function initTimerHandler() {
		if (this.size() && !this.isPlaying()) {
			// start
			this.start();
		}
	}
	
	function autoPlayTimerHandler() {
		this.next();
	}

	// START TRANSITION IN
	
	function startTransitionIn() {
		
		var hasTransition = (this.__transitionInType && (this.__currentElement || this.__transitionOnInit));
		
		
		this.__currentElement = this.__nextElement;
		this.__currentIndex = this.__nextIndex;
		this.__currentElement.style.display = "block";
		//
		
		
		//
		var direction = this.__tempInDirection ? this.__tempInDirection : this.__direction;
		this.__tempInDirection = undefined;
		window.clearTimeout(this.__delayTimerRef);
		this.__delayTimerRef = null;
		
		var element = this.__currentElement;
		element.style.visibility = "visible";
		moveToFront(element);
		layoutElement.call(this, element);
		if (hasTransition) {
			// transition data
			var type = direction == Slideshow.REVERSE ? this.__transitionOutType : this.__transitionInType;
			
			var transitionIn = new type();
			transitionIn.setElement(element);
			transitionIn.scene = direction == Slideshow.REVERSE ? Transition.OUT : Transition.IN;
			transitionIn.direction = direction == Slideshow.REVERSE ? Tween.REVERSE : Tween.FORWARD;
			transitionIn.duration = this.__transitionInDuration;
			transitionIn.addEventListener(Tween.MOTION_FINISH, this.__transitionInFinishedDelegate, false);
			this.__inTransitions.push(transitionIn);			
			transitionIn.start();
		}

		// dispatch transition start event
		if (!this.__transitionInPlaying) {
			this.__transitionInPlaying = true;
			this.dispatchEvent(this.createEvent(Slideshow.TRANSITION_IN_START));
		}
		
		if (!hasTransition) {
			transitionInFinished.call(this);
		}
	}
	
	function transitionInFinishHandler(event) {
		var transition = event.target;
		removeTransitionIn.call(this, transition);
		if (this.__inTransitions.length == 0) {
			this.__transitionInPlaying = false;
		}
		transitionInFinished.call(this);
	}
	
	function transitionOutFinishHandler(event) {
		var transition = event.target;
		var element = transition.getElement();
		element.style.visibility = "hidden";
		removeTransitionOut.call(this, transition);
		// 
		transitionOutFinished.call(this);
	}
	
	function transitionInFinished() {
		this.__transitionInPlaying = false;
		initAutoPlayTimer.call(this);
		this.dispatchEvent(this.createEvent(Slideshow.TRANSITION_IN_FINISH));
		//
		var nextIndex = this.__currentIndex < this.size() - 1 ? this.__currentIndex + 1 : 0;
		var nextElement = this.__items[nextIndex];
		
		if (!this.__transitionOutPlaying) {
			transitionComplete.call(this);
		}
			
	}
	
	function transitionComplete() {
		if (this.__slideQueue.length) {
			doSlide.call(this);
		} else {
			var element = this.getItemAt(this.getNextPosition());
			this.__imageLoader.unshift(element);
		}
	}
	
	function transitionOutFinished() {
		this.__lastElement.style.display = "none";
		this.dispatchEvent(this.createEvent(Slideshow.TRANSITION_OUT_FINISH));
		if (this.__outTransitions.length == 0) {
			this.__transitionOutPlaying = false;
			if (this.__imageLoader.isLoading() && !this.__transitionInPlaying) {
				if (this.__showProgressImage) {
					this.progressImage.style.display = "";
				}
				this.resizeComponent();
			}
			this.dispatchEvent(this.createEvent(Slideshow.TRANSITION_END));
			if (!this.__transitionInPlaying) {
				transitionComplete.call(this);
			}
		}
	}
	
	function clearAutoPlayTimer() {
		if (this.__timerRef) {
			window.clearTimeout(this.__timerRef);
		}
	}
	
	function initAutoPlayTimer() {
		// init auto play timer:
		clearAutoPlayTimer.call(this);
		if (this.__isPlaying && this.getAutoPlay()) {
			this.__timerRef = window.setTimeout(this.__autoPlayTimerDelegate, this.__duration * 1000);
		}
	}
	
	// remove transitions
	function removeTransitionOut(transition) {
		transition.stop();
		for (var i = 0; i < this.__outTransitions.length; i++) {
			var trans = this.__outTransitions[i];
			if (transition == trans) {
				this.__outTransitions.splice(i, 1);
				break;
			}
		}
		transition.setElement(null);
		transition.removeEventListener(Tween.MOTION_FINISH, this.__transitionOutFinishedDelegate, false);
	}
	
	function removeTransitionIn(transition) {
		transition.stop();
		for (var i = 0; i < this.__inTransitions.length; i++) {
			var trans = this.__inTransitions[i];
			if (transition == trans) {
				this.__inTransitions.splice(i, 1);
				break;
			}
		}
		transition.setElement(null);
		transition.removeEventListener(Tween.MOTION_FINISH, this.__transitionInFinishedDelegate, false);
	}
	
	Slideshow.prototype.add = function(elem) {
		elem.style.visibility = "hidden";
		//element.style.display = "none";
		this.__items.push(elem);
		this.__imageLoader.add(elem);
		this.resizeComponent();
		// img
	}
	
	Slideshow.prototype.size = function() {
		return this.__items.length;
	}
	
	Slideshow.prototype.getItemAt = function(i) {
		return this.__items[i];
	}
	
	Slideshow.prototype.currentElement = function() {
		return this.__currentElement;
	}
	
	Slideshow.prototype.setTransitionInDelay = function(sec) {
		this.__transitionInDelay = sec;
	}
	
	Slideshow.prototype.getTransitionInDelay = function() {
		return this.__transitionInDelay;
	}
	
	Slideshow.prototype.setTransitionOutDelay = function(sec) {
		this.__transitionOutDelay = sec;
	}
	
	Slideshow.prototype.getTransitionOutDelay = function() {
		return this.__transitionOutDelay;
	}
	
	Slideshow.prototype.setTransitionType = function(transitionInType, transitionOutType) {
		if (typeof(transitionOutType) == "undefined") {
			transitionOutType = transitionInType;
		}
		
		this.setTransitionInType(transitionInType);
		this.setTransitionOutType(transitionOutType);
	}
	
	Slideshow.prototype.setTransitionInType = function(transitionType) {
		if (typeof(transitionType) == "string") {
			transitionType = transitionType == "none" ? null : transitionType;
			transitionType = Class.getClass(transitionType);
		}
		this.__transitionInType = transitionType;
	}
	
	Slideshow.prototype.setTransitionOutType = function(transitionType) {
		if (typeof(transitionType) == "string") {
			transitionType = transitionType == "none" ? null : transitionType;
			transitionType = Class.getClass(transitionType);
		}
		this.__transitionOutType = transitionType;
	}
	
	Slideshow.prototype.getTransitionType = function() {
		var obj = {};
		obj[Transition.IN] = this.__transitionInType;
		obj[Transition.OUT] = this.__transitionOutType;
		return obj;
	}
	
	Slideshow.prototype.getTransitionInType = function() {
		return this.__transitionInType;
	}
	
	Slideshow.prototype.getTransitionOutType = function() {
		return this.__transitionOutType;
	}
	
	Slideshow.prototype.isPlaying = function() {
		return this.__isPlaying;
	}
	
	Slideshow.prototype.isTransitionPlaying = function() {
		return (this.__transitionInPlaying || this.__transitionInPlaying);
	}
	
	Slideshow.prototype.isTransitionInPlaying = function() {
		return this.__transitionInPlaying;
	}
	
	Slideshow.prototype.isTransitionOutPlaying = function() {
		return this.__transitionOutPlaying;
	}
	
	Slideshow.prototype.start = function() {
		this.stop();
		this.setPosition(0);
		this.play();
	}
	
	Slideshow.prototype.stop = function() {
		this.__isPlaying = false;
		clearAutoPlayTimer.call(this);
	}
	
	Slideshow.prototype.pause = function() {
		if (this.__isPlaying) {
			this.__isPlaying = false;
			clearAutoPlayTimer.call(this);
		}
	}
	
	Slideshow.prototype.play = function() {
		if (!this.__isPlaying) {
			this.__isPlaying = true;
			initAutoPlayTimer.call(this);
		}
		if (this.getPosition() == -1) {
			this.setPosition(0);
		}
	}
	
	Slideshow.prototype.togglePlay = function() {
		if (!this.__isPlaying) {
			this.play();
		} else {
			this.pause();
		}
	}
	
	Slideshow.prototype.setPosition = function(pos, direction) {
//		if (pos < 0 || pos > this.size() - 1) {
//			return;
//		}
		if (this.__position != pos) {
			this.__position = pos;
			var slide = {position: pos, direction: direction};
			if (this.__slideQueue.length >= this.__slideQueueMaxSize) {
				this.__slideQueue = this.__slideQueue.slice(0, this.__slideQueueMaxSize - 1);
			}
			this.__slideQueue.push(slide);
			//
			this.dispatchEvent(this.createEvent(Slideshow.POSITION_CHANGE));
			if (!this.isTransitionInPlaying()) {
				doSlide.call(this);
			}
		}
	}
	
	Slideshow.prototype.getPosition = function() {
		return this.__position;
	}
	
	function doSlide() {
		var slide = this.__slideQueue.shift();
		if (!slide) {
			return;
		}
		//
		var index = slide.position;
		var direction = slide.direction;
		
		if (typeof(direction) == "undefined") {
			direction = this.__direction;
		}

		window.clearTimeout(this.__timerRef);
		
		var size = this.size();
		if (index < 0) {
			index = 0;
		}
		
		var element = this.__items[index];
		if (element != this.__currentElement) {
			
			if (this.__delayTimerRef) {
				window.clearTimeout(this.__delayTimerRef);
				this.__delayTimerRef = null;
			}

			this.__lastElement = this.__currentElement;
			
			
			if (this.__lastElement) {
				for (var i = 0; i < this.__inTransitions.length; i++) {
					var transition = this.__inTransitions[i];
					var e = transition.getElement();
					if (e == this.__lastElement && e != element) {
						removeTransitionIn.call(this, transition);
						break;
					}
				}
				if (this.__lastElement.visibility != "hidden" && !this.__imageLoader.isLoaded(element) && this.__alwaysWaitForLoad) {
					
					this.__transitionOutStartDelegate();
				}
			} 
			
			var transIn = true;
			for (var i = 0; i < this.__inTransitions.length; i++) {
				var transition = this.__inTransitions[i];
				var e = transition.getElement();
				if (e == element) {
					transIn = false;
				}
			}
			
			if (typeof(direction) != undefined) {
				this.__tempOutDirection = direction;
				this.__tempInDirection = direction;
			}
			
			if (transIn) {	
				this.__nextElement = element;
				this.__nextIndex = index;

				if (!this.__imageLoader.isLoaded(element)) {
					if (!this.isTransitionOutPlaying() && this.__showProgressImage) {
						this.progressImage.style.display = "";
						this.resizeComponent();
					}
					this.__waitingForLoadElement = element;
					this.__imageLoader.unshift(element);
					this.__imageLoader.start();
				} else {
					// start transition in
					initTransitionIn.call(this);
					if (this.__alwaysWaitForLoad) {
						initTransitionOut.call(this);
					}
				}
			}
		}
	}

	function initTransitionIn() {
		this.progressImage.style.display = "none";
		this.resizeComponent();
		var delay = this.__lastElement ? this.__transitionInDelay * 1000 : 0;
		if (delay) {
			this.__delayTimerRef = window.setTimeout(this.__startTransitionInDelegate, delay);
		} else {
			startTransitionIn.call(this);
		}
		this.dispatchEvent(this.createEvent(Slideshow.TRANSITION_START));
	}
	
	function initTransitionOut() {
		var delay = this.__transitionOutDelay * 1000;
		if (delay) {
			this.__delayTimerRef = window.setTimeout(this.__startTransitionOutDelegate, delay);
		} else {
			startTransitionOut.call(this);
		}
	}
	
	function startTransitionOut() {
		if (!this.__lastElement) return;
		if (this.__waitingForLoadElement) return;
		this.__lastElement.style.display = "block";
		this.resizeComponent();
		
		var direction = this.__tempOutDirection ? this.__tempOutDirection : this.__direction;
		this.__tempOutDirection = undefined;

		if (!this.__delayTimerRef) {
			var transIn = false;
			var c = 0;
			for (var i = 0; i < this.__inTransitions.length; i++) {
				var transition = this.__inTransitions[i];
				var e = transition.getElement();
				if (e == this.__lastElement) {
					transIn = true;
					break;
				}
			}
			
			if (!transIn) {
				this.__lastElement.style.visibility = "hidden";
			} else {
				
			}
			
			element = this.__lastElement;
			this.insertBefore(element, this.__lastElement);
			element.style.visibility = "visible";
			
			var hasTransition = (this.__transitionInType);
			if (hasTransition) {
				var type = direction == Slideshow.REVERSE ? this.__transitionInType : this.__transitionOutType;

				var transitionOut = new type();
				transitionOut.setElement(element);
				transitionOut.scene = direction == Slideshow.REVERSE ? Transition.IN : Transition.OUT;
				transitionOut.direction = direction == Slideshow.REVERSE ? Tween.REVERSE : Tween.FORWARD;
				transitionOut.duration = this.__transitionOutDuration;
				transitionOut.addEventListener(Tween.MOTION_FINISH, this.__transitionOutFinishedDelegate, false);
				this.__outTransitions.push(transitionOut);
				this.__transitionOutPlaying = true;
				transitionOut.start();
			}
			//
			this.dispatchEvent(this.createEvent(Slideshow.TRANSITION_OUT_START));
			if (!hasTransition) {
				transitionOutFinished.call(this);
			}
		}
	}
	
	Slideshow.prototype.getCurrentPosition = function() {
		return this.__currentIndex;
	}
	
	Slideshow.prototype.getNextPosition = function() {
		var pos = this.getPosition() + 1;
		if (pos >= this.size()) {
			if (this.loops == 0) {
				pos = 0;
			} else {
				pos = -1;
			}
		}
		return pos;
	}
	
	Slideshow.prototype.getPreviousPosition = function() {
		var pos = this.getPosition() - 1;
		if (pos < 0) {
			if (this.loops == 0) {
				pos = this.size() - 1;
			} else {
				pos = -1;
			}
		}
		return pos;
	}
	
	Slideshow.prototype.next = function() {
		this.setPosition(this.getNextPosition());
	}
	
	Slideshow.prototype.previous = function() {
		this.setPosition(this.getPreviousPosition(), this.getDirection() * -1);
	}
	
	Slideshow.prototype.setDuration = function(duration) {
		this.__duration = duration;
	}
	
	Slideshow.prototype.getDuration = function(duration) {
		return this.__duration;
	}
	
	Slideshow.prototype.setAutoPlay = function(bool) {
		bool = StringUtils.getBoolean(bool);
		if (bool != this.__autoPlay) {
			if (bool) {
				// start
			} else {
				window.clearTimeout(this.__initTimerRef);
				window.clearTimeout(this.__timer);
			}
			this.__autoPlay = bool;
		}
	}
	
	Slideshow.prototype.getAutoPlay = function() {
		return this.__autoPlay;
	}
	
	Slideshow.prototype.setTransitionDuration = function(duration) {
		this.setTransitionInDuration(duration);
		this.setTransitionOutDuration(duration);
	}
	
	Slideshow.prototype.getTransitionDuration = function() {
		var obj = {};
		obj[Transition.IN] = this.__transitionInDuration;
		obj[Transition.OUT] = this.__transitionOutDuration;
		return obj;
	}
	
	Slideshow.prototype.setTransitionInDuration = function(duration) {
		this.__transitionInDuration = parseFloat(duration);
		for (var i = 0; i < this.__inTransitions.length; i++) {
			this.__inTransitions[i].duration = duration;
		}
	}
	
	Slideshow.prototype.getTransitionInDuration = function() {
		return this.__transitionInDuration;
	}
	
	Slideshow.prototype.setTransitionOutDuration = function(duration) {
		this.__transitionOutDuration = parseFloat(duration);
		for (var i = 0; i < this.__outTransitions.length; i++) {
			this.__outTransitions[i].duration = duration;
		}
	}
	
	Slideshow.prototype.getTransitionOutDuration = function() {
		return this.__transitionOutDuration;
	}
	
	Slideshow.prototype.setInterruptible = function(bool) {
		this.__interruptible = bool;
	}
	
	Slideshow.prototype.getInterruptible = function() {
		return this.__transitionOutDuration;
	}
	
	Slideshow.prototype.setQueueSlides = function(bool) {
		this.__queueSlides = bool;
	}
	
	Slideshow.prototype.getQueueSlides = function() {
		return this.__queueSlides;
	}
	
	Slideshow.prototype.setQueueMaxSize = function(num) {
		this.__slideQueueMaxSize = parseInt(num);
	}
	
	Slideshow.prototype.getQueueMaxSize = function() {
		return this.__slideQueueMaxSize;
	}
	
	Slideshow.prototype.setDirection = function(code) {
		this.__direction = parseInt(code) < 0 ? Slideshow.REVERSE : Slideshow.FORWARD;
	}
	
	Slideshow.prototype.getDirection = function() {
		return this.__direction;
	}
	
	Slideshow.prototype.setAutoLayout = function(bool) {
		this.__autoLayout = bool;
	}
	
	Slideshow.prototype.getAutoLayout = function() {
		return this.__autoLayout;
	}
	
	Slideshow.prototype.setHorizontalAlign = function(bool) {
		this.__autoLayoutAlign = bool;
	}
	
	Slideshow.prototype.getHorizontalAlign = function() {
		return this.__autoLayoutAlign;
	}
	
	Slideshow.prototype.setVerticalAlign = function(str) {
		this.__autoLayoutVAlign = str;
	}
	
	Slideshow.prototype.getVerticalAlign = function() {
		return this.__autoLayoutVAlign;
	}
	
	Slideshow.prototype.setScaleMode = function(scaleMode) {
		this.__scaleMode = scaleMode;
	}
	
	Slideshow.prototype.getScaleMode = function() {
		return this.__scaleMode;
	}
	
	Slideshow.prototype.setScaleBounds = function(scaleBounds) {
		this.__scaleBounds = scaleBounds;
	}
	
	Slideshow.prototype.getScaleBounds = function() {
		return this.__scaleBounds;
	}

	Slideshow.prototype.setTransitionOnInit = function(bool) {
		this.__transitionOnInit = StringUtils.getBoolean(bool);
	}
	
	Slideshow.prototype.getTransitionOnInit = function() {
		return this.__transitionOnInit;
	}
	
	Slideshow.prototype.setShowProgressImage = function(bool) {
		this.__showProgressImage = StringUtils.getBoolean(bool);
	}
	
	Slideshow.prototype.getShowProgressImage = function() {
		return this.__showProgressImage;
	}
	
	function layoutProgressImage() {
		var b = this.getBorderMetrics('border');
		var x = (this.offsetWidth - this.progressImage.offsetWidth) * 0.5;
		var y = (this.offsetHeight - this.progressImage.offsetHeight) * 0.5;
		this.progressImage.style.left = x + "px";
		this.progressImage.style.top = y + "px";
		
	}

	Slideshow.prototype.resizeComponent = function() {
		if (this.getAutoLayout()) {
			for (var i = 0; i < this.childNodes.length; i++) {
				var child = this.childNodes[i];
				if (child.nodeType == 1) {
					scaleElement.call(this, child);
				}
			}
			
			for (var i = 0; i < this.childNodes.length; i++) {
				var element = this.childNodes[i];
				if (element.nodeType == 1 && element != this.progressImage) {
					
					layoutElement.call(this, element);
					/*
					var trans;
					for (var t = 0; t < this.__inTransitions.length; t++) {
						var transition = this.__inTransitions[t];
						var e = transition.getElement();
						if (e == element) {
							trans = transition;
							trans.update();
						}
					}
					for (var t = 0; t < this.__outTransitions.length; t++) {
						var transition = this.__outTransitions[t];
						var e = transition.getElement();
						if (e == element) {
							trans = transition;
							trans.update();
						}
					}
					if (!trans || !trans.isPlaying()) {
						
					}
					*/
				}
			}
			
			
			// update transitions
			for (var t = 0; t < this.__inTransitions.length; t++) {
				var transition = this.__inTransitions[t];
				transition.update();
			}
			for (var t = 0; t < this.__outTransitions.length; t++) {
				var transition = this.__outTransitions[t];
				transition.update();
			}
			
			
			
			layoutProgressImage.call(this);
			
		}
	}
	
	
	
	function getScaledSize(originalWidth, originalHeight, maxWidth, maxHeight, scaleMode) {
		scaleMode = typeof(scaleMode) != "undefined" ? scaleMode : 1;
		
		var r1 = originalWidth / maxWidth;
		var r2 = originalHeight / maxHeight;
		var w, h;
		if (scaleMode == 1 || scaleMode == 2) {
			var largestRatio;
			if (scaleMode == 1) {
				largestRatio = Math.max(r1, r2);
			} else {
				largestRatio = Math.min(r1, r2);
			}
			w = originalWidth * (1 / largestRatio);
			h = originalHeight * (1 / largestRatio);
		}
		w = w < originalWidth ? w : originalWidth;
		h = h < originalHeight ? h : originalHeight;
		return {
			width: w, 
			height: h
		}
	}
	
	function scaleElement(element) {
		var element = DOM.getDeepestElement(element);
		if (element.tagName.toLowerCase() == "img") {
			var b = this.getBorderMetrics();
			var maxWidth = this.offsetWidth - b.left - b.right;
			var maxHeight = this.offsetHeight - b.top - b.bottom;
			Image.scale(element, maxWidth, maxHeight, this.getScaleMode(), this.getScaleBounds());
		}
	}
	
	function getIEVersion() {

	    var undef,
	        v = 3,
	        div = document.createElement('div'),
	        all = div.getElementsByTagName('i');

	    while (
	        div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
	        all[0]
	    );

	    return v > 4 ? v : undef;

	};

	
	function layoutElement(element) {
		
		var w = this.offsetWidth;
		var h = this.offsetHeight;
		var op = this.offsetParent;

		if (!op) {
			return;
		}
		var px = op.offsetLeft;
		var py = op.offsetTop;
		
		
		var b = this.getBorderMetrics('border');
		var m = this.getBorderMetrics('border', 'margin');
		
		var x = this.offsetLeft + m.left;
		var y = this.offsetTop + m.top;
		
		var ie = getIEVersion();
		if (ie <= 7) {
			x-= this.offsetParent.offsetLeft;
		}
		element.style.position = "absolute";
		
		var ew = element.offsetWidth;
		var eh = element.offsetHeight;
		
		
		
		var align = this.getHorizontalAlign();
		var a = align == Slideshow.ALIGN_LEFT ? 0 : align == Slideshow.ALIGN_RIGHT ? 1 : 0.5; 
		
		var vAlign = this.getVerticalAlign();
		var va = vAlign == Slideshow.ALIGN_TOP ? 0 : vAlign == Slideshow.ALIGN_BOTTOM ? 1 : 0.5; 
		
		var ex = x + ((w - ew) * a) - b.left;
		var ey = y + ((h - eh) * va) - b.top - b.bottom;
		//
		element.style.left = ex + "px";
		element.style.top = ey + "px";
	}
	
	
	
	function moveToFront(elem) {
		elem.parentNode.appendChild(elem);
	}
	
	
	/* Button Integration */
	
	Slideshow.prototype.setNextButton = function(elem) {
		elem = typeof(elem) == "string" ? this.ownerDocument.getElementById(elem) : elem;
		if (elem != this.__nextButton) {
			if (this.__nextButton) {
				this.__nextButton.removeEventListener('click', this.__nextButtonClickDelegate);
			}
			this.__nextButton = elem;
			if (this.__nextButton) {
				if (this.__nextButtonClickDelegate == null) {
					this.__nextButtonClickDelegate = Delegate.create(this, nextButtonClickHandler);
				}
				Element.addEventListener(this.__nextButton, 'click', this.__nextButtonClickDelegate, false);
			}
		}
	}
	
	Slideshow.prototype.getNextButton = function() {
		return this.__nextButton;
	}
	
	Slideshow.prototype.setPrevButton = function(elem) {
		elem = typeof(elem) == "string" ? this.ownerDocument.getElementById(elem) : elem;
		if (elem != this.__prevButton) {
			if (this.__prevButton && this.__prevButtonDelegate) {
				this.__prevButton.removeEventListener('click', this.__prevButtonDelegate);
			}
			this.__prevButton = elem;
			if (this.__prevButton) {
				if (this.__prevButtonDelegate == null) {
					this.__prevButtonDelegate = Delegate.create(this, prevButtonClickHandler);
				}
				Element.addEventListener(this.__prevButton, 'click', this.__prevButtonDelegate, false);
			}
		}
	}
	
	Slideshow.prototype.getPrevButton = function() {
		return this.__prevButton;
	}
	
	function nextButtonClickHandler(event) {
		event = Event.getEvent(event);
		this.next();
		event.preventDefault();
	}
	
	function prevButtonClickHandler(event) {
		event = Event.getEvent(event);
		this.previous();
		event.preventDefault();
	}
	
	Slideshow.prototype.setHideButtonsOnTransition = function(bool) {
		bool = StringUtils.getBoolean(bool);
		if (this.__hideButtonsOnTransition != bool) {
			this.__hideButtonsOnTransition = bool;
			if (this.__showButtonsDelegate == null) {
				this.__showButtonsDelegate = Delegate.create(this, showButtons);
			}
			if (this.__hideButtonsDelegate == null) {
				this.__hideButtonsDelegate = Delegate.create(this, hideButtons);
			}
			if (bool) {
				this.addEventListener(Slideshow.TRANSITION_COMPLETE, this.__showButtonsDelegate, false);
				this.addEventListener(Slideshow.TRANSITION_START, this.__hideButtonsDelegate, false);
			} else {
				this.removeEventListener(Slideshow.TRANSITION_COMPLETE, this.__showButtonsDelegate, false);
				this.removeEventListener(Slideshow.TRANSITION_START, this.__hideButtonsDelegate, false);
			}
			
			if (this.currentElement() && !this.isTransitionPlaying()) {
				showButtons.call(this);
			} else {
				hideButtons.call(this);
			}
		}
	}
	
	Slideshow.prototype.getHideButtonsOnTransition = function() {
		return this.__hideButtonsOnTransition;
	}
	
	function showButtons() {
		if (this.__nextButton) {
			this.__nextButton.style.visibility = "visible";
		}
		if (this.__prevButton) {
			this.__prevButton.style.visibility = "visible";
		}
	}
	
	function hideButtons() {
		if (this.__nextButton) {
			this.__nextButton.style.visibility = "hidden";
		}
		if (this.__prevButton) {
			this.__prevButton.style.visibility = "hidden";
		}
	}

	
	Slideshow.prototype.setSnapButtonsToContent = function(bool) {
		bool = StringUtils.getBoolean(bool);
		if (this.__snapButtonsToContent != bool) {
			this.__snapButtonsToContent = bool;
			this.__layoutButtonsDelegate = Delegate.create(this, layoutButtons);
			if (bool) {
				this.addEventListener(Slideshow.TRANSITION_IN_FINISH, this.__layoutButtonsDelegate, false);
			} else {
				this.removeEventListener(Slideshow.TRANSITION_IN_FINISH, this.__layoutButtonsDelegate, false);
			}
		}
	}
	
	Slideshow.prototype.getSnapButtonsToContent = function() {
		return this.__snapButtonsToContent;
	}
	
	function layoutButtons() {
		
		this.__nextButton.style.position = "absolute";
		this.__nextButton.style.left = "0px";
		if (this.__snapButtonsToContent) {
			var element = this.currentElement();
			if (element) {
				var spos = Element.getPosition(element.offsetParent);
				if (this.__nextButton) {
					var nbpos = Element.getPosition(this.__nextButton.offsetParent);
					var npos = {x: spos.x - nbpos.x, y: spos.y - nbpos.y}
					var m = Element.getBorderMetrics(this.__nextButton, 'margin');
					var ny = npos.y + this.offsetTop + (this.offsetHeight - this.__nextButton.offsetHeight - m.top - m.bottom) / 2;
					var nx = npos.x + element.offsetLeft + element.offsetWidth - this.__nextButton.offsetWidth - m.right - m.left;
					this.__nextButton.style.left = nx + "px";
					this.__nextButton.style.top = ny + "px";
				}
				if (this.__prevButton) {
					var pbpos = Element.getPosition(this.__prevButton.offsetParent);
					var ppos = {x: spos.x - pbpos.x, y: spos.y - pbpos.y}
					var m = Element.getBorderMetrics(this.__prevButton, 'margin');
					var py = ppos.y + this.offsetTop + (this.offsetHeight - this.__prevButton.offsetHeight - m.top - m.bottom) / 2;
					var px = ppos.x + element.offsetLeft;
					this.__prevButton.style.position = "absolute";
					this.__prevButton.style.left = px + "px";
					this.__prevButton.style.top = py + "px";
				}
			}
		}
	}
	
	Slideshow.prototype.setPausedOnMouseOver = function(bool) {
		bool = StringUtils.getBoolean(bool);
		if (this.__pausedOnMouseOver != bool) {
			this.__pausedOnMouseOver = bool;
			if (this.__mouseEnterDelegate == null) {
				this.__mouseEnterDelegate = Delegate.create(this, mouseEnterHandler);
			}
			if (this.__mouseLeaveDelegate == null) {
				this.__mouseLeaveDelegate = Delegate.create(this, mouseLeaveHandler);
			}
			if (bool) {
				this.addEventListener('mouseenter', this.__mouseEnterDelegate, false);
				this.addEventListener('mouseleave', this.__mouseLeaveDelegate, false);
			} else {
				this.removeEventListener('mouseenter', this.__mouseEnterDelegate, false);
				this.removeEventListener('mouseleave', this.__mouseLeaveDelegate, false);
			}
		}
	}
	
	function mouseEnterHandler(event) {
		event = Event.getEvent(event);
		this.pause();
	}
	
	function mouseLeaveHandler(event) {
		event = Event.getEvent(event);
		if (!this.__snapButtonsToContent || event.relatedTarget != this.__nextButton && event.relatedTarget != this.__prevButton) {
			this.play();
		}
	}

	

	return Slideshow;
})();
(function(){
	// import classes
	var Class = benignware.core.Class;
	var Component = Class.require("benignware.core.Component");
	var Delegate = Class.require("benignware.utils.Delegate");
	var DOM = Class.require("benignware.utils.DOM");
	var CSS = Class.require("benignware.utils.CSS");
	var Event = Class.require("benignware.events.Event");
	var Element = Class.require("benignware.core.Element");
	var StringUtils = Class.require("benignware.utils.StringUtils");
	
	var Tween = Class.require("benignware.transitions.Tween");
	var Transition = Class.require("benignware.transitions.Transition");
	var Fade = Class.require("benignware.transitions.Fade");
	var Regular = Class.require("benignware.transitions.easing.Regular");
	
	
	var Image = Class.require("benignware.core.Image");
	var ImageLoader = Class.require("benignware.view.ImageLoader");
	// define super
	var __super;

	
	/**
	 * Constructs a new form-element.
	 * @constructor
	 */
	function ItemScroller() {
		var children = [];
		if (this.innerHTML) {
			DOM.stripWhitespace(this);
			for (var i = 0; i < this.childNodes.length; i++) {
				var child = this.childNodes[i];
				if (child.nodeType == 1) {
					if (child.nodeName.toLowerCase() != "script" && child.nodeName.toLowerCase() != "link") {
						children.push(child);
					}
				}
			}
		}
		__super.call(this);
		for (var i = 0; i < children.length; i++) {
			var child = children[i];
			if (child.nodeType == 1) {
				this.add(child);
			}
		}
	}
	
	Class.registerClass("benignware.view.ItemScroller", ItemScroller);

	ItemScroller = Class(Component, ItemScroller);
	__super = Class.getSuper(ItemScroller);
	
	// events
	ItemScroller.CHANGE = "change";

	// protected
	
	ItemScroller.prototype.__imageLoader = null;
	ItemScroller.prototype.__items = null;
	
	ItemScroller.prototype.__scrollDuration = null;
	ItemScroller.prototype.__scrollTween = null;
	
	ItemScroller.prototype.initialize = function() {
		__super.initialize.call(this);
		this.__items = [];
		this.__imageLoader = new ImageLoader();
		this.__imageLoader.addEventListener(ImageLoader.LOAD, Delegate.create(this, imageLoadHandler));
		
		//
//		this.addEventListener("mousemove", Delegate.create(this, mouseMoveHandler));
		this.__scrollTween = new Tween(this.__scrollDuration);
		this.__scrollTween.addEventListener(Tween.MOTION_CHANGE, Delegate.create(this, motionChangeHandler));
		this.__scrollTween.begin = 0; 
		this.__scrollTween.finish = 1;
		this.__scrollTween.easeFunction = Regular.easeInOut;
		this.__scrollTween.stop();
	}
	
	function imageLoadHandler(event) {
		this.resizeComponent();
	}
	
	ItemScroller.prototype.createChildren = function() {
		__super.createChildren.call(this);
	}
	
	ItemScroller.prototype.add = function(elem) {
		this.__items.push(elem);
		this.__imageLoader.add(elem);
		this.__imageLoader.start();
		this.__itemClickDelegate = Delegate.create(this, itemClickHandler);
		Element.addEventListener(elem, 'mousedown', this.__itemClickDelegate, false);
		this.resizeComponent();
	}
	
	function itemClickHandler(event) {
		event = Event.getEvent(event);
		var target = event.target;
		var item = null;
		for (var i = 0; i < this.__items.length; i++) {
			item = this.__items[i];
			if (target == item || DOM.isChildOf(target, item)) {
				this.setSelectedItem(item);
				break;
			}
		}
	}
	
	// container implementation
	ItemScroller.prototype.getItemAt = function(index) {
		return this.__items[index];
	}
	
	ItemScroller.prototype.getItemIndex = function(item) {
		for (var i = 0; i < this.__items.length; i++) {
			if (this.__items[i] == item) return i;
		}
	}
	
	// layout
	ItemScroller.prototype.resizeComponent = function() {
		var x = 0;
		for (var i = 0; i < this.__items.length; i++) {
			var item = this.__items[i];
			item.style.position = "absolute";
			item.style.left = x + "px";
//			var y = (this.offsetHeight - item.height) * 0.5;
//			item.style.top = y + "px";
			x+= item.offsetWidth;
			
		}
	}
	
	ItemScroller.prototype.setPosition = function(index) {
		this.setSelectedItem(this.getItemAt(index));
	}
	
	ItemScroller.prototype.getPosition = function() {
		return this.getItemIndex(this.getSelectedItem());
	}
	
	ItemScroller.prototype.size = function() {
		return this.__items.length;
	}
	
	ItemScroller.prototype.next = function() {
		var pos = this.getPosition();
		this.setPosition(pos + 1 < this.size() - 1 ? pos + 1 : this.size() - 1);
	}
	
	ItemScroller.prototype.previous = function() {
		var pos = this.getPosition();
		this.setPosition(pos - 1 > 0 ? pos - 1 : 0);
	}
	
	ItemScroller.prototype.setSelectedItem = function(item) {
		if (this.__selectedItem != item) {
			if (this.__selectedItem) {
				Element.removeCSSName(this.__selectedItem, 'selected');
			}
			this.__selectedItem = item;
			moveToSelectedItem.call(this);
			Element.addCSSName(item, 'selected');
			// change event
			this.dispatchEvent(this.createEvent(ItemScroller.CHANGE, false, false));
		}
	}
	
	ItemScroller.prototype.getSelectedItem = function() {
		return this.__selectedItem;
	}
	
	function moveToSelectedItem() {
		var item = this.__selectedItem;
		var m = Element.getBorderMetrics(item, 'margin');
		var x = item.offsetLeft;
		var y = item.offsetTop;
		
		this.__scrollXMin = this.scrollLeft;
		this.__scrollYMin = this.scrollTop;
		//
		var a = 0.5;
		var va = 0.5;
		//
		var sx = x -(this.offsetWidth - item.offsetWidth) * a;
		this.__scrollYMax = y - (this.offsetHeight - item.offsetHeight) * va;
		
		this.__scrollXMax = sx < 0 ? 0 : sx;
		//
//		if (this.__scrollXMax != this.scrollLeft && this.__scrollXMax < this.scrollWidth - this.offsetWidth) {
			this.__scrollTween.start();
//		}

		
	}
	
	function motionChangeHandler(event) {
		
		var p = this.__scrollTween.getPosition();
		
		var x = this.__scrollXMin + ((this.__scrollXMax - this.__scrollXMin) * p);
		var y = this.__scrollYMin + ((this.__scrollYMax - this.__scrollYMin) * p);
		var item = this.__selectedItem;

		this.scrollLeft = x;
//		this.scrollTop = y;
	}
	
	
	
	
/* Button Integration */
	
	ItemScroller.prototype.__nextButton = null;
	ItemScroller.prototype.__prevButton = null;
	
	ItemScroller.prototype.setNextButton = function(elem) {
		elem = typeof(elem) == "string" ? this.ownerDocument.getElementById(elem) : elem;
		if (elem != this.__nextButton) {
			if (this.__nextButton) {
				this.__nextButton.removeEventListener('mousedown', this.__nextButtonClickDelegate);
			}
			this.__nextButton = elem;
			if (this.__nextButton) {
				if (this.__nextButtonClickDelegate == null) {
					this.__nextButtonClickDelegate = Delegate.create(this, nextButtonClickHandler);
				}
				Element.addEventListener(this.__nextButton, 'mousedown', this.__nextButtonClickDelegate, false);
			}
		}
	}
	
	ItemScroller.prototype.getNextButton = function() {
		return this.__nextButton;
	}
	
	ItemScroller.prototype.setPrevButton = function(elem) {
		elem = typeof(elem) == "string" ? this.ownerDocument.getElementById(elem) : elem;
		if (elem != this.__prevButton) {
			if (this.__prevButton && this.__prevButtonDelegate) {
				this.__prevButton.removeEventListener('mousedown', this.__prevButtonDelegate);
			}
			this.__prevButton = elem;
			if (this.__prevButton) {
				if (this.__prevButtonDelegate == null) {
					this.__prevButtonDelegate = Delegate.create(this, prevButtonClickHandler);
				}
				Element.addEventListener(this.__prevButton, 'mousedown', this.__prevButtonDelegate, false);
			}
		}
	}
	
	ItemScroller.prototype.getPrevButton = function() {
		return this.__prevButton;
	}
	
	function nextButtonClickHandler(event) {
		event = Event.getEvent(event);
		this.next();
		event.preventDefault();
	}
	
	function prevButtonClickHandler(event) {
		event = Event.getEvent(event);
		this.previous();
		event.preventDefault();
	}
	
	
	return ItemScroller;
})();
/**
 * Extend this class to build custom form elements that can be placed on any html form.
 * Subclasses must implement the public method getValue in order to send the current value when submitting the form. 
 * Use the setName method or name property to set the key for this component.
 * @class benignware.controls.Slideshow
 * @extends benignware.core.Component
 * @see benignware.controls.Form
 */
(function(){
	// import classes
	var Class = benignware.core.Class;
	var Event = Class.require("benignware.events.Event");
	var Element = Class.require("benignware.core.Element");
	var Component = Class.require("benignware.core.Component");
	var DOM = Class.require("benignware.utils.DOM");
	var CSS = Class.require("benignware.utils.CSS");
	var Delegate = Class.require("benignware.utils.Delegate");
	var StringUtils = Class.require("benignware.utils.StringUtils");
	var ArrayUtils = Class.require("benignware.utils.ArrayUtils");

	var Tween = Class.require("benignware.transitions.Tween");
	var Regular = Class.require("benignware.transitions.easing.Regular");
	
	// define super
	var __super;

	// styles
//	CSS.setDefaultStyle(".benignware.anchor", "position", "relative");
	
	/**
	 * Constructs a new form-element.
	 * @constructor
	 */
	function Anchor() {
		__super.call(this);
	}
	
	var tweens = [];
	
	Class.registerClass("benignware.view.Anchor", Anchor);

	Anchor = Class(Component, Anchor);
	__super = Class.getSuper(Anchor);
	
	Anchor.prototype.__baseElement = "a";
	Anchor.prototype.__tween = null;
	
	var scrolling = false;

	Anchor.prototype.initialize = function() {
		__super.initialize.call(this);
		this.addCSSName("anchor");
		Anchor.initialize(this);
	}
	
	Anchor.prototype.setDuration = function(duration) {
		this.__duration = parseFloat(duration);
	}
	
	Anchor.prototype.getDuration = function(duration) {
		return this.__duration;
	}
	
	Anchor.prototype.getHash = function() {
		var href = this.getAttribute("href");
		var p = /#(.*)/;
		var reg = new RegExp( p );
		var m = reg.exec(href);
		if (m) {
			return m[1];
		}
		return null;
	}
	
	function stopTweens() {
		for (var i = 0 ; i < tweens.length; i++) {
			var tweenData = tweens[i];
			if (tweenData.element.ownerDocument == this.ownerDocument) {
				tweenData.tween.stop();
				tweens.splice(i--, 1);
			}
		}
	}
	
	function update(event) {
		var tween = event.target;
		var sy = tween.getPosition();
		// update
		var win = Element.getDefaultView(this);
		var s = Element.getScrollPosition(this.ownerDocument);
		win.scrollTo(s.x, sy);
	}
	
	function finish() {
		var win = Element.getDefaultView(this);
		var hash = Anchor.prototype.getHash.call(this);
		var loc = win.location;
		var url = loc.protocol + "//" + loc.host; 
		if (loc.port) {
			url+= ":" + loc.port;
		}
		url+= loc.pathname;
		url+= "#" + hash;
		window.location.href = url;
	}
	
	function getAnchor(name) {
		var anchors = this.ownerDocument.getElementsByTagName('a');
		for (var i = 0; i < anchors.length; i++) {
			var a = anchors[i];
			if (a.getAttribute("name") == name) {
				return a;
			}
		}
		return null;
	}
	
	Anchor.initialize = function(anchor) {
		var doc = anchor ? anchor.ownerDocument ? anchor.ownerDocument : anchor : document;
		var anchor = anchor != doc ? anchor : null;
		
		if (!anchor) {
			// whole document
			var anchors = doc.getElementsByTagName('a');
			for (var i = 0; i < anchors.length; i++) {
				var a = anchors[i];
				var hash = Anchor.prototype.getHash.call(a);
				if (hash) {
					Anchor.initialize(a);
				}
			}
			return;
		}
		
		var motionStartDelegate = Delegate.create(anchor, function(event) {
			var tween = event.target;
			tween.addEventListener(Tween.MOTION_CHANGE, motionChangeDelegate);
			tween.addEventListener(Tween.MOTION_FINISH, motionFinishDelegate);
			tween.addEventListener(Tween.MOTION_STOP, motionStopDelegate);
		});
		
		var motionChangeDelegate = Delegate.create(anchor, update);
		
		var motionFinishDelegate = Delegate.create(anchor, function(event) {
			var tween = event.target;
			tween.removeEventListener(Tween.MOTION_START, motionStartDelegate);
			window.setTimeout(Delegate.create(this, finish), 0);
			stopTweens.call(this);
			tween = null;
		});
		
		var motionStopDelegate = Delegate.create(anchor, function(event){
			var tween = event.target;
			tween.removeEventListener(Tween.MOTION_CHANGE, this.__motionChangeDelegate);
			tween.removeEventListener(Tween.MOTION_FINISH, motionFinishDelegate);
			tween.removeEventListener(Tween.MOTION_STOP, motionStopDelegate);
		});
		
		var clickDelegate = Delegate.create(anchor, function(event) {
			event = Event.getEvent(event);
			var hash = Anchor.prototype.getHash.call(this);
			
			if (hash) {
				var a = getAnchor.call(this, hash);
				var s = Element.getScrollPosition(this.ownerDocument);
				//
				var pos = Element.getPosition(a);
				
				// TODO: adjust behaviour with children in anchor tag 
				if (window.navigator.userAgent.toLowerCase().indexOf('webkit') >= 0) {
					var m = Element.getBorderMetrics(a, 'margin');
				}
				
				var tween = new Tween();
				
				tween.addEventListener(Tween.MOTION_START, motionStartDelegate);
				
				
				tween.easeFunction = Regular.easeInOut;
				tween.duration = this.getDuration ? this.getDuration() : 0.9;
				
				tween.begin = s.y;
				tween.finish = pos.y;

				stopTweens.call(anchor);
				tweens.push({element: anchor, tween: tween});
				
				// start tween
				tween.start();
				
				event.preventDefault();
			}
		});
		
		Element.addEventListener(anchor, 'click', clickDelegate, false);
	}

	return Anchor;
})();

