﻿Type.registerNamespace("ITkey.Web.UI");

ITkey.Web.UI.ItkRotator = function(element) {
	ITkey.Web.UI.ItkRotator.initializeBase(this, [element]);
	this._skin = "Default";
	this._postBackReference = null;
	this._items = null;
	this._webServiceSettings = new ITkey.Web.UI.WebServiceSettings({});
	this._webServiceLoader = null;
	this._containerElement = null;
	this._clickDelegate = null;
	this._mouseOutDelegate = null;
	this._mouseOverDelegate = null;
	this._itemShownDelegate = null;

	//TEKI: Props
	//Properties from old ItkRotator that will be implemented
	this._useRandomSlide = false;

	//Properties of the new Rotator
	this._pauseOnMouseOver = true;

	var directionEnum = ITkey.Web.UI.RotatorScrollDirection;
	this._scrollDirection = directionEnum.Left + directionEnum.Right;
	this._slideShowAnimationSettings = {};

	this._rotatorType = ITkey.Web.UI.RotatorType.AutomaticAdvance;
	this._scrollDuration = 500;
	this._frameDuration = 2000;
	this._initialItemIndex = 0;
	this._canPause = true;

	this._wrapFrames = true;
	this._controlButtons = {};

	//HTML Elements
	this._relativeWrapper = null;
	this._clipElement = null;
	this._itemsElement = null;

	//Utility refs
	this._animationDirection = directionEnum.Left;

	//buttons
	this._rightButton = null;
	this._leftButton = null;
	this._downButton = null;
	this._upButton = null;

}

