(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 Loader = Class.require("benignware.utils.Loader");
	
	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.getResourceUri(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.LOAD_MODE_NORMAL = "normal"
	ImageLoader.LOAD_MODE_IFRAME = "iframe"
	ImageLoader.LOAD_MODE_BASE64 = "base64"
	
	ImageLoader.prototype.__queue = null;
	ImageLoader.prototype.__defaultImage = null;
	ImageLoader.prototype.__isLoading = false;
	ImageLoader.prototype.__useIFrame = true;
	ImageLoader.prototype.__loadMode = ImageLoader.LOAD_MODE_NORMAL;
	ImageLoader.prototype.__cancelable = true;
	
	// delegates
	ImageLoader.prototype.__loadHandlerDelegate = null;
	ImageLoader.prototype.__errorHandlerDelegate = null;

	function initialize() {
		this.__queue = [];

		this.__defaultImage = Class.getResourceUri(ImageLoader, ImageLoader.DEFAULT_IMAGE);
		//
		this.__base64LoadHandlerDelegate = Delegate.create(this, base64LoadHandler);
		this.__base64ErrorHandlerDelegate = Delegate.create(this, base64ErrorHandler);
		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;
		}
		
		if (img.naturalWidth > 0) {
			return true;
		}
	    
	    if (img.complete) {
	    	return true;
	    }
	    
	    return false;

	}
	

	function next() {
		
		if (this.__queue.length) {
			var loadItem = this.__queue.shift();
			this.__currentElement = loadItem.element;
			var img = loadItem.image; 
			if (!isImageLoaded.call(this, img)) {
				if (!startLoad.call(this, img)) {
					next.call(this);
				}
			}
		} else {
			this.__isLoading = false;
			this.dispatchEvent(new Event(ImageLoader.COMPLETE));
		}
	}
	
	ImageLoader.getImages = function(elem) {
		return getImages(elem);
	}
	
	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(element) {
		if (!element) {
			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++) {
				var loadItem = this.__queue[q];
				if (img == loadItem.image) {
					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)) {
				var loadItem = {
					image: img,
					element: elem
				}
				this.__queue.push(loadItem);
			} else {
				// is already loaded
			}
		}
	}
	
	ImageLoader.prototype.load = function(elem) {
		this.add(elem);
		this.start();
	}
	
	ImageLoader.prototype.unshift = function(elem) {
		var l = this.__queue.length;
		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];
				var loadItem = {
					image: img, 
					element: elem
				}
				this.__queue.unshift(loadItem);
			}
		}
		if (l == 0 && this.__isLoading) {
			next.call(this);
		}
	}
	
	ImageLoader.prototype.start = function() {
		if (!this.__isLoading) {
			this.__isLoading = true;
			next.call(this);
		}
	}
	
	ImageLoader.prototype.setLoadMode = function(mode) {
		this.__loadMode = mode;
	}
	
	ImageLoader.prototype.getLoadMode = function() {
		return this.__loadMode;
	}
	
	function startLoad(img) {
		this.__canceled = false;
		var src = img.getAttribute("src");
		if (!src || src == this.__defaultImage) {
			src = img.__src ? img.__src : img.getAttribute("__src");	
		}
		var doc = img.ownerDocument;
		this.__currentImage = img;
		switch (this.getLoadMode()) {
			case ImageLoader.LOAD_MODE_IFRAME:
				if (!this.__iFrame) {
					this.__iFrame = doc.createElement('iframe');
					this.__iFrame.style.display = "none";
					this.__iFrame.onload = Delegate.create(this, iFrameLoadHandler);
					this.__iFrameImageLoadDelegate = Delegate.create(this, iFrameImageLoadHandler);
					this.__iFrameImageErrorDelegate = Delegate.create(this, iFrameImageErrorHandler);
					document.body.appendChild(this.__iFrame);
				}
				loadIFrameImage.call(this, src);
				break
				
			case ImageLoader.LOAD_MODE_BASE64:
				startBase64Load.call(this, img, src);
				break;
				
			default:
				loadImage.call(this, img, src);
		}
		
		this.dispatchEvent(new Event(ImageLoader.LOAD_START));
		return (src);
	}
	
	/* LOAD NORMAL */
	function loadImage(img, src) {
		Element.addEventListener(img, 'load', this.__loadHandlerDelegate, false);
		Element.addEventListener(img, 'error', this.__errorHandlerDelegate, false);
		img.setAttribute("src", src);
	}
	
	
	// normal image loading
	function loadHandler(event) {
		event = Event.getEvent(event);
		var img = event.target;
		Element.removeEventListener(img, 'load', this.__loadHandlerDelegate);
		Element.removeEventListener(img, 'error', this.__errorHandlerDelegate);
		var src = img.getAttribute('src');
		if (src != this.__defaultImage) {
			var imageEvent = new Event(ImageLoader.LOAD, false, false);
			imageEvent.image = img;
			var target = this;
			window.setTimeout(function() {
				target.dispatchEvent(imageEvent);
				next.call(target);
			}, 100);
		}	
	}
	
	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) {
			dispatchError.call(this);
			next.call(this);
		}
	}
	
	function dispatchError() {
		var errorEvent = new Event(ImageLoader.ERROR);
		this.dispatchEvent(errorEvent);
		next.call(this);
	}
	
	function cancelImage(img) {
		var src = img.getAttribute("src");
		if (src) {
			Element.removeEventListener(img, 'load', this.__loadHandlerDelegate);
			Element.removeEventListener(img, 'error', this.__errorHandlerDelegate);
			try {
				img.removeAttribute('src');
			} catch (e) {
			}
		}
	}
	
	/* LOAD IFRAME */
	
	function iFrameLoadHandler(event) {
		var doc = this.__iFrame.contentWindow.document;
		var img = doc.createElement("img");
		var body = this.__iFrame.contentWindow.document.body;
		body.appendChild(img);
		this.__iFrameImage = img;
		Element.addEventListener(this.__iFrameImage, "load", this.__iFrameImageLoadDelegate);
		Element.addEventListener(this.__iFrameImage, "error", this.__iFrameImageErrorDelegate);
		
		if (this.__iFrameSRC) {
			loadIFrameImage.call(this, this.__iFrameSRC);
		}
		this.__iFrameSRC = null;
		this.__iFrameCanceled = false;
	}
	
	function iFrameImageErrorHandler(event) {
		// iframe error
	}

	function loadIFrameImage(src) {
		if (this.__iFrameImage) {
			this.__iFrameImage.setAttribute("src", src);
				
		} else {
			this.__iFrameSRC = src;
		}
	}
	
	function cancelIFrameLoad() {
		if (this.__iFrame) {
			this.__iFrameCanceled = true;
			this.__iFrameSRC = null;
			if (this.__iFrameImage) {
				Element.removeEventListener(this.__iFrameImage, "load", this.__iFrameImageLoadDelegate);
				Element.removeEventListener(this.__iFrameImage, "error", this.__iFrameImageErrorDelegate);
			}
			this.__iFrame.setAttribute("src", "about:blank");
		}
	}
	
	function iFrameImageLoadHandler(event) {
		var src = this.__iFrameImage.getAttribute("src");
		loadImage.call(this, this.__currentImage, src);		
	}
	
	
	
	/* LOAD BASE64 */
	
	function startBase64Load(img, src) {
		if (!this.__canceled) {
			var loader = new Loader();
			this.__base64Loader = loader;
			loader.image = img;
			loader.addEventListener('load', this.__base64LoadHandlerDelegate);
			loader.addEventListener('error', this.__base64ErrorHandlerDelegate);
			loader.load(src);
		}
	}
	
	function initBase64Image(img, data) {
		loadImage.call(this, img, "data:" + data);
	}
	
	function base64LoadHandler(event) {
//		var target = this;
		var loader = event.target; 
		var src = event.url;
		var img = loader.image;

		if (!this.__canceled) {
			this.__canceled = false;
				initBase64Image.call(this, img, event.responseText);
		}
		
		loader.removeEventListener('load', this.__base64LoadHandlerDelegate);
		loader.removeEventListener('error', this.__base64ErrorHandlerDelegate);
		if (loader == this.__base64Loader) {
			this.__base64Loader = null;
		}
	}
	
	function cancelBase64Load() {
		if (this.__base64Loader) {
			this.__base64Loader.abort();
			this.__base64Loader.removeEventListener('load', this.__base64LoadHandlerDelegate);
			this.__base64Loader.removeEventListener('error', this.__base64ErrorHandlerDelegate);
		}
	}
	
	function base64ErrorHandler(event) {
		var loader = event.target;
		loader.removeEventListener('load', this.__base64LoadHandlerDelegate);
		loader.removeEventListener('error', this.__base64ErrorHandlerDelegate);
		if (loader == this.__base64Loader) {
			this.__base64Loader = null;
		}
		dispatchError.call(this);
	}
	
	
	ImageLoader.prototype.stop = function() {
		if (this.__cancelable) {
			switch (this.__loadMode) {
				case ImageLoader.LOAD_MODE_IFRAME:
					cancelIFrameLoad.call(this);
					break;
				case ImageLoader.LOAD_MODE_BASE64:
					cancelBase64Load.call(this);
					break;
				default:
					if (this.__currentImage) {
						cancelImage.call(this, this.__currentImage);
					}
			}
			for (var i = 0; i < this.__queue.length; i++) {
				this.__queue.splice(i--, 1);
			}
			this.__isLoading = false;
			
			this.__canceled = true;
		}
	}
	
	// alias to stop
	ImageLoader.prototype.cancel = ImageLoader.prototype.stop;
	
	
	ImageLoader.prototype.currentImage = function() {
		return this.__currentImage;
	}
	
	ImageLoader.prototype.currentElement = function() {
		return this.__currentElement;
	}
	
	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 Container = Class.require("benignware.core.Container");
	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.extend(Container, Slideshow);
	
	__super = Class.getSuper(Slideshow);
	
	
	// styles
	//CSS.setDefaultStyle(".benignware.slideshow", "position", "relative");
	
	var progressImage = Class.getResourceUri(Slideshow, "ajax-loader.gif");
	
	CSS.setDefaultStyle(".benignware.slideshow .progress", "background", "url(" + progressImage + ") center no-repeat");
	CSS.setDefaultStyle(".benignware.slideshow .progress", "width", "16px");
	CSS.setDefaultStyle(".benignware.slideshow .progress", "height", "16px");
	CSS.setDefaultStyle(".benignware.slideshow .progress", "position", "absolute");
	
	// 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.PRELOAD_ALL = "all";
	Slideshow.PRELOAD_NEXT = "next";
	Slideshow.PRELOAD_NONE = "none";
	
	// events
	Slideshow.POSITION_CHANGE = "positionChange";
	Slideshow.SLIDE = "slide";
	
	Slideshow.TRANSITION_ = "transition";
	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.__horizontalAlign = Slideshow.ALIGN_CENTER;
	Slideshow.prototype.__verticalAlign = 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 = 2;
	
	Slideshow.prototype.__interruptible = false;
	Slideshow.prototype.__queueSlides = true;
	Slideshow.prototype.__slideQueue = null;
	Slideshow.prototype.__slideQueueMaxSize = 1;
	
	Slideshow.prototype.__hideElements = true;
	
	Slideshow.prototype.__transitionInType = Fade;
	Slideshow.prototype.__transitionOutType = Fade;
	
	Slideshow.prototype.__transitionInDuration = 1.5;
	Slideshow.prototype.__transitionOutDuration = 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.__transitionIn = null;
	Slideshow.prototype.__transitionOut = null;
	
	Slideshow.prototype.__preloadMode = Slideshow.PRELOAD_NONE;
	Slideshow.prototype.__cancelLoadOnTransition = false;
	
	Slideshow.prototype.__waitForLoad = false;
	Slideshow.prototype.__loadingElement = null;
	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.__autoHideButtons = false;
	Slideshow.prototype.__snapButtonsToContent = false;
	
	Slideshow.prototype.__pausedOnMouseOver = false;
	
	Slideshow.prototype.__playOnInit = true;
	Slideshow.prototype.__playOnInitFlag = true;
	
	Slideshow.prototype.__transitionOnInit = true;
	Slideshow.prototype.__transitionOnInitFlag = false;
	
	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);
		//
		// init
		var dataset = this.getDataset();
		var autoLayout = dataset.get('autoLayout');
		if (typeof(autoLayout)) {
			this.setAutoLayout(autoLayout);
		}
		var verticalAlign = dataset.get('verticalAlign');
		if (typeof(verticalAlign)) {
			this.setVerticalAlign(verticalAlign);
		}
		//
		this.addCSSName("slideshow");
		this.__slideQueue = [];
		this.__imageLoader = new ImageLoader();
		//
		this.__imageLoadDelegate = Delegate.create(this, imageLoadHandler);
		this.__imageLoader.addEventListener(ImageLoader.LOAD, this.__imageLoadDelegate);
		//
		this.__imageErrorDelegate = Delegate.create(this, imageErrorHandler);
		this.__imageLoader.addEventListener(ImageLoader.ERROR, this.__imageErrorDelegate);
		//
		this.__imageCompleteDelegate = Delegate.create(this, imageCompleteHandler);
		this.__imageLoader.addEventListener(ImageLoader.COMPLETE, this.__imageCompleteDelegate);
		//
		
		window.setTimeout(Delegate.create(this, function(event) {
			if (this.__playOnInit) {
				this.__playOnInitFlag = true;
				if (this.__autoPlay) {
					this.start();
				} else {
					this.setPosition(0);
				}
			}
		}), 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 scrollHandler(event) {
		this.resizeComponent();
	}
	
	function imageLoadHandler(event) {
		if (this.__waitingForLoadElement) {
			var loaded = this.__imageLoader.isLoaded(this.__waitingForLoadElement);
			if (loaded) {
				var element = this.__waitingForLoadElement;
				this.__waitingForLoadElement = null;
				if (element == this.__currentElement) {
					if (this.__waitForLoad) {
						initTransitions.call(this);
					} else {
						initTransitionIn.call(this);
					}
				} else {
					this.next();
				}
			}
		} else {
			//console.log("IMAGE LOAD EVENT, NOT WAITING FOR LOAD, DO NOTHING ");
		}
	}
	
	function imageErrorHandler() {
		this.next();
	}
	
	function initTransitions() {
		initTransitionIn.call(this);
		if (this.__lastElement && this.__lastElement.display != "none") {					
			initTransitionOut.call(this);
		}
	}
	
	function imageCompleteHandler(event) {
		hideElement(this.progressImage);
	}
	
	function initTimerHandler() {
		if (this.size() && !this.isPlaying()) {
			// start
			this.start();
		}
	}
	
	function clearAutoPlayTimer() {
		if (this.__timerRef) {
			window.clearTimeout(this.__timerRef);
		}
	}
	
	function initAutoPlayTimer() {
		
		// init auto play timer:
		if (this.getAutoPlay()) {
			clearAutoPlayTimer.call(this);
			if (this.isPlaying() && this.getAutoPlay()) {
				this.__timerRef = window.setTimeout(this.__autoPlayTimerDelegate, this.__duration * 1000);
			}
		}
	}
	
	
	function autoPlayTimerHandler() {
		if (this.getAutoPlay()) {
			var nextElement = this.get(this.getNextPosition());
			if (nextElement) {
				var loaded = this.__imageLoader.isLoaded(nextElement);
				if (loaded) {
					this.next();
				} else {
					this.__waitingForLoadElement = nextElement;
				}
			}
		}
	}
	
	function showElement(elem) {
		elem.style.display = "";
	}
	
	function hideElement(elem) {
		elem.style.display = "none";
	}
	
	function isShowing(elem) {
		var display = Element.getComputedStyle(elem, 'display');
		return display != 'none';
	}

	// START TRANSITION IN
	function startTransitionIn() {
		var type = direction == Slideshow.REVERSE ? this.__transitionOutType : this.__transitionInType;
		var hasTransition = (type);
		var finishImmediately = !this.getTransitionOnInit() && !this.__transitionOnInitFlag;
		this.__transitionOnInitFlag = true;
		//
		var direction = this.__tempInDirection ? this.__tempInDirection : this.__direction;
		this.__tempInDirection = undefined;
		window.clearTimeout(this.__delayTimerRef);
		this.__delayTimerRef = null;
		
		var element = this.__currentElement;
		
		if (this.getHideElements()) {
			showElement(element);
		}
		
		if (this.getAutoLayout()) {
			moveToFront.call(this, element);
			this.resizeComponent();
		}
		
		if (hasTransition) {
			// transition data
			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);

			// params
			var params = direction == Slideshow.REVERSE ? this.__transitionOutParams : this.__transitionInParams;
			if (params) {
				for (var x in params) {
					Class.callSetter(transitionIn, x, params[x]);
				}
			}
			if (finishImmediately) {
//				transitionIn.fforward();
			} else {
				transitionIn.start();
			}
			this.__transitionIn = transitionIn;
		}

		// dispatch transition start event
		
		this.dispatchEvent(this.createEvent(Slideshow.TRANSITION_IN_START));
		
		if (!hasTransition || finishImmediately) {
			transitionInFinished.call(this);
		}
		
	}
	
	function transitionInFinishHandler(event) {
		transitionInFinished.call(this);
	}
	
	function transitionOutFinishHandler(event) {
		transitionOutFinished.call(this);
	}
	
	function transitionInFinished() {
		initAutoPlayTimer.call(this);
		
		this.__transitionInPlaying = false;
		this.dispatchEvent(this.createEvent(Slideshow.TRANSITION_IN_FINISH));
		//
//		if (!this.__transitionOutPlaying) {
			transitionComplete.call(this);
//		}

		
		
		var nextElement = this.get(this.getNextPosition());
		if (this.__imageLoader.isLoaded(this.__currentElement) && !this.__imageLoader.isLoaded(nextElement)) {
			this.__imageLoader.unshift(nextElement);
			this.__imageLoader.start();
		}
	}
	
	function transitionComplete() {
		
		this.dispatchEvent(this.createEvent(Slideshow.TRANSITION_COMPLETE));
		if (this.__slideQueue.length) {
			doSlide.call(this);
		} else {
			if (this.__preloadMode == Slideshow.PRELOAD_NEXT || this.__preloadMode == Slideshow.PRELOAD_ALL) {
				
				var startLoad = false;

//				var prevElement = this.getItemAt(this.getPreviousPosition());
//				if (!this.__imageLoader.isLoaded(prevElement)) {
//					startLoad = true;
//					this.__imageLoader.unshift(prevElement);
//				}
				
				
				
			} else {
				// preload none
			}
		}
	}
	
	function transitionOutFinished() {
//		var transition = event.target;
//		var element = transition.getElement();
//		if (this.getHideElements()) {
//			hideElement(element);
//		}
		removeTransitionOut.call(this, this.__transitionOut);
		
		if (this.__lastElement) {
			if (this.getHideElements()) {
				hideElement(this.__lastElement);
			}
		}
		
		this.dispatchEvent(this.createEvent(Slideshow.TRANSITION_OUT_FINISH));
		this.__transitionOutPlaying = false;
		
		if (!this.__imageLoader.isLoaded(this.__currentElement)) {
			
			if (this.__waitingForLoadElement == this.__currentElement && this.__loadingElement != this.__currentElement) {
				this.__waitingForLoadElement = this.__currentElement;
				this.__loadingElement = this.__currentElement;
				this.__imageLoader.unshift(this.__currentElement);
				this.__imageLoader.start();
				if (!this.getWaitForLoad() && this.getShowProgressImage()) {
					showElement(this.progressImage);
				}
			}
			layoutProgressImage.call(this);
			this.resizeComponent();
		} else {
			
		}
		
		this.dispatchEvent(this.createEvent(Slideshow.TRANSITION_END));

	}
	
	
	// remove transitions
	function removeTransitionOut(transition) {
		if (this.__transitionOut) {
			this.__transitionOut.stop();
			this.__transitionOut.setElement(null);
			this.__transitionOut.removeEventListener(Tween.MOTION_FINISH, this.__transitionOutFinishedDelegate, false);
		}
	}
	
	function removeTransitionIn(transition) {
		if (this.__transitionIn) {
			this.__transitionIn.stop();
			this.__transitionIn.setElement(null);
			this.__transitionIn.removeEventListener(Tween.MOTION_FINISH, this.__transitionInFinishedDelegate, false);
		}
	}
	
	Slideshow.prototype.add = function(elem, index) {
		__super.add.call(this, elem, index);
		if (this.getHideElements()) {
			hideElement(elem);
		}
	}
	
	Slideshow.prototype.currentElement = function() {
		return this.__currentElement;
	}
	
	
	
	function doSlide() { 
		var slide = this.__slideQueue.shift();
		if (!slide) {
			return;
		}
		clearAutoPlayTimer.call(this);
		//
		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.get(index);
		
		if (element != this.__currentElement) {
			
			this.__lastElement = this.__currentElement;
			
			this.__currentElement = element;
			this.__currentIndex = index;
			
			if (this.__delayTimerRef) {
				window.clearTimeout(this.__delayTimerRef);
				this.__delayTimerRef = null;
			}

			if (typeof(direction) != undefined) {
				this.__tempOutDirection = direction;
				this.__tempInDirection = direction;
			}

			if (!this.isTransitionPlaying()) {	

				if (!this.__imageLoader.isLoaded(element)) {
						
						var loadFlag = true;
						
						if (this.__lastElement && this.__lastElement.display != "none" && !this.__waitForLoad) {					
							loadFlag = false;
							initTransitionOut.call(this);
						}
						
						if (this.__waitingForLoadElement != element) {
							this.__waitingForLoadElement = element;
							
							if (loadFlag) {
								
								this.__loadingElement = element;
								this.__imageLoader.unshift(element);
								this.__imageLoader.start();

								if ((!this.__waitForLoad || !this.__lastElement) && this.__showProgressImage) {
									showElement(this.progressImage);
									this.resizeComponent();
								}
								
							}
						}
						
					
					
				} else {
					// start transition in
					
//					initTransitionIn.call(this);
//					if (this.__waitForLoad) {
//						initTransitionOut.call(this);
//					}
					
					
//					
//					if (this.__waitingForLoadElement && this.__waitingForLoadElement == this.__currentElement) {
//						//console.log("is waiting for current element");
//						return;
//					}
					initTransitions.call(this);
				}
			}
		}
		this.dispatchEvent(this.createEvent(Slideshow.SLIDE));
	}

	function initTransitionIn() {
		if (this.__imageLoader.isLoaded(this.__currentElement)) {
			hideElement(this.progressImage);
			if (this.__transitionInPlaying) return;
			this.__transitionInPlaying = true;
			var delay = this.__lastElement ? this.__transitionInDelay * 1000 : 0;
			if (delay) {
				this.__delayTimerRefIn = window.setTimeout(this.__startTransitionInDelegate, delay);
			} else {
				startTransitionIn.call(this);
			}
			this.resizeComponent();
		}
	}
	
	function initTransitionOut() {
		if (this.__cancelLoadOnTransition && !this.__imageLoader.isLoaded(this.__currentElement)) {
			this.__imageLoader.stop();
		}
		this.dispatchEvent(this.createEvent(Slideshow.TRANSITION_START));
		if (!this.__lastElement) {
			transitionOutFinished.call(this);
			return;
		} 
		
		if (this.__transitionOutPlaying) return;
		this.__transitionOutPlaying = true;
		var delay = this.__transitionOutDelay * 1000;
		if (delay) {
			this.__delayTimerRefOut = window.setTimeout(this.__startTransitionOutDelegate, delay);
		} else {
			startTransitionOut.call(this);
		}
	}
	
	function startTransitionOut() {
		
		this.resizeComponent();
		
		var direction = this.__tempOutDirection ? this.__tempOutDirection : this.__direction;
//		console.log("START TRANSITION OUT: last element: ", this.__lastElement, direction);

		this.__tempOutDirection = undefined;

//		if (!this.__delayTimerRef) {
			
			if (!this.__transitionInPlaying) {
				if (this.getHideElements()) {
					hideElement(this.__lastElement);
				}
			}
			
			element = this.__lastElement;

			showElement(element);
			var type = direction == Slideshow.REVERSE ? this.__transitionInType : this.__transitionOutType;
			
			var hasTransition = (type);
			
			
			if (hasTransition) {

				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.__transitionOutPlaying = true;
				
				this.__transitionOut = transitionOut;
				// params
				var params = direction == Slideshow.REVERSE ? this.__transitionInParams : this.__transitionOutParams;
				if (params) {
					for (var x in params) {
						Class.callSetter(transitionOut, x, params[x]);
					}
				}
				transitionOut.start();
			}
			//
			this.dispatchEvent(this.createEvent(Slideshow.TRANSITION_OUT_START));
			if (!hasTransition) {
				transitionOutFinished.call(this);
			}
//		}
	}
	
	
	
	Slideshow.prototype.start = function() {
		this.stop();
		this.__isPlaying = true;
		this.setPosition(0);
	}
	
	Slideshow.prototype.stop = function() {
		this.__isPlaying = false;
		//
		clearAutoPlayTimer.call(this);
	}
	
	Slideshow.prototype.destroy = function() {
		__super.destroy();
		//
		
		this.__imageLoader.removeEventListener(ImageLoader.LOAD, this.__imageLoadDelegate);
		this.__imageLoader.removeEventListener(ImageLoader.COMPLETE, this.__imageCompleteDelegate);

		//
		this.__imageLoader = null;
		
		window.clearTimeout(this.__delayTimerRefIn);
		window.clearTimeout(this.__delayTimerRefOut);
		
		removeTransitionOut.call(this);
		removeTransitionIn.call(this);
		
		
		this.__transitionIn = null;
		this.__transitionOut = null;
	}
	
	Slideshow.prototype.pause = function() {
		if (this.__isPlaying) {
			this.__isPlaying = false;
			clearAutoPlayTimer.call(this);
		}
	}
	
	Slideshow.prototype.play = function() {
		if (!this.__isPlaying) {
			clearMouseOverTimer.call(this);
			this.__isPlaying = true;
			if (this.isShowing(this.__currentElement)) {
				initAutoPlayTimer.call(this);
			}
		}
		if (this.getPosition() == -1) {
			this.setPosition(0);
		}
	}
	
	Slideshow.prototype.togglePlay = function() {
		if (!this.__isPlaying) {
			this.play();
		} else {
			this.pause();
		}
	}
	
	Slideshow.prototype.isLoading = function() {
		return this.__imageLoader.isLoading();
	}

	Slideshow.prototype.next = function() {
		this.setPosition(this.getNextPosition());
	}
	
	Slideshow.prototype.previous = function() {
		var pos = this.getPreviousPosition();
		this.setPosition(pos, this.getDirection() * -1);
	}
	
	Slideshow.prototype.setPosition = function(pos, direction) {
		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;
	}
	
	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;
	}
	
	// getter/setters
	
	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;
			if (transitionType) {
				transitionType = Class.getClass(transitionType);
			}
		}
		this.__transitionInType = transitionType;
	}
	
	Slideshow.prototype.getTransitionInType = function() {
		return this.__transitionInType;
	}
	
	Slideshow.prototype.setTransitionOutType = function(transitionType) {
		if (typeof(transitionType) == "string") {
			transitionType = transitionType == "none" ? null : transitionType;
			if (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.getTransitionOutType = function() {
		return this.__transitionOutType;
	}
	
	Slideshow.prototype.isPlaying = function() {
		return this.__isPlaying;
	}
	
	function isElementShowing(elem) {
		return (elem.style.display != "none");
	}
	
	Slideshow.prototype.isShowing = function() {
		return (!this.isTransitionOutPlaying() && this.__currentElement && isElementShowing(this.__currentElement));
	}
	
	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.setPreloadMode = function(mode) {
		this.__preloadMode = mode;
	}
	
	Slideshow.prototype.getPreloadMode = function() {
		return this.__preloadMode;
	}
	
	Slideshow.prototype.setLoadMode = function(mode) {
		this.__imageLoader.setLoadMode(mode);
	}
	
	Slideshow.prototype.getLoadMode = function() {
		return this.__imageLoader.getLoadMode();
	}
	
	Slideshow.prototype.setCancelLoadOnTransition = function(bool) {
		this.__cancelLoadOnTransition = StringUtils.getBoolean(bool);
	}
	
	Slideshow.prototype.getCancelLoadOnTransition = function() {
		return this.__cancelLoadOnTransition;
	}
	
	Slideshow.prototype.setDuration = function(duration) {
		this.__duration = duration;
	}
	
	Slideshow.prototype.getDuration = function(duration) {
		return this.__duration;
	}
	
	Slideshow.prototype.setPlayOnInit = function(bool) {
		this.__playOnInit = StringUtils.getBoolean(bool);
	}
	
	Slideshow.prototype.getPlayOnInit = function() {
		return this.__playOnInit;
	}
	
	Slideshow.prototype.setHideElements = function(bool) {
		bool = StringUtils.getBoolean(bool);
		if (!bool) {
			for (var i = 0; i < this.size(); i++) {
				var item = this.get(i);
				item.style.display = "";
			}
		}
		this.__hideElements = bool;
	}
	
	Slideshow.prototype.getHideElements = function() {
		return this.__hideElements;
	}
	
	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);
		if (this.__transitionIn) {
			this.__transitionIn.duration = duration;
		}
	}
	
	Slideshow.prototype.getTransitionInDuration = function() {
		return this.__transitionInDuration;
	}
	
	Slideshow.prototype.setTransitionOutDuration = function(duration) {
		this.__transitionOutDuration = parseFloat(duration);
		if (this.__transitionOut) {
			this.__transitionOut.duration = duration;
		}
	}
	
	Slideshow.prototype.getTransitionOutDuration = function() {
		return this.__transitionOutDuration;
	}
	
	Slideshow.prototype.setTransitionParams = function(params) {
		this.setTransitionInParams(params);
		this.setTransitionOutParams(params);
	}
	
	Slideshow.prototype.setTransitionInParams = function(params) {
		this.__transitionInParams = typeof(params) == "string" ? StringUtils.jsonDecode(params) : params;
	}
	
	Slideshow.prototype.getTransitionInParams = function(params) {
		return this.__transitionInParams;
	}
	
	Slideshow.prototype.setTransitionOutParams = function(params) {
		this.__transitionOutParams = typeof(params) == "string" ? StringUtils.jsonDecode(params) : params;
	}
	
	Slideshow.prototype.getTransitionOutParams = function(params) {
		return this.__transitionOutParams;
	}
	
	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 = StringUtils.getBoolean(bool);
	}
	
	Slideshow.prototype.getAutoLayout = function() {
		return this.__autoLayout;
	}
	
	Slideshow.prototype.setHorizontalAlign = function(bool) {
		this.__horizontalAlign = bool;
	}
	
	Slideshow.prototype.getHorizontalAlign = function() {
		return this.__horizontalAlign;
	}
	
	Slideshow.prototype.setVerticalAlign = function(str) {
		this.__verticalAlign = str;
	}
	
	Slideshow.prototype.getVerticalAlign = function() {
		return this.__verticalAlign;
	}
	
	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;
	}
	
	Slideshow.prototype.setWaitForLoad = function(bool) {
		this.__waitForLoad = StringUtils.getBoolean(bool);
	}
	
	Slideshow.prototype.getWaitForLoad = function() {
		return this.__waitForLoad;
	}
	
	
	/*
	 * LAYOUT
	 */
	
	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.size(); i++) {
				var item = this.get(i);
				scaleElement.call(this, item);
			}
			for (var i = 0; i < this.size(); i++) {
				var item = this.get(i);
				layoutElement.call(this, item);
			}
			
			if (this.__transitionIn) {
				this.__transitionIn.updateTarget();
			}
			if (this.__transitionOut) {
				this.__transitionOut.updateTarget();
			}
			
			if (this.__transitionIn) {
				this.__transitionIn.update();
			}
			if (this.__transitionOut) {
				this.__transitionOut.update();
			}
			
			layoutButtons.call(this);
			layoutProgressImage.call(this);
		}
	}

	function scaleElement(element) {
		if (!isShowing(element)) return 
		var element = DOM.getDeepestElement(element);
		if (element.tagName.toLowerCase() == "img") {
			var b = this.getBorderMetrics('border');
			var maxWidth = this.offsetWidth;
			var maxHeight = this.offsetHeight;
			if (maxWidth && maxHeight) {
				Image.scale(element, maxWidth, maxHeight, this.getScaleMode(), this.getScaleBounds());
			}
		}
	}
	
	function layoutElement(element) {
		
		if (!isShowing(element)) return 
		
		element.style.position = "absolute";
		
		var w = this.offsetWidth;
		var h = this.offsetHeight;
		
		var op = this.offsetParent;

		var px = op ? op.offsetLeft : 0;
		var py = op ? op.offsetTop : 0;
	
		
		var b = this.getBorderMetrics('border');
		var m = this.getBorderMetrics('margin');
		//
		var x = m.left;
		var y = m.top;
		//
		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 + Math.floor((w - ew) * a) - b.left;
		var ey = y + Math.floor((h - eh) * vA) - b.top;

		element.style.left = ex + "px";
		element.style.top = ey + "px";
	}
	
	
	
	function moveToFront(elem) {
//		elem.parentNode.appendChild(elem);
		var parent = elem.parentNode; 
		if (parent) {
			for (var i = 0; i < parent.childNodes.length; i++) {
				var child = parent.childNodes[i];
				if (child.style) {
					child.style.zIndex = child == elem ? 1 : 0
				}
			}
		}
	}
	
	
	
	
	
	
	
	/*
	 * ADDITIONAL FUNCTIONALITY
	 */
	
	/* 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.setAutoHideButtons = function(bool) {
		bool = StringUtils.getBoolean(bool);
		if (this.__autoHideButtons != bool) {
			this.__autoHideButtons = 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.POSITION_CHANGE, this.__hideButtonsDelegate, false);
			} else {
				this.removeEventListener(Slideshow.TRANSITION_COMPLETE, this.__showButtonsDelegate, false);
				this.removeEventListener(Slideshow.POSITION_CHANGE, this.__hideButtonsDelegate, false);
			}
			
			if (this.currentElement() && !this.isTransitionPlaying() && !this.isShowing()) {
				showButtons.call(this);
			} else {
				hideButtons.call(this);
			}
		}
	}
	
	Slideshow.prototype.getAutoHideButtons = function() {
		return this.__autoHideButtons;
	}
	
	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() {
		if (this.__snapButtonsToContent) {
			var element = this.currentElement();
			if (element) {
				var spos = Element.getPosition(element.offsetParent);
				if (this.__nextButton) {
					var npos = Element.getPosition(element, this.__nextButton.offsetParent);
					if (npos) {
						var m = Element.getBorderMetrics(this.__nextButton, 'margin');
						var ny = npos.y + element.offsetTop + (element.offsetHeight - this.__nextButton.offsetHeight - m.top - m.bottom) / 2 - element.offsetTop;
						var nx = npos.x + element.offsetWidth - this.__nextButton.offsetWidth - m.right - m.left;
						this.__nextButton.style.position = "absolute";
						this.__nextButton.style.left = nx + "px";
						this.__nextButton.style.top = ny + "px";
					}
				}
				if (this.__prevButton) {
					var ppos = Element.getPosition(element, this.__prevButton.offsetParent);
					var m = Element.getBorderMetrics(this.__prevButton, 'margin');
					var py = ppos.y + element.offsetTop + (element.offsetHeight - this.__prevButton.offsetHeight - m.top - m.bottom) / 2 - element.offsetTop
					var px = ppos.x;
					if (npos) {
						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.__mouseOverDelegate == null) {
				this.__mouseOverDelegate = Delegate.create(this, mouseOverHandler);
			}
			if (bool) {
				Element.addEventListener(Element.getDefaultView(this), 'blur', this.__mouseOverDelegate, false);
				Element.addEventListener(this.ownerDocument, 'mousemove', this.__mouseOverDelegate, false);
				Element.addEventListener(this.ownerDocument, 'mousedown', this.__mouseOverDelegate, false);
			} else {
				Element.removeEventListener(Element.getDefaultView(this), 'blur', this.__mouseOverDelegate, false);
				Element.removeEventListener(this.ownerDocument, 'mousemove', this.__mouseOverDelegate, false);
				Element.removeEventListener(this.ownerDocument, 'mousedown', this.__mouseOverDelegate, false);
			}
		}
	}
	
	
	Slideshow.prototype.setMouseOverDuration = function(sec) {
		this.__mouseOverDuration = parseFloat(sec);
	}
	
	Slideshow.prototype.getMouseOverDuration = function() {
		return this.__mouseOverDuration;
	}
	
	function clearMouseOverTimer() {
		if (this.__mouseOverTimerRef != null) {
			window.clearTimeout(this.__mouseOverTimerRef);
			this.__mouseOverTimerRef = null;
		}
	}
	
	function pausedTimerHandler() {
		this.play();
	}
	
	function initMouseOverTimer() {
		clearMouseOverTimer.call(this);
		clearAutoPlayTimer.call(this);
		if (this.__mouseOverDuration > 0) {
			if (!this.__playDelegate) {
				this.__playDelegate = Delegate.create(this, pausedTimerHandler);
			}
			this.__mouseOverTimerRef = window.setTimeout(this.__playDelegate, this.__mouseOverDuration * 1000);
		}
	}
	
	function mouseOverHandler(event) {
		
		event = Event.getEvent(event);
		if (event.target == this || DOM.isChildOf(event.target, this)
			|| (this.__nextButton && (event.target == this.__nextButton || DOM.isChildOf(event.target, this.__nextButton)))
			|| (this.__prevButton && (event.target == this.__prevButton || DOM.isChildOf(event.target, this.__prevButton)))) {
			if (this.isPlaying()) {
				this.pause();
			}
			initMouseOverTimer.call(this);
		} else {
//			if (!this.isPlaying()) {
//				this.play();
//			}
		}
	}
	
	function mouseMoveHandler(event) {
		
	}
	

	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();
	}
	
	
//	function mouseMoveHandler(event) {
//		if (scrollEnabled && isMouseOverComponent()) {
//			scrollSpeed = - Math.cos(( mouseX / width) * Math.PI) * scrollMaxSpeed;
//		} else if (scrollSpeed != 0) {
//			scrollSpeed*= 1 - scrollFriction;
//			if (Math.abs(scrollSpeed) <= scrollFriction * 2) {
//				scrollSpeed = 0;
//				scrollFadeOut();
//			}
//		}
//		setScrollPosition(scrollX + scrollSpeed, 0);
//	}
	
	
	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;
})();
(function(){
	// import classes
	var Class = benignware.core.Class;
	var Component = Class.require("benignware.core.Component");
	var Container = Class.require("benignware.core.Container");
	var Delegate = Class.require("benignware.utils.Delegate");
	var CSS = Class.require("benignware.utils.CSS");
	var Element = Class.require("benignware.core.Element");
	var StringUtils = Class.require("benignware.utils.StringUtils");
	
	// define super
	var __super;

	function ScrollContainer() {
		__super.call(this);
	}
	
	Class.registerClass("benignware.view.ScrollContainer", ScrollContainer);

	ScrollContainer = Class.extend(Container, ScrollContainer);
	__super = Class.getSuper(ScrollContainer);

	// variables
	ScrollContainer.prototype.__mouseOverFlag = false;
	ScrollContainer.prototype.__mouseX = 0;
	ScrollContainer.prototype.__mouseY = 0;
	
	ScrollContainer.prototype.__scrollX = 0;
	ScrollContainer.prototype.__scrollY = 0;
	ScrollContainer.prototype.__scrollMaxSpeed = 18;
	
	ScrollContainer.prototype.__vector = {x:0, y:0}
	
	ScrollContainer.prototype.__currentVector = {x:0, y:0}
	
	ScrollContainer.prototype.__frameRate = 20;
	ScrollContainer.prototype.__activeMargin = 0.25;
	
	ScrollContainer.prototype.__clones = null;
	ScrollContainer.prototype.__contentHTML = "";
	
	ScrollContainer.prototype.initialize = function() {
		__super.initialize.call(this);
		this.__clones = [];
		this.style.overflow = "hidden";
		this.style.position = "relative";
		this.content.style.position = "absolute";
		this.addEventListener("mousedown", Delegate.create(this, mouseDownHandler), false);
		Element.addEventListener(this.ownerDocument, "mouseup", Delegate.create(this, mouseUpHandler), false);
		this.addEventListener("mousemove", Delegate.create(this, mouseMoveHandler), false);
		this.addEventListener("mouseover", Delegate.create(this, mouseEnterHandler), false);
		this.addEventListener("mouseenter", Delegate.create(this, mouseEnterHandler), false);
		this.addEventListener("mouseleave", Delegate.create(this, mouseLeaveHandler), false);
		start.call(this);
	}
	
	ScrollContainer.prototype.createChildren = function() {
		__super.createChildren.call(this);
	}
	
	ScrollContainer.prototype.setFrameRate = function(frameRate) {
		if (this.__frameRate = frameRate) {
			this.__frameRate = frameRate;
			start.call(this);
		}
	}
	
	ScrollContainer.prototype.getFrameRate = function() {
		return this.__frameRate;
	}
	
	function start() {
		clearInterval(this.__inverval);
		var target = this;
		this.__inverval = setInterval(function() {
			enterFrameHandler.call(target, {target: target})
		}, 1 / this.getFrameRate() * 1000);
	}
	
	function mouseDownHandler(event) {
		this.__vector = {x: 0, y: 0}
		this.__currentVector = {x: 0, y: 0}
		this.__mouseDownFlag = true;
		event.preventDefault();
	}
	
	function mouseUpHandler(event) {
		this.__mouseDownFlag = false;
		if (this.__isDragging) {
			this.__isDragging = false;
			this.__mouseOverFlag = false;
		}
	}
	
	function mouseEnterHandler(event) {
		this.__mouseOverFlag = true;
	}
	
	function mouseLeaveHandler(event) {
		this.__mouseOverFlag = false;
	}
	
	function isMouseOver() {
		if (this.__mouseOverFlag) {
			var mg = this.__activeMargin;
			if (mg) {
				var w = this.offsetWidth;
				var h = this.offsetHeight;
				var mgx = mg < 1 ? w * mg : mg < w / 2 ? mg : w / 2;
				var mgy = mg < 1 ? h * mg : mg < h / 2 ? mg : h / 2;
				return (this.__mouseX < mgx 
					|| this.__mouseX > this.offsetWidth - mgx 
					|| this.__mouseY < mgy 
					|| this.__mouseY > this.offsetHeight - mgy)
			}
			return true
		}
		return false;
	}
	
//	function draggingHandler(event) {
//		
//	}
	
	function mouseMoveHandler(event) {
		var maxsp = this.__scrollMaxSpeed;
		
		var pos = Element.getPosition(this);
		var mx = event.clientX - pos.x;
		var my = event.clientY - pos.y;
		
		//
		
		var w = this.offsetWidth;
		var h = this.offsetHeight;
		//
		if (this.__mouseDownFlag) {
			// dragging
			this.__isDragging = true;
			var vx = mx - this.__mouseX;
			var vy = my - this.__mouseY;
			this.__vector.x = vx * this.__scrollMaxSpeed;
			this.__vector.y = vy * this.__scrollMaxSpeed;
		} else {
			
		}
		
		this.__mouseX = mx;
		this.__mouseY = my;
		
//		console.log("vector: ", event, this.__vector, this.__vector);
		
		if (!this.__mouseDownFlag) {
			// not dragging
			var mg = this.__activeMargin;
			var v = this.__vector;
			if (mg) {
				var mgx = mg < 1 ? w * mg : mg < w / 2 ? mg : w / 2;
				var mgy = mg < 1 ? h * mg : mg < h / 2 ? mg : h / 2;
				if (this.__mouseX < mgx) {
					v.x = - (1 - this.__mouseX / mgx) * maxsp;
				} else if (this.__mouseX > w - mgx) {
					v.x = (1 - (w - this.__mouseX) / mgx) * maxsp;
				} else {
					v.x = 0;
				}
				if (this.__mouseY < mgy) {
					v.y = - (1 - this.__mouseY / mgy) * maxsp;
				} else if (this.__mouseY > h - mgy) {
					v.y = (1 - (h - this.__mouseY) / mgy) * maxsp;
				} else {
					v.y = 0;
				}
			} else {
				v.x = - Math.cos(( this.__mouseX / w) * Math.PI) * maxsp;
				v.y = - Math.cos(( this.__mouseY / h) * Math.PI) * maxsp;	
			}
			
		}
		this.resizeComponent();
	}
	
	function enterFrameHandler(event) {
	
		var scrollPos = this.getScrollPosition();
		var scrollFriction = 0.1;
		var scrollAcceleration = this.__isDragging ? 2 : 0.8;

		var cv = this.__currentVector;
		var v = this.__vector;
		if (this.__isDragging || isMouseOver.call(this)) {
			// scroll
			if (cv.x != v.x) {
				var xacc = cv.x > v.x ? scrollAcceleration * -1 : scrollAcceleration;
				cv.x+= xacc;
				if (xacc > 0 && cv.x > v.x || xacc < 0 && cv.x < v.x) {
					cv.x = v.x;
				}
			}
			
			if (cv.y != v.y) {
				var yacc = cv.y > v.y ? scrollAcceleration * -1 : scrollAcceleration;
				cv.y+= yacc;
				if (yacc > 0 && cv.y > v.y || yacc < 0 && cv.y < v.y) {
					cv.y = v.y;
				}
			}
			
		} else {
			// slow down
			if (cv.x != 0) {
				cv.x*= 1 - scrollFriction;
				if (Math.abs(cv.x) <= scrollFriction * 2) {
					cv.x = 0;
				}
			}
			if (cv.y != 0) {
				cv.y*= 1 - scrollFriction;
				if (Math.abs(cv.y) <= scrollFriction * 2) {
					cv.y = 0;
				}
			}
		}
		var maxsp = this.__scrollMaxSpeed;
		cv.x = cv.x > maxsp ? maxsp : cv.x < -maxsp ? -maxsp : cv.x;
		cv.y = cv.y > maxsp ? maxsp : cv.y < -maxsp ? -maxsp : cv.y;
		this.__currentVector = {x: cv.x, y: cv.y}
		this.setScrollPosition(scrollPos.x + cv.x, scrollPos.y + cv.y);
	}
	
	
	
	ScrollContainer.prototype.setScrollPosition = function(x, y) {
		var endlessScrolling = true;
		var w = this.offsetWidth, h = this.offsetHeight;
		var cw = this.content.offsetWidth, ch = this.content.offsetHeight;
		x = cw < w ? 0 : x;
		y = ch < h ? 0 : y;
		
		if (endlessScrolling) {
			x = cw > 0 ? x % cw : 0;
			y = ch > 0 ? y % ch : 0;
		} else {
			if (x > cw - w) {
				x = cw - w;
			} else if (x < 0) {
				x = 0;
			}
			if (y > ch - h) {
				y = ch - h;
			} else if (y < 0) {
				y = 0;
			}
		}
		this.__scrollX = x;
		this.__scrollY = y;
		this.layout();
	}
	
	ScrollContainer.prototype.getScrollPosition = function() {
		return {x: this.__scrollX, y: this.__scrollY}
	}
	// layout
	ScrollContainer.prototype.resizeComponent = function() {
		this.layout();
	}
	
	ScrollContainer.prototype.layout = function() {
		__super.layout.call(this);
		
		var s = this.getScrollPosition();
		var w = this.offsetWidth;
		var h = this.offsetHeight;
		var cw = this.content.offsetWidth;
		var ch = this.content.offsetHeight;
		setupClones.call(this);
		var sx = s.x < 0 ? -s.x - cw : -s.x;
		var sy = s.y < 0 ? -s.y - ch : -s.y;
		var cols = 2;
		var cl = 0;
		var cnt = false;
		for (var i = 0; i < this.__clones.length + 1; i++) {
			var elem = null;
			var cx = (i % cols) * cw;
			var cy = Math.floor(i / cols) * ch;
			var x = (sx + cx);
			var y = (sy + cy);		
	//		console.log("MOUSE OVER: ", i, this.__mouseX, ", " + this.__mouseX + ", " + (s.x - x) + ", " + (s.x - x + cw));
	//		var isOver = this.__mouseX >= -s.x + x && this.__mouseX < -s.x + x + cw && this.__mouseY >= -s.y + y && this.__mouseY < -s.y + y + ch
	//		console.log("IS OVER: ", i, this.__mouseX - sx, x, " >>>>>>>>>>", this.__mouseX - sx >= x && this.__mouseX - sx < x + cw);
	//		if (!cnt && (!this.__mouseOverFlag && i == 0 || isOver || i == this.__clones.length)) {
			if (i == 0) {
				elem = this.content;
				elem.style.opacity = "1";
				cnt = true;
			} else {
				elem = this.__clones[cl];
				if (elem) {
					elem.style.opacity = "1";
				}
				cl++;
			}
			if (elem) {
				elem.style.left = x + "px";
				elem.style.top = y + "px";
			}
		}
	}
	
	
	function setupClones() {
		var num = 3;
		if (this.content.innerHTML != this.__contentHTML) {
			this.__contentHTML = this.content.innerHTML;
			for (var i = 0; i < this.__clones.length; i++) {
				this.removeChild(this.__clones[i]);
			}
			this.__clones = [];
		}
		if (this.content.childNodes.length) {
			for (var i = this.__clones.length; i < num; i++) {
				var clone = this.content.cloneNode(true);
				clone.removeAttribute("id");
				this.appendChild(clone);
				this.__clones.push(clone);
			}
		}
	}
	
	return ScrollContainer;
})();
/**
 * 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.DURATION = 1;
	
	Anchor.prototype.__baseElement = "a";
	Anchor.prototype.__tween = null;
	Anchor.prototype.__duration = Anchor.DURATION;
	
	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() {
		return this.__duration;
	}
	
	Anchor.prototype.setHref = function(href) {
		this.setAttribute("href", href);
	}
	
	Anchor.prototype.getHref = function() {
		return this.getAttribute("href");
	}
	
	Anchor.prototype.setName = function(name) {
		this.setAttribute("name", name);
	}
	
	Anchor.prototype.getName = function() {
		return this.getAttribute("name");
	}
	
	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; 
		var pathname = loc.pathname;
		url+= 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) {
			// initialize all anchor tags in 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() : Anchor.DURATION;
				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;
})();