ITkey.Web.UI.ItkRotator.prototype =
{
	initialize : function()
	{
		ITkey.Web.UI.ItkRotator.callBaseMethod(this, "initialize");
		//Create UI
		this._setChildElements();
		this._createUI();
		this._createChildItems();
		this._attachEvents(true);

		//If the initialFrame # is specified - move it to proper position
		this._initialItemSet = false;
		this._loadInitialFrame();

		//Configure rotator buttons(if any)
		this._enableDisableButtons();

		//handle case when the parent is invisible and becomes visible
		this._fixVisibilityProblems(true);

		//raise the client load event
		this.raiseEvent("load", Sys.EventArgs.Empty);

		//If automatic - start animation
		if (this.isAutomaticAdvance())
		{
			var frameDuration = this.get_frameDuration();
			if (frameDuration > 0)
			{
				window.setTimeout(Function.createDelegate(this, this.startAutoPlay), frameDuration);
			}
			else
			{
				this.startAutoPlay();
			}
		}
	},


	dispose : function()
	{
		this._fixVisibilityProblems(false);

		this._attachEvents(false);
		this._containerElement = null;
		//TEKI - Dispose animation
		if (this._animation)
		{
			this._animation.dispose();
			this._animation = null;
		}
		if (this._slideShowAnimation)
		{
			this._slideShowAnimation.dispose();
			this._slideShowAnimation = null;
		}

		//use attachevents to attach/detach events?
		if (this._rightButton) $clearHandlers(this._rightButton);
		if (this._leftButton) $clearHandlers(this._leftButton);
		if (this._downButton) $clearHandlers(this._downButton);
		if (this._upButton) $clearHandlers(this._upButton);

		//UL items element
		if (this._itemsElement)
		{
			$clearHandlers(this._itemsElement);
		}

		ITkey.Web.UI.ItkRotator.callBaseMethod(this, "dispose");
	},

	_createChildItems : function()
	{
		var childElements = $ITkey.getChildrenByTagName(this.get_containerElement(), "li");

		for (var i = 0; i < childElements.length; i++)
		{
			var rotatorItem = $create(ITkey.Web.UI.ItkRotatorItem, this.get_items()[i], null, null, childElements[i]);
			//calculate the item index
			var rotatorItemIndex = rotatorItem.get_index();
			childElements[i]._item = rotatorItem;
			this.get_items()[i] = rotatorItem;
		}
	},


	//================================ Changes added to support ButtonOver as well as changed logic for initial positioning of item when ScrollType is of type Automatic
	_getNextItemToShow : function()
	{
		var lis = this.getItemHtmlElements();

		var isForward = this.isScrollingForward();

		//Set the first or last item to be used as starting index (depending on direction)
		if (this._nextItemIndex == null)
		{
			var index = isForward ? 0 : lis.length - 1;
			this._nextItemIndex = index;
		}

		//Mozilla throws exception here if we use negative index. All other browsers are OK
		if (this._nextItemIndex < 0) return null;
		var li = lis[this._nextItemIndex];

		//Increase or decrease the index, depending on the direction
		if (isForward) this._nextItemIndex++;
		else this._nextItemIndex--;

		//NEW: Needed by the ButtonsOver way!
		if (this._nextItemIndex > lis.length - 1 || this._nextItemIndex < 0)
		{
			this._nextItemIndex = null;
		}

		return li;
	},

	//Return the item whose width/height will be used to judge whether there is enough length for the rotator to scroll an item
	get_currentItem : function()
	{
		var item = this._currentItem;
		if (!item)
		{
			var list = this._itemsElement;
			var lis = this.getItemHtmlElements();
			item = this.isScrollingForward() ? lis[0] : lis[lis.length - 1];
		}
		return item;
	},


	_needsShift : function(direction)
	{
		//If no direction is set, use the currently set
		if (null == direction) direction = this.get_animationDirection();
		var listElement = this._itemsElement;
		var viewPort = this._clipElement;
		var listLeft = parseInt(listElement.style.left);
		var listTop = parseInt(listElement.style.top);
		var listBounds = $ITkey.getOuterSize(listElement);
		var viewPortBounds = $ITkey.getContentSize(viewPort);

		var curItem = this.get_currentItem();
		if (!curItem)
		{
			return false;
		}

		var curItemSize = $ITkey.getOuterSize(curItem);

		var canSlide = false;
		var directionEnum = ITkey.Web.UI.RotatorScrollDirection;
		switch (direction)
		{
			case directionEnum.Left:
				canSlide = listLeft + listBounds.width < viewPortBounds.width + curItemSize.width;
				break;

			case directionEnum.Up:
				canSlide = listTop + listBounds.height < viewPortBounds.height + curItemSize.height;
				break;
			case directionEnum.Right:
				canSlide = listLeft * -1 < curItemSize.width;
				break;
			case directionEnum.Down:
				canSlide = listTop * -1 < viewPortBounds.height;
				break;
		}
		return canSlide;
	},

	_getMoveAnimation : function()
	{
		if (this._animation) return this._animation;

		var list = this._itemsElement;
		var duration = this._getCalculatedAnimationDuration();
		var fps = 25;
		this._animation = new ITkey.Web.Animation.MoveAnimation(list, duration, fps, true, false, false, "px"); //horizontal = true, vertical = false

		//Due to problem with Mozilla and other browsers in the way that the Lenght animation is implemented, it rounds values to 0 or 1, but it always needs to be 0!
		//Otherwise there is a kind of shaking during the animation
		function returnZeroPixels(start, end, percentage) { return 0; }

		if (this.get_vertical())
		{
			this._animation._horizontalAnimation.interpolate = returnZeroPixels;
		}
		else
		{
			this._animation._verticalAnimation.interpolate = returnZeroPixels;
		}

		return this._animation;

	},


	scrollViewport : function()
	{
		var list = this._itemsElement;

		//Create animation
		if (!this._animation)
		{
			var move = this._getMoveAnimation();
			var initItemAnimation = Function.createDelegate(this, function()
			{
				//See if rotator can slide a full length
				var canSlide = this._hasViewportWidth();
				//If false && wrapFrames = true -> move the required number of items in a while - 1)move 2)canScroll cycle
				if (!canSlide && this.get_wrapFrames())
				{
					//Move frames from list
					var listLength = this.getItemHtmlElements().length;
					for (var i = 0; i < listLength; i++)
					{
						//First time we arleady know that we need to do shift
						this._shiftItemInList();
						canSlide = this._hasViewportWidth();
						if (canSlide) break;
					}
				}

				//Set next x or y - to be the size of the viewPort
				var itemSize = this._getViewPortPixelsToScroll();

				var isForward = this.isScrollingForward();
				//Scrolling is vertical or horizontal?
				if (this.get_vertical())
				{
					var endPosition = parseInt(list.style.top) + (isForward ? -itemSize : itemSize);
					move.set_vertical(endPosition);
				}
				else
				{
					var endPosition = parseInt(list.style.left) + (isForward ? -itemSize : itemSize);
					move.set_horizontal(endPosition);
				}
			});

			move.add_started(Function.createDelegate(this, function()
			{
				//NEW: If animation is currently playing get its values and set those
				this.stopViewportAnimation();
				var needsShift = !this._hasViewportWidth();
				if (needsShift && !this.get_wrapFrames())
				{
					//if wrap frames is false and we have reached the end - stop here
					return false;
				}
				var realTarget = null;
				var showingArgs = new ITkey.Web.UI.ItkRotatorCancelEventArgs(realTarget);
				this.raiseEvent("itemShowing", showingArgs);
				if (showingArgs.get_cancel && showingArgs.get_cancel())
				{
					return false;
				}

				//NEW: Smooth out the list movement
				if (this.isSlideShow())
				{
					list.style.visibility = "hidden";
				}

				//Initialize animation
				initItemAnimation();
			}));

			move.add_ended(Function.createDelegate(this, function()
			{
				//Enable disable buttons if needed
				this._enableDisableButtons();

				if (this.isSlideShow())
				{
					//NEW: Smooth out the list movement
					list.style.visibility = "visible";
					this.runSlideShowAnimation();
				}
				else
				{
					//raise item shown event
					var realTarget = null;
					this.raiseEvent("itemShown", new ITkey.Web.UI.ItkRotatorEventArgs(realTarget));
				}
			}));
		}
		this._animation.play();
	},


	scrollItem : function()
	{
		var clipElement = this._clipElement;
		var list = this._itemsElement;

		//Create animation
		if (!this._animation)
		{
			this._animation = this._getMoveAnimation();

			var move = this._animation;
			var initItemAnimation = Function.createDelegate(this, function()
			{
				//Get next list item
				var nextItem = this._getNextItemToShow();
				if (!nextItem)
				{
					return;
				}
				//NEW: Set it to be used by get_currentItem - this method is called to perform some size calculations
				this._currentItem = nextItem;

				//Set next x/y
				var itemSize = $ITkey.getOuterSize(nextItem);

				//Multiply by -1 if the rotator is moving "forward"
				if (this.isScrollingForward())
				{
					itemSize.width *= -1;
					itemSize.height *= -1;
				}

				//Scrolling is vertical or horizontal?
				if (this.get_vertical())
				{
					var endPosition = parseInt(list.style.top) + itemSize.height;
					move.set_vertical(endPosition);
				}
				else
				{
					var endPosition = parseInt(list.style.left) + itemSize.width;
					move.set_horizontal(endPosition);
				}
			});


			move.add_started(Function.createDelegate(this, function()
			{
				var needsShift = this._needsShift();
				if (needsShift && !this.get_wrapFrames())
				{
					//if wrap frames is false and we have reached the end - stop here
					return false;
				}
				var realTarget = this._getNextItemToShow().control;
				var showingArgs = new ITkey.Web.UI.ItkRotatorCancelEventArgs(realTarget);
				this.raiseEvent("itemShowing", showingArgs);
				if (showingArgs.get_cancel && showingArgs.get_cancel())
				{
					return false;
				}
				//Flip frames first if needed
				
				if (needsShift)
				{
					this._shiftItemInList();
				}

				//Ignore if ButtonsOver mode is on, and mouse is out of rotator
				if (this._stopAnimationButtonOver) return;

				//Initialize animation
				initItemAnimation();
			}));

			move.add_ended(Function.createDelegate(this, function()
			{
				//raise item shown event
				var realTarget = this._getNextItemToShow().control;
				this.raiseEvent("itemShown", new ITkey.Web.UI.ItkRotatorEventArgs(realTarget));

				//Ignore if ButtonsOver mode is on, and mouse is out of rotator
				if (this._stopAnimationButtonOver) return;

				if (this.isAutomaticAdvance())
				{
					//Restart animation
					if (this.get_frameDuration() > 0)
						this._setAnimationTimeout(this.get_frameDuration());
					else
						this._animation.play();
				}
			}));
		}
		this._animation.stop();
		this._animation.play();
	},

	_checkItemsSize : function()
	{
		//checks if the list width is smaller than the rotator width
		//if it is - no need to scroll.
		var size = $ITkey.getOuterSize(this._itemsElement);
		var isVertical = this.get_vertical();
		var itemsLength = (isVertical) ? size.height : size.width;
		var rotatorLength = (isVertical) ? this.get_height() : this.get_width();
		return parseInt(itemsLength) > parseInt(rotatorLength);
	},

	_shiftItemInList : function()
	{
		var list = this._itemsElement;
		var lis = this.getItemHtmlElements();
		var isVertical = this.get_vertical();
		var isForward = this.isScrollingForward();
		var curX = parseInt(list.style.left);
		var curY = parseInt(list.style.top);

		var nextItem = isForward ? lis[0] : lis[lis.length - 1];
		var itemSize = $ITkey.getOuterSize(nextItem);

		nextItem.parentNode.removeChild(nextItem);

		if (!isForward)//Add item to the start of list
		{
			list.insertBefore(nextItem, list.firstChild);
		}

		//Set new left/top offset for the list
		if (isVertical)
		{
			list.style.top = (curY + (isForward ? itemSize.height : -itemSize.height)) + "px";
		}
		else
		{
			list.style.left = (curX + (isForward ? itemSize.width : -itemSize.width)) + "px";
		}

		if (isForward)
		{
			//Add item to end of list
			list.appendChild(nextItem);
		}

		//Set item index so that it "points" to proper LI
		this._nextItemIndex = isForward ? lis.length - 1 : 0;

		return nextItem;
	},


	_loadInitialFrame : function()
	{
		//Set the top/left for the first selected frame
		var firstVisible = this.get_initialItemIndex();
		var direction = this.get_defaultAnimationDirection();
		var directionEnum = ITkey.Web.UI.RotatorScrollDirection;
		var isVertical = this.isVertical();

		var listElement = this._itemsElement;
		var listSize = $ITkey.getOuterSize(listElement);
		//NEW - Take care of the viewport size
		var viewPortSize = $ITkey.getContentSize(this._clipElement);

		var x = 0;
		var y = 0;
		if (firstVisible >= 0)
		{
			if (isVertical)
			{
				y = (direction == directionEnum.Up) ? 0 : -listSize.height + viewPortSize.height;
			}
			else
			{
				x = (direction == directionEnum.Left) ? 0 : -listSize.width + viewPortSize.width;
			}
		}
		else if (firstVisible == -1)
		{
			//It should not be visible in the rotator, but depending on the scroll direction (say - Right, or Down) should be positioned
			//in such a way that when animation starts, the frame will start appearing right away.
			//NEW: -1 has a special meaning - it needs to set the rotator JUST OUTSIDE of the viewport and prepare it for sliding
			//However, depending on the direction where to slide, we need extra calcuations
			//			|  |-1 |  |
			//			-----------
			//			|-1| 0 |-1|
			//			-----------
			//			|  |-1 |  |
			if (isVertical)
			{
				//Set to the end of the viewport
				y = (direction == directionEnum.Down) ? -listSize.height : viewPortSize.height;
			}
			else
			{
				//Set to the end of the viewport
				x = (direction == directionEnum.Right) ? -listSize.width : viewPortSize.width;
			}
		}
		listElement.style.left = x + "px";
		listElement.style.top = y + "px";
		if (firstVisible > 0 && !this._initialItemSet)
		{
			//shift items to position the one with initialItemIndex at the beginning
			for (var i = 0; i < firstVisible; i++)
			{
				this._shiftItemInList();
			}
			//vertical rotator needs an additional shift if we want to see the same item 
			//as in horizontal scrolling
			//if (isVertical) this._shiftItemInList();
			listElement.style.left = x + "px";
			listElement.style.top = y + "px";
		}
		if (!this._initialItemSet && firstVisible>=0)
		{
			this.raiseEvent("itemShown", new ITkey.Web.UI.ItkRotatorEventArgs(this.get_items()[firstVisible]));
		}
		this._initialItemSet = true;
	},

	pause : function()
	{
		this._isPaused = true;
		//If animation actually exists
		if (this._animation && this._animation.get_isActive()) this._animation.pause();
	},

	resume : function()
	{
		if (this._timeoutPassed || !this._isPaused)
		{
			if (this._animation) this._animation.play();
		}
		else if (this._isPaused)
		{
			this._isPaused = false;
			//If animation actually is in progress, resume it as well
			if (this._animation && this._animation.get_isActive()) this._animation.play();
		}
	},

	stop : function()
	{
		this._clearAnimationTimeout();
		this._canPause = false;
		this.pause();
	},
	
	start : function()
	{
		this._canPause = true;
		this._isPaused = false;
		this.resume();
	},

	isViewportScrollMode : function()
	{
		//returns true if mode is of type that one scroll will scroll the whole viewport
		var typeEnum = ITkey.Web.UI.RotatorType;
		//AutomaticAdvance, iPod, 2DSurface, Carousel
		if (this._isRotatorTypeEnabled(typeEnum.AutomaticAdvance) ||
			this._isRotatorTypeEnabled(typeEnum.ButtonsOver) ||
			this._isRotatorTypeEnabled(typeEnum.FromCode)
			)
		{
			return false;
		}
		//Buttons, Slideshow, FromCode
		return true;
	},

	_getButtonScrollDirection : function(button)
	{
		var scrollEnum = ITkey.Web.UI.RotatorScrollDirection;
		var scrollValue = scrollEnum.Left;
		switch (button)
		{
			case this._rightButton: scrollValue = scrollEnum.Left; break;
			case this._leftButton: scrollValue = scrollEnum.Right; break;
			case this._downButton: scrollValue = scrollEnum.Up; break;
			case this._upButton: scrollValue = scrollEnum.Down; break;
		}
		return scrollValue;
	},

	//Refactor - itroduce a new method to be used in button over and buttonout
	_buttonClicked : function(e)
	{
		var button = e.target;
		if (this._isButtonDisabled(button)) return;

		var args = new ITkey.Web.UI.ItkRotatorButtonEventArgs(button);
		this.raiseEvent("buttonClick", args);
		if (args.get_cancel())
		{
			return;
		}

		var scrollValue = this._getButtonScrollDirection(button);

		this.set_animationDirection(scrollValue);
		this.scrollViewport();

		return $ITkey.cancelRawEvent(e);
	},


	_buttonOver : function(e)
	{
		var button = e.target;
		if (this._isButtonDisabled(button)) return;

		var args = new ITkey.Web.UI.ItkRotatorButtonEventArgs(button);
		this.raiseEvent("buttonOver", args);
		if (args.get_cancel())
		{
			return;
		}

		var scrollValue = this._getButtonScrollDirection(button);

		this.set_animationDirection(scrollValue);
		//NEW: FLAG Scroll item
		this._stopAnimationButtonOver = false;
		this.scrollItem();
		return $ITkey.cancelRawEvent(e);
	},

	_buttonOut : function(e)
	{
		var button = e.target;
		if (this._isButtonDisabled(button)) return;

		var args = new ITkey.Web.UI.ItkRotatorButtonEventArgs(button);
		this.raiseEvent("buttonOut", args);
		if (args.get_cancel())
		{
			return;
		}

		var scrollValue = this._getButtonScrollDirection(button);
		this.set_animationDirection(scrollValue);

		//NEW: FLAG Pause animation - actually this has side effects - let if finish instead!
		this._stopAnimationButtonOver = true;
		return $ITkey.cancelRawEvent(e);
	},


	_initializeButtonsRotatorType : function()
	{
		//Initialize & configure all buttons - show and hide those depending on the scrollDirection

		//Create references to these buttons
		var controlButtons = this.get_controlButtons();
		this._rightButton = $ITkey.getElementByClassName(this._rootElement, this._rotatorRightClass);
		this._leftButton = $ITkey.getElementByClassName(this._rootElement, this._rotatorLeftClass);
		this._downButton = $ITkey.getElementByClassName(this._rootElement, this._rotatorDownClass);
		this._upButton = $ITkey.getElementByClassName(this._rootElement, this._rotatorUpClass);

		//Create some initializations array to go through
		var directionEnum = ITkey.Web.UI.RotatorScrollDirection;
		var directionArray = [directionEnum.Right, directionEnum.Left, directionEnum.Down, directionEnum.Up];
		var buttonsArray = [this._leftButton, this._rightButton, this._upButton, this._downButton];
		var customButtonsArray = [controlButtons.LeftButtonID ? $get(controlButtons.LeftButtonID) : null,
								  controlButtons.RightButtonID ? $get(controlButtons.RightButtonID) : null,
								  controlButtons.UpButtonID ? $get(controlButtons.UpButtonID) : null,
								  controlButtons.DownButtonID ? $get(controlButtons.DownButtonID) : null];
		var cssArray = [this._rotatorLeftClass, this._rotatorRightClass, this._rotatorUpClass, this._rotatorDownClass];
		var marginsArray = ["marginLeft", "marginRight", "marginTop", "marginBottom"];
		var paddingsArray = ["paddingLeft", "paddingRight", "paddingTop", "paddingBottom"];
		var sizeArray = ["width", "width", "height", "height"];

		var relativeWrapper = this._relativeWrapper;
		var rootElement = this.get_element();

		for (var i = 0; i < buttonsArray.length; i++)
		{
			var button = buttonsArray[i];
			var buttonWithHandlers = (null != customButtonsArray[i]) ? customButtonsArray[i] : button;

			this._createButton(button, cssArray[i]);

			//See if button should be visible or hidden
			if (this._isScrollDirectionEnabled(directionArray[i]) && null == customButtonsArray[i])
			{
				//alert("buttonSize " + marginsArray[i]);
				button.style.display = "block";
				//Add margin and change width
				var sizeValue = sizeArray[i];
				var buttonSize = parseInt($ITkey.getCurrentStyle(button, sizeValue));

				//Reduce size of the relative wrapper
				relativeWrapper.style[sizeValue] = (parseInt(relativeWrapper.style[sizeValue]) - buttonSize) + "px";

				//Add padding to root parent, and change its size
				rootElement.style[sizeValue] = (parseInt(rootElement.style[sizeValue]) - buttonSize) + "px";
				rootElement.style[paddingsArray[i]] = buttonSize + "px";
			}

			if (this._isRotatorTypeEnabled(ITkey.Web.UI.RotatorType.Buttons) ||
				this._isRotatorTypeEnabled(ITkey.Web.UI.RotatorType.SlideShowButtons)
			)
			{
				$addHandlers(buttonWithHandlers, { "click": this._buttonClicked }, this);
			}
			else
			{
				//Add the hover and out
				$addHandlers(buttonWithHandlers, { "mouseover": this._buttonOver, "mouseout": this._buttonOut }, this);
			}
		}

		//set properties
		this._rightButton = customButtonsArray[1] || this._rightButton;
		this._leftButton = customButtonsArray[0] || this._leftButton;
		this._downButton = customButtonsArray[3] || this._downButton;
		this._upButton = customButtonsArray[2] || this._upButton;

		//NEW - if custom buttons are used, hide the border, let the developer style the rotator
		var hideBorder = false;
		for (var i = 0; i < customButtonsArray.length; i++) { if (customButtonsArray[i]) hideBorder = true; break; }
		return hideBorder;
	},


	//=========SlideShow modes=========//
	runSlideShowAnimation : function()
	{
		if (!this._slideShowAnimation)
		{
			var list = this._itemsElement;
			var duration = this.get_slideShowAnimationSettings().duration || 500;
			duration = duration / 1000;
			var animationType = this.get_slideShowAnimationSettings().type || ITkey.Web.UI.RotatorAnimationType.None;
			var startDelegate = Function.createDelegate(this, function()
			{
				//disable pause/resume during this animation
				//otherwise mouseover/mouseout events will cause premature item shifts
				this._canPause = false;
			});
			var endDelegate = Function.createDelegate(this, function()
			{
				this._canPause = true;
				//raise item shown event
				var realTarget = null;
				this.raiseEvent("itemShown", new ITkey.Web.UI.ItkRotatorEventArgs(realTarget));
				if (this.get_frameDuration() > 0 && this.isAutomaticAdvance()) this._setAnimationTimeout(this.get_frameDuration());
			});

			switch (animationType)
			{
				case ITkey.Web.UI.RotatorAnimationType.Fade:
					this._slideShowAnimation = new ITkey.Web.Animation.FadeInAnimation(list, duration);
					this._slideShowAnimation.add_started(startDelegate);
					this._slideShowAnimation.add_ended(endDelegate);
					break;
				case ITkey.Web.UI.RotatorAnimationType.Pulse:
					this._slideShowAnimation = new ITkey.Web.Animation.PulseAnimation(list, null);
					//Setting duration in the constructor results in exception, so it is set afterwards
					this._slideShowAnimation.set_iterations(1);
					this._slideShowAnimation.set_duration(duration);
					this._slideShowAnimation.add_ended(endDelegate);
					break;
				default:
					//no animation, just pause
					this._slideShowAnimation = {};
					this._slideShowAnimation.play = endDelegate;
					this._slideShowAnimation.dispose = function() { };
					break;
			}
		}
		this._slideShowAnimation.play();
	},

	//================================== TEKI ==========================================================//
	_hasViewportWidth : function(direction)
	{
		//If no direction is set, use the currently set
		if (null == direction) direction = this.get_animationDirection();
		var listElement = this._itemsElement;
		var viewPort = this._clipElement;
		var listLeft = parseInt(listElement.style.left);
		var listTop = parseInt(listElement.style.top);
		var listBounds = $ITkey.getOuterSize(listElement);
		var viewPortBounds = $ITkey.getContentSize(viewPort);

		var canSlide = false;
		var directionEnum = ITkey.Web.UI.RotatorScrollDirection;
		switch (direction)
		{
			case directionEnum.Left:
				canSlide = listBounds.width + listLeft < viewPortBounds.width * 2;
				break;
			case directionEnum.Up:
				canSlide = listBounds.height + listTop < viewPortBounds.height * 2;
				break;
			case directionEnum.Right:
				canSlide = (listLeft * -1 < viewPortBounds.width);
				break;
			case directionEnum.Down:
				canSlide = (listTop * -1 < viewPortBounds.height);
				break;
		}

		return !canSlide;
	},


	stopViewportAnimation : function()
	{
		var move = this._animation;
		if (!move) return;
		if (move.get_isPlaying())
		{
			move.stop();
			var isVertical = this.get_vertical();
			var value = isVertical ? move.get_vertical() : move.get_horizontal();
			if (null != value)
			{
				this._itemsElement.style[isVertical ? "top" : "left"] = value + "px";
			}
		}
	},




	_getViewPortPixelsToScroll : function()
	{
		var vertical = this.get_vertical();
		var viewPortSize = $ITkey.getContentSize(this._clipElement);
		var result = vertical ? viewPortSize.height : viewPortSize.width;
		return result;
	},


	showNext : function(animationDir)
	{
		//Set animation direction
		this.set_animationDirection(animationDir);

		if (!this._checkItemsSize())
		{
			//if the rotator width is bigger than the list of items - no need to scroll
			return;
		}

		if (this.isViewportScrollMode())
		{
			this.scrollViewport();
		}
		else
		{
			this.scrollItem();
		}
	},


	getItemHtmlElements : function()
	{
		//var lis = list.getElementsByTagName("LI");
		//return lis;
		//A better approach is needed to avoid returning items from nested lists. For now use implementation below. Will improve it in future.
		var list = this._itemsElement;
		if (!this._hasCleanedList)
		{
			var nodes = list.childNodes;
			for (var i = 0; i < nodes.length; i++)
			{
				var node = nodes[i];
				if (node && node.tagName != "LI")
				{
					list.removeChild(node);
					i--;
				}
			}
			this._hasCleanedList = true;
		}
		return list.childNodes;
	},


	_getCalculatedAnimationDuration : function(animationDir)
	{
		var result = this.get_scrollDuration() / 1000;
		return result;
	},


	//=============================== Animations pasue and start ================================================================//

	_setAnimationTimeout : function(milliseconds)
	{
		this._clearAnimationTimeout();
		this._currentAnimationTimeout = window.setTimeout(Function.createDelegate(this, function() { if (!this._isPaused) this.resume(); this._timeoutPassed = true; }), milliseconds);
	},

	_clearAnimationTimeout : function()
	{
		if (this._currentAnimationTimeout)
		{
			window.clearTimeout(this._currentAnimationTimeout);
		}
		this._currentAnimationTimeout = 0;
		this._timeoutPassed = false;
	},

	//=======================================================================================================================//

	//Determine whether the method advances scrolls automatically, or requires manual interaction
	isAutomaticAdvance : function()
	{
		var typeEnum = ITkey.Web.UI.RotatorType;
		if (this._isRotatorTypeEnabled(typeEnum.AutomaticAdvance) || this._isRotatorTypeEnabled(typeEnum.SlideShow))//+ CarouselAutomatic
		{
			return true;
		}
		//All other modes
		return false;
	},

	isSlideShow : function()
	{
		var typeEnum = ITkey.Web.UI.RotatorType;
		if (this._isRotatorTypeEnabled(typeEnum.SlideShow) || this._isRotatorTypeEnabled(typeEnum.SlideShowButtons))
		{
			return true;
		}
		//All other modes
		return false;
	},


	//===================================================================================================================//
	isScrollingForward : function()
	{
		return this.isScrollingLeft() || this.isScrollingUp();
	},

	isScrollingLeft : function()
	{
		return this._isAnimationDirectionOn(ITkey.Web.UI.RotatorScrollDirection.Left);
	},

	isScrollingUp : function()
	{
		return this._isAnimationDirectionOn(ITkey.Web.UI.RotatorScrollDirection.Up);
	},


	_isAnimationDirectionOn : function(animDir)
	{
		return animDir == this.get_animationDirection() ? true : false;
	},

	//===================================================================================================================//


	_enableDisableButtons : function()
	{
		//If no buttons, return
		if (this._rotatorType == ITkey.Web.UI.RotatorType.AutomaticAdvance) return;

		//If wrapFrames - enable buttons
		var wrapFrames = this.get_wrapFrames();

		var directionEnum = ITkey.Web.UI.RotatorScrollDirection;

		//Check if there is at least one more 'go' into a direction and enable a button, disable it if it is not possible to scroll more.
		this._enableButton(this._rightButton, wrapFrames || this._canSlideMore(directionEnum.Left));
		this._enableButton(this._leftButton, wrapFrames || this._canSlideMore(directionEnum.Right));
		this._enableButton(this._downButton, wrapFrames || this._canSlideMore(directionEnum.Up));
		this._enableButton(this._upButton, wrapFrames || this._canSlideMore(directionEnum.Down));
	},


	_enableButton : function(button, toEnable)
	{
		if (!button) return;

		if (toEnable)
		{
			//Removed disabled class
			Sys.UI.DomElement.removeCssClass(button, this._rotatorButtonDisabledClass);
			button.removeAttribute("disabled");
		}
		else
		{
			//Add disabled class
			Sys.UI.DomElement.addCssClass(button, this._rotatorButtonDisabledClass);
			button.setAttribute("disabled", "disabled");
		}
	},


	_canSlideMore : function(direction)
	{
		//If no direction is set, use the currently set
		if (null == direction) direction = this.get_animationDirection();

		//Right - if list.left < 0
		//Left - if list.width + list.left > port.width
		//Down - if list.top < 0
		//Up - if list.height + list.top > port.height
		var canSlide = false;
		var listElement = this._itemsElement;
		var viewPort = this._clipElement;
		var directionEnum = ITkey.Web.UI.RotatorScrollDirection;

		var listLeft = parseInt(listElement.style.left);
		var listTop = parseInt(listElement.style.top);
		var listBounds = $ITkey.getBounds(listElement);

		var viewPortBounds = $ITkey.getBounds(viewPort);

		if (direction == directionEnum.Left)
		{
			canSlide = (listBounds.width + listLeft) > viewPortBounds.width;
		}
		else if (direction == directionEnum.Up)
		{
			canSlide = (listBounds.height + listTop) > viewPortBounds.height;
		}
		else if (direction == directionEnum.Right)
		{
			canSlide = (listLeft < 0);
		}
		else if (direction == directionEnum.Down)
		{
			canSlide = (listTop < 0);
		}

		return canSlide;
	},

	_getCalculatedAnimationDirection : function()
	{
		var animationDir = this.get_animationDirection();
		//These animations are declared in ItkToolTip and are used in all ITkeyAnimations
		//TopCenter : 12,
		//MiddleRight : 21,
		//MiddleLeft : 23,
		//BottomCenter : 32,
		var directionEnum = ITkey.Web.UI.RotatorScrollDirection;
		var direction = 23;

		switch (animationDir)
		{
			case directionEnum.Left: direction = 21; break;
			case directionEnum.Down: direction = 32; break;
			case directionEnum.Up: direction = 12; break;
			default: direction = 23;
		}
		return direction;
	},


	startAutoPlay : function()
	{
		//Set the default frame before you start animation for the first time
		this._loadInitialFrame();

		//Start animation!
		this.showNext(this.get_defaultAnimationDirection());
	},

	get_defaultAnimationDirection : function()
	{
		//Get the first possible enabled direction

		var directionEnum = ITkey.Web.UI.RotatorScrollDirection;
		var dir = 0;

		if (this._isScrollDirectionEnabled(directionEnum.Left))
		{
			dir = directionEnum.Left;
		}
		else if (this._isScrollDirectionEnabled(directionEnum.Up))
		{
			dir = directionEnum.Up;
		}
		else if (this._isScrollDirectionEnabled(directionEnum.Right))
		{
			dir = directionEnum.Right;
		}
		else if (this._isScrollDirectionEnabled(directionEnum.Down))
		{
			dir = directionEnum.Down;
		}
		if (!dir) dir = directionEnum.Left;

		return dir;
	},

	get_containerElement : function()
	{
		return this._itemsElement;
	},


	_setChildElements : function()
	{
		//================== Class names - define for easy change ===========================//
		this._rotatorListClass = "radr_itemsList";
		this._rotatorVerticalClass = "radr_verticalList";
		this._rotatorRelativeWrapperClass = "radr_relativeWrapper";
		this._rotatorClipRegionClass = "radr_clipRegion";
		this._rotatorRightClass = "radr_buttonRight";
		this._rotatorLeftClass = "radr_buttonLeft";
		this._rotatorDownClass = "radr_buttonDown";
		this._rotatorUpClass = "radr_buttonUp";
		this._rotatorButtonDisabledClass = "radr_buttonDisabled";

		//======================Get HTML elements that were rendered from the server==================================//
		this._rootElement = this.get_element();

		//Get relativeWrapper that holds the clip list
		this._relativeWrapper = $ITkey.getElementByClassName(this._rootElement, this._rotatorRelativeWrapperClass);

		//Get the clip region element
		this._clipElement = $ITkey.getElementByClassName(this._rootElement, this._rotatorClipRegionClass);

		//Get the list of items element
		this._itemsElement = $ITkey.getElementByClassName(this._rootElement, this._rotatorListClass);

	},

	_createUI : function()
	{
		if (!this.isVisible())
		{
			//do not calculate the rotator size if it is not visible yet
			return;
		}

		//Set explicit size for the viewport!
		var rootElement = this.get_element();
		var relativeWrapper = this._relativeWrapper;
		var clipRegion = this._clipElement;

		relativeWrapper.style.height = rootElement.offsetHeight + "px";
		relativeWrapper.style.width = rootElement.offsetWidth + "px";

		//Create buttons
		//See if type is buttons, and we need buttons or it sAutomaticAdvance
		var hideBorder = true;
		if (this._isRotatorTypeEnabled(ITkey.Web.UI.RotatorType.Buttons) ||
			this._isRotatorTypeEnabled(ITkey.Web.UI.RotatorType.ButtonsOver) ||
			this._isRotatorTypeEnabled(ITkey.Web.UI.RotatorType.SlideShowButtons)
		)
		{
			//Here we need to know whether to hide the border
			hideBorder = this._initializeButtonsRotatorType();
		}

		if (hideBorder) Sys.UI.DomElement.addCssClass(rootElement, "radr_noBorder");

		//Set the proper list orientation for the scrolling
		if (this.get_vertical())
		{
			this.set_vertical(true);
		}

		//Set relativeWrapper overlow to auto for a while to calculate list size
		relativeWrapper.style.overflow = "auto";

		//The list size calculation happens here
		//Set overflow to auto
		clipRegion.style.overflow = "auto";
		//Set huge width (and height if the list is vertical) so that its size can be calculated OK
		clipRegion.style.width = "10000px";
		clipRegion.style.height = "10000px";

		//Set the width and height of the list element
		//NEW: Because of bug in rendering in IE6 and IE7 we need to set the width of the vertical list to be as wide as the VIEWPORT!
		this._itemsElement.style.width = this.get_vertical() ? relativeWrapper.style.width : this._itemsElement.offsetWidth + "px";
		//this._itemsElement.style.width = this.get_vertical() ? "1px": this._itemsElement.offsetWidth + "px";
		this._itemsElement.style.height = this._itemsElement.offsetHeight + "px";

		//Restore things
		//Fix element sized and overflows, calculations are complete!
		relativeWrapper.style.overflow = "";
		clipRegion.style.width = relativeWrapper.style.width;
		clipRegion.style.height = relativeWrapper.style.height;

		//Finish the element setup!
		//Hide the overflow of the clip region
		clipRegion.style.overflow = "hidden";
		//IE6 seems to have a problem with parent not being relative
		clipRegion.style.position = "relative";

		//Set position to relative/absolute to the list as well!
		this._itemsElement.style.position = "relative";

		//Make visible - last thing you do after all initialization is complete
		rootElement.style.visibility = "visible";
	},

	_createButton : function(baseElement, className)
	{
		var elem = baseElement;
		if (!elem)
		{
			elem = document.createElement("div");
		}

		if (!elem.className) elem.className = this._rotatorDownClass;
		return elem;
	},


	//A method that says if a button is enabled by using its containsCssClass method da checkva za disabled. I ako e disabled, clicka mu nishto ne pravi
	_isButtonDisabled : function(button)
	{
		if (!button) return true; //we consider a non-existent button to be disabled
		return Sys.UI.DomElement.containsCssClass(button, this._rotatorButtonDisabledClass);
	},

	_isScrollDirectionEnabled : function(scrollDir)
	{
		//return true;
		return scrollDir & this._scrollDirection ? true : false;
	},

	_isRotatorTypeEnabled : function(type)
	{
		return type == this._rotatorType ? true : false;
	},

	//================================= TEKI: New props (or modified existing props ==================================//
	//Sets a property how the rotator will render and what options the user will have for interacting with it on the client.
	get_rotatorType : function()
	{
		return this._rotatorType;
	},
	set_rotatorType : function(value)
	{
		this._rotatorType = value;
	},


	//Sets a property whether frames should wrap after the rotator scrolls to the end
	get_wrapFrames : function()
	{
		return this._wrapFrames;
	},
	set_wrapFrames : function(value)
	{
		this._wrapFrames = value;
	},


	//Duration is the time it takes for one length of the rotator to be scrolled! Thus we can calculate time it takes for any lenght of items
	//When in slideshow mode, scroll duration is set to 1 - instant item move without animation
	get_scrollDuration : function()
	{
		if (this.isSlideShow())
		{
			return 1;
		}
		else
		{
			return this._scrollDuration;
		}
	},

	set_scrollDuration : function(value)
	{
		this._scrollDuration = value;
	},

	set_vertical : function(value)
	{
		//If UI is created set it
		if (this._itemsElement)
		{
			Sys.UI.DomElement.addCssClass(this._itemsElement, this._rotatorVerticalClass);
		}
	},

	get_vertical : function()
	{
		//Vertical is always when developer specified Down or Up or both scrollDirections
		var directionEnum = ITkey.Web.UI.RotatorScrollDirection;
		return (this._isScrollDirectionEnabled(directionEnum.Down) || this._isScrollDirectionEnabled(directionEnum.Up));
	},

	isVertical : function()
	{
		if (this._itemsElement) return Sys.UI.DomElement.containsCssClass(this._itemsElement, this._rotatorVerticalClass);
		return false;
	},

	get_height : function()
	{
		return this.get_element().style.height;
	},

	set_height : function(value)
	{
		this.get_element().style.height = value;
		if (this.isVisible())
		{
			this.repaint();
		}
	},

	get_width : function()
	{
		return this.get_element().style.width;
	},
	set_width : function(value)
	{
		this.get_element().style.width = value;
		if (this.isVisible())
		{
			this.repaint();
		}
	},

	get_scrollDirection : function()
	{
		return this._scrollDirection;
	},

	set_scrollDirection : function(value)
	{
		this._scrollDirection = value;
	},

	get_frameDuration : function()
	{
		return this._frameDuration;
	},

	set_frameDuration : function(value)
	{
		this._frameDuration = value;
	},

	get_controlButtons : function()
	{
		return this._controlButtons;
	},

	set_controlButtons : function(value)
	{
		this._controlButtons = value;
	},

	get_initialItemIndex : function()
	{
		return this._initialItemIndex;
	},

	set_initialItemIndex : function(value)
	{
		this._initialItemIndex = value;
	},

	get_slideShowAnimationSettings : function()
	{
		return this._slideShowAnimationSettings;
	},

	set_slideShowAnimationSettings : function(value)
	{
		this._slideShowAnimationSettings = value;
	},


	//Client-side property only - set by buttons or code
	set_animationDirection : function(animationDir)
	{
		this._animationDirection = animationDir ? animationDir : ITkey.Web.UI.RotatorScrollDirection.Left;
	},

	get_animationDirection : function()
	{
		return this._animationDirection;
	},
	//================================== /TEKI ==========================================================//

	_attachEvents : function(toAttach)
	{
		//click, mouseover, mouseout
		var containerElement = this.get_containerElement();
		if (null == containerElement)
		{
			return;
		}

		if (toAttach != false)
		{
			this._clickDelegate = Function.createDelegate(this, this._mouseClickHandler);
			this._mouseOutDelegate = Function.createDelegate(this, this._mouseOutHandler);
			this._mouseOverDelegate = Function.createDelegate(this, this._mouseOverHandler);
			this._itemShownDelegate = Function.createDelegate(this, this._itemShownHandler);
			$addHandler(containerElement, "mouseover", this._mouseOverDelegate);
			$addHandler(containerElement, "mouseout", this._mouseOutDelegate);
			$addHandler(containerElement, "click", this._clickDelegate);
			this.add_itemShown(this._itemShownDelegate);
		}
		else
		{
			$removeHandler(containerElement, "mouseover", this._mouseOverDelegate);
			$removeHandler(containerElement, "mouseout", this._mouseOutDelegate);
			$removeHandler(containerElement, "click", this._clickDelegate);
			this._clickDelegate = null;
			this._mouseOutDelegate = null;
			this._mouseOverDelegate = null;
			this.remove_itemShown(this._itemShownDelegate);
		}
	},

	_itemShownHandler : function(args)
	{
		if (typeof(ITkey.Web.UI.ItkTicker) == "undefined")
		{
			//ItkTicker scripts are not loaded on the page, no need to check further
			return;
		}
		//fire tickers
		var items = this.get_items();
		for (var i=0, len = items.length;i<len;i++)
		{
			var ritem = items[i];
			if (this._isItemVisible(ritem))
			{
				this._fireTickersForItem(ritem);
			}
			else
			{
				this._resetTickersForItem(ritem);
			}
		}
	},

	_mouseOverHandler : function(args)
	{
		if (this.isAutomaticAdvance() && this._canPause)
		{
			//Pause animation
			this.pause();
		}

		var realTarget = this._getItemFromEvent(args.target);
		if (null != realTarget)
		{
			this.raiseEvent("mouseOver", new ITkey.Web.UI.ItkRotatorEventArgs(realTarget));
		}
	},

	_mouseOutHandler : function(args)
	{
		if (this.isAutomaticAdvance() && this._canPause)
		{
			//Resume animation
			this.resume();
		}

		var realTarget = this._getItemFromEvent(args.target);
		if (null != realTarget)
		{
			this.raiseEvent("mouseOut", new ITkey.Web.UI.ItkRotatorEventArgs(realTarget));
		}
	},

	_mouseClickHandler : function(args)
	{
		var realTarget = this._getItemFromEvent(args.target);
		if (null != realTarget)
		{
			var clickingArgs = new ITkey.Web.UI.ItkRotatorCancelEventArgs(realTarget);
			this.raiseEvent("itemClicking", clickingArgs);
			if (clickingArgs.get_cancel && clickingArgs.get_cancel())
			{
				$ITkey.cancelRawEvent(args.rawEvent);
				return false;
			}
			window.setTimeout(Function.createDelegate(this, function()
			{
				this.raiseEvent("itemClicked", new ITkey.Web.UI.ItkRotatorEventArgs(realTarget));
				this._postback(realTarget.get_index());
			}), 0);
		}
	},

	_postback : function(itemIndex)
	{
		if (!this._postBackReference)
			return;
		var postbackFunction = this._postBackReference.replace("arguments", itemIndex);
		eval(postbackFunction);
	},

	_isItemVisible : function(item)
	{
		//TODO: implement better detection
		var viewportBounds = $ITkey.getContentSize(this._clipElement);
		var size = $ITkey.getLocation(this._clipElement);
		viewportBounds.x = size.x;
		viewportBounds.y = size.y;
		
		var elementBounds = $ITkey.getOuterSize(item.get_element());
		var size = $ITkey.getLocation(item.get_element());
		elementBounds.x = size.x;
		elementBounds.y = size.y;

		//true if either rectangle is inside the other
		var eiv = ($ITkey.containsPoint(viewportBounds, elementBounds.x, elementBounds.y) && $ITkey.containsPoint(viewportBounds, elementBounds.x + elementBounds.width, elementBounds.y + elementBounds.height));
		var vie = ($ITkey.containsPoint(elementBounds, viewportBounds.x, viewportBounds.y) && $ITkey.containsPoint(elementBounds, viewportBounds.x + viewportBounds.width, viewportBounds.y + viewportBounds.height));
		//debugger;
		return eiv || vie;
	},
	
	_fireTickersForItem : function(item)
	{
		var tickers = item.get_tickers();
		for (var i=0,len=tickers.length;i<len;i++)
		{
			if (tickers[i])
			{
				var ticker = $find(tickers[i]);
				if (ticker)
					ticker.startTicker();
			}
		}
	},
	
	_resetTickersForItem : function(item)
	{
		var tickers = item.get_tickers();
		for (var i=0,len=tickers.length;i<len;i++)
		{
			if (tickers[i])
			{
				var ticker = $find(tickers[i]);
				if (ticker)
					ticker.resetTicker();
			}
		}
	},
	
	_getItemFromEvent : function(element)
	{
		var container = this.get_containerElement();
		var frame = null;
		while (null != element && element != container)
		{
			if (element.tagName.toLowerCase() == "li" && null != element._item && Object.getTypeName(element._item) == "ITkey.Web.UI.ItkRotatorItem")
				frame = element._item;
			element = element.parentNode;
		}
		return frame;
	},

	_initializeWebServiceLoader : function()
	{
		this._webServiceLoader = new ITkey.Web.UI.WebServiceLoader(this.get_webServiceSettings());
		this._webServiceLoader.add_loadingStarted(Function.createDelegate(this, this._onItemLoadingStarted));
		this._webServiceLoader.add_loadingSuccess(Function.createDelegate(this, this._onItemLoadingSuccess));
		this._webServiceLoader.add_loadingError(Function.createDelegate(this, this._onItemLoadingError));
	},

	_loadChildrenFromWebService : function(itemIndex, itemCount)
	{
		if (!this._webServiceLoader)
		{
			this._initializeWebServiceLoader();
		}

		var params = { itemIndex: itemIndex, itemCount: itemCount };
		this._webServiceLoader.loadData(params, params);
	},

	_onItemLoadingStarted : function(sender, eventArgs)
	{
		//item.showloading
	},

	_onItemLoadingSuccess : function(sender, eventArgs)
	{
		var result = eventArgs.get_data();
		if (result && result.length > 0)
		{
			for (var i = 0; i < result.length; i++)
			{
				this.createRotatorItem(result[i]);
			}
		}
		//item.hideloading
		//item.show
	},

	_onItemLoadingError : function(sender, eventArgs)
	{
		var errorMessage = eventArgs.get_message();
		alert(errorMessage);
	},

	createRotatorItem : function(radRotatorItemData)
	{
		var container = this.get_containerElement();
		var listItem = container.ownerDocument.createElement("li");
		container.appendChild(listItem);
		listItem.innerHTML = radRotatorItemData.Html;
		var args = { cssClass: radRotatorItemData.CssClass, visible: radRotatorItemData.Visible };
		var rotatorItem = $create(ITkey.Web.UI.ItkRotatorItem, args, null, null, listItem);
		listItem._item = rotatorItem;
		Array.add(this.get_items(), rotatorItem);
	},

	_getInvisibleParent : function()
	{
		var parent = this.get_element();
		while (parent && parent != document)
		{
			if ("none" == $ITkey.getCurrentStyle(parent, "display", ""))
			{
				return parent;
			}
			parent = parent.parentNode;
		}
		return null;
	},

	isVisible : function()
	{
		//we are visible if no invisible parent exists
		return (this._getInvisibleParent() == null);
	},

	_fixVisibilityProblems : function(toAttach)
	{
		if (toAttach)
		{
			var parent = this._getInvisibleParent();
			if (parent)
			{
				this._onParentVisibilityChangeDelegate = Function.createDelegate(this, this._onParentVisibilityChange);
				this._invisibleParent = parent;
				if ($ITkey.isIE)
				{
					$addHandler(this._invisibleParent, "propertychange", this._onParentVisibilityChangeDelegate);
				}
				else
				{
					this._invisibleParent.addEventListener("DOMAttrModified", this._onParentVisibilityChangeDelegate, false);
				}
			}
		}
		else
		{
			if (this._invisibleParent && this._onParentVisibilityChangeDelegate)
			{
				if ($ITkey.isIE)
				{
					$removeHandler(this._invisibleParent, "propertychange", this._onParentVisibilityChangeDelegate);
				}
				else
				{
					this._invisibleParent.removeEventListener("DOMAttrModified", this._onParentVisibilityChangeDelegate, false);
				}
				this._onParentVisibilityChangeDelegate = null;
				this._invisibleParent = null;
			}
		}
	},

	_onParentVisibilityChange : function(e)
	{
		if ($ITkey.isIE)
		{
			var e = e.rawEvent; //e is a fake MS AJAX event wrapper that misses important info!
			if (!e) return;
			if (e.propertyName == "style.display" || e.propertyName == "className")
			{
				//Update the size only once - the first time the parent is shown, and then never again!
				var display = $ITkey.getCurrentStyle(this._invisibleParent, "display");
				if (display != "none")
				{
					this.repaint();
				}
			}
		}
		else
		{
			if (e.attrName == "style" || e.attrName == "class")//! class must be used, not className!!!!
			{
				var element = e.target;
				if ((e.currentTarget == e.originalTarget) && "none" != $ITkey.getCurrentStyle(element, "display"))
				{
					//Timeout is needed as in fact the event is raised before actual changes are rendered
					window.setTimeout(Function.createDelegate(this, function() { this.repaint(); }), 0);
				}
			}
		}
		this._fixVisibilityProblems(false);
	},

	repaint : function()
	{
		this._createUI();
	},

	add_itemClicking : function(handler)
	{
		this.get_events().addHandler("itemClicking", handler);
	},

	remove_itemClicking : function(handler)
	{
		this.get_events().removeHandler("itemClicking", handler);
	},

	add_itemClicked : function(handler)
	{
		this.get_events().addHandler("itemClicked", handler);
	},

	remove_itemClicked : function(handler)
	{
		this.get_events().removeHandler("itemClicked", handler);
	},

	add_mouseOver : function(handler)
	{
		this.get_events().addHandler("mouseOver", handler);
	},

	remove_mouseOver : function(handler)
	{
		this.get_events().removeHandler("mouseOver", handler);
	},

	add_mouseOut : function(handler)
	{
		this.get_events().addHandler("mouseOut", handler);
	},

	remove_mouseOut : function(handler)
	{
		this.get_events().removeHandler("mouseOut", handler);
	},

	add_itemShowing : function(handler)
	{
		this.get_events().addHandler("itemShowing", handler);
	},

	remove_itemShowing : function(handler)
	{
		this.get_events().removeHandler("itemShowing", handler);
	},

	add_itemShown : function(handler)
	{
		this.get_events().addHandler("itemShown", handler);
	},

	remove_itemShown : function(handler)
	{
		this.get_events().removeHandler("itemShown", handler);
	},

	add_load : function(handler)
	{
		this.get_events().addHandler("load", handler);
	},

	remove_load : function(handler)
	{
		this.get_events().removeHandler("load", handler);
	},

	add_buttonOver : function(handler)
	{
		this.get_events().addHandler("buttonOver", handler);
	},

	remove_buttonOver : function(handler)
	{
		this.get_events().removeHandler("buttonOver", handler);
	},

	add_buttonOut : function(handler)
	{
		this.get_events().addHandler("buttonOut", handler);
	},

	remove_buttonOut : function(handler)
	{
		this.get_events().removeHandler("buttonOut", handler);
	},

	add_buttonClick : function(handler)
	{
		this.get_events().addHandler("buttonClick", handler);
	},

	remove_buttonClick : function(handler)
	{
		this.get_events().removeHandler("buttonClick", handler);
	},

	get_items : function()
	{
		return this._items;
	},

	set_items : function(value)
	{
		this._items = value;
	},

	get_webServiceSettings : function()
	{
		return this._webServiceSettings;
	},

	set_webServiceSettings : function(value)
	{
		var deserializedWebServiceSettings = Sys.Serialization.JavaScriptSerializer.deserialize(value);
		this._webServiceSettings = new ITkey.Web.UI.WebServiceSettings(deserializedWebServiceSettings);
	},

	get_skin : function()
	{
		return this._skin;
	},

	set_skin : function(value)
	{
		this._skin = value;
	}
}

ITkey.Web.UI.ItkRotator.registerClass("ITkey.Web.UI.ItkRotator", ITkey.Web.UI.ItkWebControl);

ITkey.Web.UI.ItkRotatorEventArgs = function(item)
{
	ITkey.Web.UI.ItkRotatorEventArgs.initializeBase(this);
	this._item = item;
}

ITkey.Web.UI.ItkRotatorEventArgs.prototype =
{
	get_item : function()
	{
		return this._item;
	}
}

ITkey.Web.UI.ItkRotatorEventArgs.registerClass("ITkey.Web.UI.ItkRotatorEventArgs", Sys.EventArgs);


ITkey.Web.UI.ItkRotatorCancelEventArgs = function(item)
{
	ITkey.Web.UI.ItkRotatorCancelEventArgs.initializeBase(this);
	this._item = item;
}

ITkey.Web.UI.ItkRotatorCancelEventArgs.prototype =
{
	get_item : function()
	{
		return this._item;
	}
}

ITkey.Web.UI.ItkRotatorCancelEventArgs.registerClass("ITkey.Web.UI.ItkRotatorCancelEventArgs", Sys.CancelEventArgs);


ITkey.Web.UI.ItkRotatorButtonEventArgs = function(button)
{
	ITkey.Web.UI.ItkRotatorButtonEventArgs.initializeBase(this);
	this._button = button;
}

ITkey.Web.UI.ItkRotatorButtonEventArgs.prototype =
{
	get_button : function()
	{
		return this._button;
	}
}

ITkey.Web.UI.ItkRotatorButtonEventArgs.registerClass("ITkey.Web.UI.ItkRotatorButtonEventArgs", Sys.CancelEventArgs);

ITkey.Web.UI.ItkRotatorItem = function(element)
{
	ITkey.Web.UI.ItkRotatorItem.initializeBase(this, [element]);
	this._visible = null;
	this._cssClass = null;
	this._index = -1;
}

ITkey.Web.UI.ItkRotatorItem.prototype =
{
	initialize : function()
	{
		ITkey.Web.UI.ItkRotatorItem.callBaseMethod(this, "initialize");
		this._tickers = null;
	},

	dispose : function()
	{
		ITkey.Web.UI.ItkRotatorItem.callBaseMethod(this, "dispose");
	},

	get_index : function()
	{
		if (this._index == -1)
		{
			var index = 0;
			var element = this.get_element();
			var parent = element.parentNode;
			if (null != parent)
			{
				var siblings = $ITkey.getChildrenByTagName(parent, "li");
				if (null != siblings)
				{
					for (index=0; index<siblings.length && siblings[index] != element;index++);
					if (index == siblings.length)
					{
						index = 0;
					}
				}
			}
			this._index = index;
		}
		return this._index;
	},

	get_visible : function()
	{
		return this._visible;
	},

	set_visible : function(value)
	{
		this._visible = value;
	},

	get_cssClass : function()
	{
		return this._cssClass;
	},

	set_cssClass : function(value)
	{
		this._cssClass = value;
	},
	
	get_tickers : function()
	{
		//TODO: Optimize, perhaps using JQ?
		if (null == this._tickers && typeof(ITkey.Web.UI.ItkTicker) != "undefined")
		{
			this._tickers = [];
			for (var i=0,length=$ITkey.radControls.length;i<length;i++)
			{
				var control = $ITkey.radControls[i];
				if (ITkey.Web.UI.ItkTicker.isInstanceOfType(control) && $ITkey.isDescendant(this.get_element(), control.get_element()))
					Array.add(this._tickers, control.get_id());
			}
		}
		return this._tickers;
	}
}

ITkey.Web.UI.ItkRotatorItem.registerClass("ITkey.Web.UI.ItkRotatorItem", Sys.UI.Control);

//=========================================== TEKI ================================================//
ITkey.Web.UI.RotatorScrollDirection = function() {
	/// <summary>
	/// Used to determine the possible scroll directions for a rotator.
	/// </summary>
	/// <field name="Left" type="Number" integer="true" />
	/// <field name="Right" type="Number" integer="true" />
	/// <field name="Up" type="Number" integer="true" />
	/// <field name="Down" type="Number" integer="true" />
	throw Error.invalidOperation();
}
ITkey.Web.UI.RotatorScrollDirection.prototype =
{
	Left: 1,
	Right : 2,
	Up: 4,
	Down : 8
};

ITkey.Web.UI.RotatorScrollDirection.registerEnum("ITkey.Web.UI.RotatorScrollDirection", false);

ITkey.Web.UI.RotatorAnimationType = function() {
	/// <summary>
	/// Used to determine the possible slide show animations of a rotator.
	/// </summary>
	/// <field name="None" type="Number" integer="true" />
	/// <field name="Fade" type="Number" integer="true" />
	/// <field name="Pulse" type="Number" integer="true" />
	throw Error.invalidOperation();
}
ITkey.Web.UI.RotatorAnimationType.prototype =
{
	None: 1,
	Fade : 2,
	Pulse: 3
};

ITkey.Web.UI.RotatorAnimationType.registerEnum("ITkey.Web.UI.RotatorAnimationType", false);

ITkey.Web.UI.RotatorType = function() {
	/// <summary>
	/// Used to determine the rotator type
	/// </summary>
	/// <field name="Buttons" type="Number" integer="true" />
	/// <field name="ButtonsOver" type="Number" integer="true" />
	/// <field name="AutomaticAdvance" type="Number" integer="true" />
	/// <field name="SlideShow" type="Number" integer="true" />
	/// <field name="SlideShowButtons" type="Number" integer="true" />
	/// <field name="FromCode" type="Number" integer="true" />
	throw Error.invalidOperation();
}
ITkey.Web.UI.RotatorType.prototype =
{
	AutomaticAdvance : 1,
	ButtonsOver : 2,
	Buttons : 3,
	SlideShow : 4,
	SlideShowButtons : 5,
	FromCode : 6
};

ITkey.Web.UI.RotatorType.registerEnum("ITkey.Web.UI.RotatorType", false);

if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();