﻿if (typeof (Tangora) == 'undefined') var Tangora = {};

// ImageRotator API -----------------------------------------------------------------------

Tangora.ImageRotator = ImageRotator;
Tangora.ImageRotatorManager = new ImageRotatorManager();


function ImageRotatorManager()
{
	var _instances = [];
	var _htmltransitions = null;
	var _pending = false;
	var _lightboxImageIndex = [];
	var _htmlLightBox = [];

	this.GetInstance = function (id)
	{
	    if (typeof (_instances[id]) == 'undefined') _instances[id] = new ImageRotator(id, true);
	    return _instances[id];
	}

	this.GetHtmlTransitions = function ()
	{
		if (!_htmltransitions)
		{
			if (_pending == false)
			{
				_pending = true;
				var ajax = tsAjax.createInstance('Transitions');
				ajax.method = 'post';
				ajax.postData = 'action=imagerotatorhtmltransitions';
				var result = tsAjax.innerHTML('/publicajax.ashx?ts=' + (new Date().getTime()), null, 'Transitions', null, null, null, true);
				result = eval('(' + result + ')');
				_htmltransitions = result;
			}
			else
			{
				var start = new Date().getTime()
				while (true)
				{
					// Avoid infinite loop
					var now = new Date().getTime();
					if (now - start > 5000) break;
					if (!_htmltransitions) break;
				}
			}
		}
		return _htmltransitions;
	}

	this.CheckFlash = function (id, domId, width, height, dynamicImages)
	{
		// ----------------------------------------------------------------------------------------------------
		// Flash detection code from: http://www.featureblend.com/javascript-flash-detection-library.html
		// http://www.featureblend.com/license.txt
		var FlashDetect = new function ()
		{
			var self = this; self.installed = false; self.raw = ""; self.major = -1; self.minor = -1; self.revision = -1; self.revisionStr = ""; var activeXDetectRules = [{ "name": "ShockwaveFlash.ShockwaveFlash.7", "version": function (obj) { return getActiveXVersion(obj); } }, { "name": "ShockwaveFlash.ShockwaveFlash.6", "version": function (obj)
			{
				var version = "6,0,21"; try { obj.AllowScriptAccess = "always"; version = getActiveXVersion(obj); } catch (err) { }
				return version;
			}
			}, { "name": "ShockwaveFlash.ShockwaveFlash", "version": function (obj) { return getActiveXVersion(obj); } }]; var getActiveXVersion = function (activeXObj)
			{
				var version = -1; try { version = activeXObj.GetVariable("$version"); } catch (err) { }
				return version;
			}; var getActiveXObject = function (name)
			{
				var obj = -1; try { obj = new ActiveXObject(name); } catch (err) { obj = { activeXError: true }; }
				return obj;
			}; var parseActiveXVersion = function (str) { var versionArray = str.split(","); return { "raw": str, "major": parseInt(versionArray[0].split(" ")[1], 10), "minor": parseInt(versionArray[1], 10), "revision": parseInt(versionArray[2], 10), "revisionStr": versionArray[2] }; }; var parseStandardVersion = function (str) { var descParts = str.split(/ +/); var majorMinor = descParts[2].split(/\./); var revisionStr = descParts[3]; return { "raw": str, "major": parseInt(majorMinor[0], 10), "minor": parseInt(majorMinor[1], 10), "revisionStr": revisionStr, "revision": parseRevisionStrToInt(revisionStr) }; }; var parseRevisionStrToInt = function (str) { return parseInt(str.replace(/[a-zA-Z]/g, ""), 10) || self.revision; }; self.majorAtLeast = function (version) { return self.major >= version; }; self.minorAtLeast = function (version) { return self.minor >= version; }; self.revisionAtLeast = function (version) { return self.revision >= version; }; self.versionAtLeast = function (major) { var properties = [self.major, self.minor, self.revision]; var len = Math.min(properties.length, arguments.length); for (i = 0; i < len; i++) { if (properties[i] >= arguments[i]) { if (i + 1 < len && properties[i] == arguments[i]) { continue; } else { return true; } } else { return false; } } }; self.FlashDetect = function () { if (navigator.plugins && navigator.plugins.length > 0) { var type = 'application/x-shockwave-flash'; var mimeTypes = navigator.mimeTypes; if (mimeTypes && mimeTypes[type] && mimeTypes[type].enabledPlugin && mimeTypes[type].enabledPlugin.description) { var version = mimeTypes[type].enabledPlugin.description; var versionObj = parseStandardVersion(version); self.raw = versionObj.raw; self.major = versionObj.major; self.minor = versionObj.minor; self.revisionStr = versionObj.revisionStr; self.revision = versionObj.revision; self.installed = true; } } else if (navigator.appVersion.indexOf("Mac") == -1 && window.execScript) { var version = -1; for (var i = 0; i < activeXDetectRules.length && version == -1; i++) { var obj = getActiveXObject(activeXDetectRules[i].name); if (!obj.activeXError) { self.installed = true; version = activeXDetectRules[i].version(obj); if (version != -1) { var versionObj = parseActiveXVersion(version); self.raw = versionObj.raw; self.major = versionObj.major; self.minor = versionObj.minor; self.revision = versionObj.revision; self.revisionStr = versionObj.revisionStr; } } } } } ();
		};
		FlashDetect.JS_RELEASE = "1.0.4";
		// ----------------------------------------------------------------------------------------------------

		if (FlashDetect.installed && FlashDetect.major >= 9) return;

		var ajax = tsAjax.createInstance('ImageRotator_' + domId);
		ajax.method = 'post';
		ajax.postData = 'action=imagerotatorfallback&id=' + id + '&domid=' + domId + '&width=' + width + '&height=' + height + '&dynimages=' + dynamicImages;
		tsAjax.innerHTML('/publicajax.ashx?ts=' + (new Date().getTime()), 'tsAjax', 'ImageRotator_' + domId, null, null, callback, true);

		function callback()
		{
			if (ajax.ajaxObj.readyState == 4)
			{
				var result = ajax.ajaxObj.responseText;
				result = eval('(' + result + ')');

				var temp = document.createElement('div');
				temp.innerHTML = result.html;

				var flash = document.getElementById('imagerotator_ie_' + domId);
				flash.parentNode.insertBefore(temp, flash);
				flash.parentNode.removeChild(flash);

				var html = temp.getElementsByTagName('div')[0];
				temp.parentNode.insertBefore(html, temp);
				temp.parentNode.removeChild(temp);

				var script = eval('(' + result.js + ')');
				ImageRotator(domId).Ready(script.images, script.settings);
			}
		}
    }


    this.ShowLightBox = function (lightBoxId, imageIndex)
    {
        var rotatorId = lightBoxId.replace('_lightbox', '');
        if (ImageRotator(rotatorId).ReInit)
        {
            // If ReInit method does not exist, the rotator is not fully loaded, hence we can't open it
            ImageRotator(rotatorId).ReInit(imageIndex);
            LightBox.Show(lightBoxId);
            if (typeof (_lightboxImageIndex[lightBoxId]) != 'undefined') _lightboxImageIndex[lightBoxId] = imageIndex;
            else _lightboxImageIndex[lightBoxId] = imageIndex;
        }
    }

    this.GetLightBoxStartIndex = function (lightBoxId)
    {
        if (typeof (_lightboxImageIndex[lightBoxId]) != 'undefined') return _lightboxImageIndex[lightBoxId];
        else return 0;
    }

    this.RegisterHtmlLightBox = function (domId)
    {
        _htmlLightBox[domId] = false;
    }

    this.InitHtmlLightBox = function (domId)
    {
        _htmlLightBox[domId] = true;
    }

    this.IsHtmlLightBoxLoaded = function (domId)
    {
        return typeof (_htmlLightBox[domId]) == 'undefined' || _htmlLightBox[domId] == true;
    }

    this.GetBasicGallery = function (id, trigger, interactionMode)
    {
        var isInsideLightBox = getElm(id + '_lightbox_Wrapper');
        var gallery = getElm('imagerotator_' + id + '_gallery');
        var marker = getElm('imagerotator_' + id + '_marker');
        var imgs = gallery.getElementsByTagName('img');
        var timer = null;
        var images = [];
        if (imgs.length > 0 && ImageRotator(id).GetLength() > 0)
        {
            var sourcepaths = ImageRotator(id).GetItem(0).Source.split('/');
            var source = sourcepaths[sourcepaths.length - 1];
            for (var i = 0; i < imgs.length; i++) images.push(imgs[i]);
            var start = new Date().getTime();
            while (images.length > 0 && images[0].src.indexOf(source) == -1)
            {
                var now = new Date().getTime();
                if (now - start > 1000)
                {
                    //alert('breaking infinite loop');
                    break;
                }
                images.push(images.shift());
            }
            for (var i = 0; i < images.length; i++)
            {
                if (trigger == 'click')
                {
                    images[i].onclick = new Function('ImageRotator(\'' + id + '\').ClearCommandQueue(); if(ImageRotator(\'' + id + '\').GetCurrentIndex() != ' + i + ') { ImageRotator(\'' + id + '\').Goto(' + i + '); }; ImageRotator(\'' + id + '\').Pause();');
                    if (interactionMode == 'running')
                    {
                        images[i].onmouseout = new Function('if(ImageRotator(\'' + id + '\').GetCurrentIndex() != ' + i + ')return;ImageRotator(\'' + id + '\').ClearCommandQueue();ImageRotator(\'' + id + '\').Start();');
                    }
                }
                else
                {
                    images[i].onmouseover = new Function('ImageRotator(\'' + id + '\').ClearCommandQueue();ImageRotator(\'' + id + '\').Goto(' + i + ');ImageRotator(\'' + id + '\').Pause();');
                    if (interactionMode == 'running')
                    {
                        images[i].onmouseout = new Function('if(ImageRotator(\'' + id + '\').GetCurrentIndex() != ' + i + ')return;ImageRotator(\'' + id + '\').ClearCommandQueue();ImageRotator(\'' + id + '\').Start();');
                    }
                }
            }
        }

        function getElm(elmId)
        {
            return (typeof(top.$elm) != 'undefined' && top.$elm(id + '_lightbox_Wrapper')) ? top.$elm(elmId) : $elm(elmId);
        }

        function showMarker()
        {
            if (images.length == 0 || ImageRotator(id).GetLength() == 0) return;
            var image = images[ImageRotator(id).GetCurrentIndex()];
            var addedWidth = 0;
            var addedHeight = 0;
            var subtractTop = 0;
            var subtractLeft = 0;
            var quirksmode = document.compatMode && document.compatMode == 'BackCompat';
            if (quirksmode)
            {
                if (!/quirksbox/.test(image.className)) image.className += (image.className.length > 0 ? ' quirksbox' : 'quirksbox');
                if (!/quirksbox/.test(marker.className)) marker.className += (marker.className.length > 0 ? ' quirksbox' : 'quirksbox');
                subtractTop = getStyleInt(marker, 'padding-top') + getStyleInt(marker, 'margin-top') + getStyleInt(marker, 'border-top-width');
                subtractLeft = getStyleInt(marker, 'padding-left') + getStyleInt(marker, 'margin-left') + getStyleInt(marker, 'border-left-width');
                addedWidth = getStyleInt(marker, 'padding-left') + getStyleInt(marker, 'padding-right') + getStyleInt(marker, 'border-left-width') + getStyleInt(marker, 'border-right-width');
                addedHeight = getStyleInt(marker, 'padding-top') + getStyleInt(marker, 'padding-bottom') + getStyleInt(marker, 'border-top-width') + getStyleInt(marker, 'border-bottom-width');
            }
            else
            {
                subtractTop = getStyleInt(marker, 'padding-top') + getStyleInt(marker, 'margin-top') + getStyleInt(marker, 'border-top-width');
                subtractLeft = getStyleInt(marker, 'padding-left') + getStyleInt(marker, 'margin-left') + getStyleInt(marker, 'border-left-width');
            }
            marker.style.visibility = 'visible';
            marker.style.top = (image.offsetTop - subtractTop) + 'px';
            marker.style.left = (image.offsetLeft - subtractLeft) + 'px';
            marker.style.width = (image.offsetWidth + addedWidth) + 'px';
            marker.style.height = (image.offsetHeight + addedHeight) + 'px';
            fadeUp(0);
        }
        function getStyleInt(elm, attribute)
        {
            var value = 0;
            if (document.defaultView && document.defaultView.getComputedStyle)
            {
                var styles = document.defaultView.getComputedStyle(elm, null);
                if (styles != null) value = styles.getPropertyValue(attribute);
            }
            else if (elm.currentStyle)
            {
                while (/([a-z])-([a-z])/.test(attribute)) attribute = attribute.replace(/([a-z])-([a-z])/, RegExp.$1 + RegExp.$2.toUpperCase());
                value = elm.currentStyle[attribute];
            }
            if (!/\d/.test(value)) return 0;
            else value = parseInt(value, 10);
            return isNaN(value) ? 0 : value;
        }
        function setOpacity(opacity)
        {
            marker.style.opacity = (opacity / 100).toString();
            if (!isInsideLightBox)
            {
                // Filter should not be shown if inside lightbox - IE breaks if double filter is applied (lightbox already uses an opacity filter).
                if (typeof (document.createElement("div").style.opacity) == 'undefined')
                {
                    marker.style.filter = 'Alpha(Opacity=' + opacity + ')';
                }
            }
        }
        function fadeUp(opacity)
        {
            clearTimeout(timer);
            opacity = Math.min(100, opacity + 10);
            setOpacity(opacity);
            if (opacity < 100) timer = setTimeout(function () { fadeUp(opacity) }, 50);
        }
        function fadeDown(opacity)
        {
            clearTimeout(timer);
            if (!opacity) opacity = 100;
            opacity = Math.max(0, opacity - 20);
            setOpacity(opacity);
            if (opacity > 0) timer = setTimeout(function () { fadeDown(opacity) }, 50);
        }
        showMarker();
        ImageRotator(id).OnImageChange = showMarker;
        ImageRotator(id).OnImageEnd = fadeDown;
    }
}

function ImageRotatorImage(source)
{
	this.Source = source;
	this.Duration = 'inherit';
	this.Link = 'inherit';
	this.NewWindow = 'inherit';
	this.Name = source;
	this.Description = '';
	this.EditDate = null;
	var _transitions = null;
	this.AddTransition = function (id)
	{
		if (!_transitions) _transitions = [];
		_transitions.push(id);
	}
	this.GetTransitions = function ()
	{
		if (!_transitions) return 'inherit';
		else return _transitions.join(',');
	}
}

function ImageRotator(id, isNew)
{
	var _debug, _isBusy, _isPaused, _images, _currentIndex;
	var _transitions = null;
	var _lightBoxContext = false;   // Is the rotator running inside a lightbox
    var _lightBoxState = null;      // What is the state of the lightbox (open|closed)

	if (isNew)
	{
		this.OnImageChange = null;
		this.OnImageBegin = null;
		this.OnImageEnd = null;
		this.OnReady = null;
		this.IsReady = function () { return false; }
		this.Ready = function (imagesJSON, stateJSON)
		{
		    var that = this;
		    function ready()
		    {
		        if (window.loaded && Tangora.ImageRotatorManager.IsHtmlLightBoxLoaded(id))
		        {
		            init(that, imagesJSON, stateJSON);
		            if (that.OnReady) that.OnReady(id);
		            if (/admin\/designer\.aspx/i.test(location.href))
		            {
                        // force the rotator paused in Visual Designer context...
		                that.ClearCommandQueue();
		                that.Pause();
		            }
		        }
		        else
		        {
		            setTimeout(ready, 100);
		        }
		    }
		    ready();
		}
		return this;
	}
	else
	{
        return Tangora.ImageRotatorManager.GetInstance(id);
    }

    function showLightBoxWrapper()
    {
        var objectElm = $elm('#' + id + '_lightbox_Wrapper object');
        if (objectElm) return; // LightBox is supported by HTML rotators only...

//        var lightboxWrapper = $elm(id + '_loadwrapper');
//        if (lightboxWrapper)
//        {
//            lightboxWrapper.style.opacity = 1;
//            if (typeof (document.createElement("div").style.opacity) == 'undefined') lightboxWrapper.style.filter = ''; // Pre IE9
//            $elm(id + '_lightbox_Wrapper').style.backgroundColor = '#ffffff';
//        }
        _lightBoxState = 'open';
        var index = Tangora.ImageRotatorManager.GetLightBoxStartIndex(id + '_lightbox');
        ImageRotator(id).ReInit(index);
    }


    function hideLightBoxWrapper()
    {
//        var lightboxWrapper = $elm(id + '_loadwrapper');
//        if (lightboxWrapper)
//        {
//            lightboxWrapper.style.opacity = 0;
//            if (typeof (document.createElement("div").style.opacity) == 'undefined') lightboxWrapper.style.filter = 'Alpha(Opacity=0)'; // Pre IE9
//            $elm(id + '_lightbox_Wrapper').style.backgroundColor = 'transparent';
//        }
        _lightBoxState = 'closed';
    }

	function init(obj, imagesJSON, stateJSON)
	{

	    // This method is called from flash, ensuring that flash is loaded and ready to accept commands from this API
        // In HTML rotators, this method is called when the DOM is ready
	    if (typeof (LightBox) != 'undefined' && $ts.exists(LightBox) && getElm(id + '_lightbox_Wrapper') && getElm('#' + id + '_lightbox_Wrapper object') == null)
	    {
	        // LightBox is supported by HTML rotators only...
	        $ts.Observer.UnRegister(id + '_lightbox', 'ShowComplete', showLightBoxWrapper);
	        $ts.Observer.UnRegister(id + '_lightbox', 'Closed', hideLightBoxWrapper);
	        $ts.Observer.Register(id + '_lightbox', 'ShowComplete', showLightBoxWrapper);
	        $ts.Observer.Register(id + '_lightbox', 'Closed', hideLightBoxWrapper);
	        _lightBoxContext = true;
	        _lightBoxState = 'closed';
	    }

		_debug = false;
		_isBusy = true;
		_isPaused = false;
		_images = [];
		_currentIndex = 0;
		_isHtmlFallback = false;

		updateState(stateJSON);
		updateImages(imagesJSON);

		var _object = document.getElementById('imagerotator_ie_' + id); // swf object as detected by ie
		if (_object && typeof (_object.Next) == 'undefined')
		{
			_object = document.getElementById('imagerotator_' + id); // swf  object as detected by firefox, chrome, safari etc
		}
		if (!_object || (_object && typeof (_object.Next) == 'undefined'))
		{
			_object = new HTMLalternative(stateJSON);
			_isHtmlFallback = true;
        }

		obj.Start = function () { return doChainCommand('start'); }
		obj.Pause = function () { return doChainCommand('pause'); }
		obj.Next = function () { return doChainCommand('next'); }
		obj.Previous = function () { return doChainCommand('previous'); }
		obj.Goto = function (index) { return doChainCommand('goto', index, _images.length - 1); }
		obj.Add = function (index, image) { checkIndex(index, _images.length); checkSize(); return doChainCommand('add', index, _images.length, image); }
		obj.Remove = function (index) { checkIndex(index, _images.length - 1); return doChainCommand('remove', index, _images.length - 1); }
		obj.ClearCommandQueue = function () { return doChainCommand('clear'); }
		obj.GetItem = function (index) { checkIndex(index, _images.length - 1); return _images[index]; }
		obj.GetLength = function () { return _images.length; }
		obj.GetCurrentIndex = function () { return _currentIndex; }
		obj.IsBusy = function () { return _isBusy; }
		obj.IsPaused = function () { return _isPaused; }
		obj.IsReady = function () { return true; }
		obj.ReInit = function (index) { _object.ReInit(index); }


		// Publicly exposed but not part of the API: Used for state-synch between flash and javascript, and for debugging...
		obj.StateChange = function (stateJSON) { updateState(stateJSON); }       // Called from flash when state changes
		obj.ImageChange = function (imagesJSON) { updateImages(imagesJSON); }    // Called from flash when images are added/removed
		obj.IndexChange = function (indexJSON) { debugIndex(indexJSON); }        // Called from flash when debug is on
		obj.QueueChange = function (queueJSON) { debugQueue(queueJSON); }        // Called from flash when debug is on
		obj.Debug = function () { _debug = true; showDebug(); _object.Debug(); }  // Shows debug window


		function checkIndex(index, maxIndex)
		{
			if (index != null && !/^\d+$/.test(index)) throw new Error('ImageRotator: Index must be an integer.');
			if (index < 0 || index > maxIndex) throw new Error('ImageRotator: Index out of bounds.');
		}

		function checkSize()
		{
			if (_images.length >= 64) throw new Error('ImageRotator: Cannot contain more than 64 images.');
		}

		function doChainCommand(cmd, index, maxIndex, image)
		{
		    if (index) checkIndex(index, maxIndex);
		    switch (cmd)
		    {
		        case 'start': _object.Start(); break;
		        case 'pause': _object.Pause(); break;
		        case 'next': _object.Next(); break;
		        case 'previous': _object.Previous(); break;
		        case 'goto': _object.Goto(index); break;
		        case 'add':
		            if (_isHtmlFallback) _object.Add(index, image);
		            else _object.Add(index, image.Source, image.Duration, image.Link, image.NewWindow, image.GetTransitions());
		            break;
		        case 'remove': _object.Remove(index); break;
		        case 'clear': _object.ClearCommandQueue(); break;
		        default: throw new Error('ImageRotator: Method not supported.'); break;
		    }
		    return obj;
		}

		function updateImages(json)
		{
			while (_images.length > 0) _images.shift(0, 1);
			var images = typeof (json) == 'object' ? json : eval('(' + json + ')');
			for (var i = 0; i < images.length; i++)
			{
				var image = new ImageRotatorImage(images[i].source);
				image.Duration = images[i].duration;
				image.Link = images[i].link;
				image.NewWindow = images[i].newwindow;
				for (var j = 0; j < images[i].transitions.length; j++)
				{
					image.AddTransition(images[i].transitions[j]);
				}
				if (typeof (images[i].editdate) != 'undefined') image.EditDate = new Date(images[i].editdate);
				if (typeof (images[i].name) != 'undefined') image.Name = images[i].name;
				if (typeof (images[i].description) != 'undefined') image.Description = images[i].description;
				_images.push(image);
			}
			if (_debug) debugImages();
		}

		function updateState(json)
		{
			var state = typeof (json) == 'object' ? json : eval('(' + json + ')');
			_isBusy = state.busy;
			_isPaused = state.paused;
			_currentIndex = state.currentindex;
			switch (state.event)
			{
				case "ImageChange": if (obj.OnImageChange) obj.OnImageChange(); break;
				case "ImageBegin": if (obj.OnImageBegin) obj.OnImageBegin(); break;
				case "ImageEnd": if (obj.OnImageEnd) obj.OnImageEnd(); break;
            }
            if (_debug) debugState(state);
        }

        function getElm(elmId)
        {
            return (typeof (top.$elm) != 'undefined' && top.$elm(id + '_lightbox_Wrapper')) ? top.$elm(elmId) : $elm(elmId);
        }

		function showDebug()
		{
			var div = document.getElementById('debugrotator');
			if (!div)
			{
				div = document.createElement('div');
				div.id = 'debugrotator';
				div.style.border = '#000 1px solid';
				div.style.backgroundColor = '#fff';
				div.style.padding = '10px'
				document.body.appendChild(div);

				var events = document.createElement('div');
				events.id = 'debugrotator_events';
				events.style.height = '200px';
				events.style.overflow = 'auto';
				events.style.marginBottom = '10px';
				events.innerHTML = '<table border="1" style="width:100%;border:1px solid #ccc;margin-bottom:10px;"><tr><th>Event</th><th>Busy</th><th>Paused</th><th>Current index</th></tr>&nbsp;</table>'
				div.appendChild(events);
				var sorting = document.createElement('div');
				sorting.id = 'debugrotator_sorting';
				div.appendChild(sorting);
				var queue = document.createElement('div');
				queue.id = 'debugrotator_queue';
				div.appendChild(queue);
				var images = document.createElement('div');
				images.id = 'debugrotator_images';
				div.appendChild(images);
			}
		}

		function debugState(state)
		{
			var events = document.getElementById('debugrotator_events');
			if (!events) return;
			events.innerHTML = events.innerHTML.replace('&nbsp;', '&nbsp;<tr><td>' + state.event + '</td><td>' + state.busy + '</td><td>' + state.paused + '</td><td>' + state.currentindex + '</td></tr>');
		}

		function debugImages()
		{
			var div = document.getElementById('debugrotator_images');
			if (!div) return;

			var html = '<table border="1" style="width:100%;border:1px solid #ccc;margin-bottom:10px;"><tr><th>Index</th><th>Source</th><th>Duration</th><th>Link</th><th>New window</th><th>Transitions</th></tr>';
			for (var i = 0; i < _images.length; i++)
			{
				html += '<tr>';
				html += '<td>' + i + '</td>';
				html += '<td>' + _images[i].Source + '</td>';
				html += '<td>' + _images[i].Duration + '</td>';
				html += '<td>' + _images[i].Link + '</td>';
				html += '<td>' + _images[i].NewWindow + '</td>';
				html += '<td>' + _images[i].GetTransitions() + '</td>';
				html += '</tr>';
			}
			html += '</table>';
			div.innerHTML = html;
		}

		function debugIndex(indexJSON)
		{
			if (!_debug) return;
			var sorting = document.getElementById('debugrotator_sorting');
			if (!sorting) return;

			var state = eval('(' + indexJSON + ')');
			var html = '<table border="1" style="width:100%;border:1px solid #ccc;margin-bottom:10px;"><tr><th>Array</th><th>Stage</th><th>Index</th><th>Name</th></tr>';
			for (var i = 0; i < state.length; i++)
			{
				html += '<tr>';
				html += '<td>' + state[i].array + '</td>';
				html += '<td>' + state[i].stage + '</td>';
				html += '<td>' + state[i].index + '</td>';
				html += '<td>' + state[i].name + '</td>';
				html += '</tr>';
			}
			html += '</table>';
			sorting.innerHTML = html;
		}

		function debugQueue(queueJSON)
		{

			if (!_debug) return;
			var div = document.getElementById('debugrotator_queue');
			if (!div) return;

			var queue = eval('(' + queueJSON + ')');
			var html = '<table border="1" style="width:100%;border:1px solid #ccc;margin-bottom:10px;"><tr><th>Queue</th></tr>';
			for (var i = 0; i < queue.length; i++)
			{
				html += '<tr>';
				html += '<td>' + queue[i] + '</td>';
				html += '</tr>';
			}
			html += '</table>';
			div.innerHTML = html;
		}

		// =============================================================================================================================

		// HTML fallback:

		function HTMLalternative(json)
		{
			var transitions = Tangora.ImageRotatorManager.GetHtmlTransitions();
			var settings = typeof (json) == 'object' ? json : eval('(' + json + ')');
			var autoStart = settings.autostart;
			var randomStart = settings.randomstart;
			var previewTransitionMode = settings.previewtransition;
			var hideQueuedImages = settings.hidequeuedimages;
			var durationTimer = null;
			var durationStartTime = null;
			var startAfterPause = null;
			var commandQueue = [];

			// Public API

			this.Start = function ()
			{
				if (!_isBusy)
				{
					if (_isPaused)
					{
						if (startAfterPause) startAfterPause();
						startAfterPause = null;
					}
				}
				else
				{
					queueCommand(_object.Start);
				}
			}
			this.Pause = function ()
			{
			    if (!_isBusy)
			    {
			        if (!_isPaused)
			        {
			            _isPaused = true;
			            clearTimeout(durationTimer);

			            var timeElapsed = (durationStartTime) ? new Date().getTime() - durationStartTime : 0;
			            var timeLeft = Math.max(1, _images[_currentIndex].Duration - timeElapsed);

			            startAfterPause = function ()
			            {
			                durationTimer = setTimeout(swapImages, timeLeft);
			                durationStartTime = new Date().getTime() - timeElapsed;
			                startAfterPause = null;
			                _isPaused = false;
			            }
			        }
			    }
			    else
			    {
			        queueCommand(_object.Pause);
			    }
			}
			this.Next = function ()
			{
				if (!_isBusy)
				{
					swapImages();
				}
				else
				{
					queueCommand(_object.Next);
				}
			}
			this.Previous = function ()
			{
				if (!_isBusy)
				{
					var index = _currentIndex > 0 ? _currentIndex - 1 : _images.length - 1;
					gotoFunc(index);
				}
				else
				{
					queueCommand(_object.Previous);
				}
			}
			this.Goto = function (index)
			{
				if (!_isBusy)
				{
					gotoFunc(index);
				}
				else
				{
					queueCommand(_object.Goto, [index]);
				}
            }
			this.Add = function (index, image)
			{
				//if (!_isBusy && (_images.length == 0 || index != _currentIndex))
				if (!_isBusy)
				{
					if (image.Duration == 'inherit') image.Duration = settings.defaultduration;
					if (image.Link == 'inherit') link = image.Link = settings.defaultlink;
					if (image.NweWindow == 'inherit') image.NewWindow = settings.defaultnewwindow;
					if (image.GetTransitions() == 'inherit')
					{
						// TODO: - transitions not handled yet...
					}

					if (index == _images.length)
					{
						_images.push(image);
					}
					else
					{
						_images.splice(index, 0, image);
						for (var i = _images.length - 1; i > index; i--)
						{
							getImg(i - 1).setAttribute('id', id + '_' + i);
						}
					}

					var wrapper = document.getElementById('imagerotator_htmlwrapper_' + id);
					var img = document.createElement('img');
					img.id = id + '_' + index;
					img.src = image.Source;
					img.width = settings.width;
					img.height = settings.height;
					img.style.visibility = (hideQueuedImages) ? 'hidden' : 'visible';
					img.style.position = 'absolute';

					if (_images.length == 0 || index == _images.length - 1)
					{
						wrapper.appendChild(img);
					}
					else
					{
						wrapper.insertBefore(img, getImg(index + 1));
					}
					setCssIndexOrder();
				}
				else
				{
					queueCommand(_object.Add, [index, image]);
				}
			}
			this.Remove = function (index)
			{
				if (!_isBusy && (_images.length == 1 || index != _currentIndex))
				{
					_images.splice(index, 1);
					var img = getImg(index);
					img.parentNode.removeChild(img);
					for (var i = index; i < _images.length; i++)
					{
						var elm = document.getElementById(id + '_' + (i + 1));
						elm.setAttribute('id', id + '_' + i);
					}
					setCssIndexOrder();
					if (_images.length < 2)
					{
						ImageRotator(id).Pause();
						_currentIndex = 0;
					}
				}
				else
				{
					queueCommand(_object.Remove, [index]);
				}
			}
			this.ClearCommandQueue = function ()
			{
				while (commandQueue.length > 0) commandQueue.pop();
			}
			this.Debug = function ()
			{
				alert('Debug is not supported in HTML mode.\nUse DOM explorer instead.');
            }
            this.ReInit = function (forceToIndex)
            {
                init(forceToIndex);
            }

			function queueCommand(cmd, args)
			{
				if (!args) args = [];
				commandQueue.push([cmd, args]);
			}

			function executeCommandQueue()
			{
				// We need to only execute the number of queued commands present at this time, because looping through this, commands might be queued again.
				var cmdCount = commandQueue.length;
				for (var i = 0; i < cmdCount; i++)
				{
					var cmd = commandQueue.shift();
					if (typeof (cmd[0]) == 'function')
					{
						var argsCount = cmd[1].length;
						switch (argsCount)
						{
							case 0: cmd[0](); break;
							case 1: cmd[0](cmd[1][0]); break;
							case 2: cmd[0](cmd[1][0], cmd[1][1]); break;
							default: throw new Error('ImageRotator: Number of arguments not supported.');
						}
					}
				}
			}



            init();


			function init(forceToIndex)
			{   
			    if ($ts.exists(forceToIndex))
			    {
			        clearTimeout(durationTimer);
			        durationStartTime = null;

			        for (var i = 0; i < _images.length; i++)
			        {
			            getElm(id + '_' + i).style.visibility = 'hidden';
			        }

			        getElm(id + '_' + forceToIndex).style.visibility = 'visible';
			        _currentIndex = forceToIndex;
			        setCssIndexOrder();   
			    }
                else if (randomStart)
                {
                    _currentIndex = Math.floor(Math.random() * _images.length);
					setCssIndexOrder();
				}

				if (previewTransitionMode) _isPaused = false;
				else _isPaused = !autoStart || _images.length < 2;

				if (_isPaused)
				{
					startAfterPause = function ()
					{
						durationTimer = setTimeout(swapImages, _images[_currentIndex].Duration);
						durationStartTime = new Date().getTime();
						startAfterPause = null;
						_isPaused = false;
					}
				}

				if (_images.length == 0)
				{
					// waiting for images to added via the API
					_isBusy = false;
					return;
				}


	            if (hideQueuedImages)
				{
				    // if queued images are not visible, run transition in on the first image (except if opened via a lightbox - it just looks ugly)
				    if (!$ts.exists(forceToIndex))
				    {
				        doTransition('in', startDuration);
				    }
					// make sure image is visible but after transition is started to avoid flicker (this is normally handled in the goto function except for this first transition)
				    getCurrImg().style.visibility = 'visible';

                    // if inside lightbox and not paused, start rotator
				    if ($ts.exists(forceToIndex) && !_isPaused)
				    {
				        startDuration();
				    }
				}
				else
				{
                    // show all images
				    for (var i = 0; i < _images.length; i++ )
				    {
				        getElm(id + '_' + i).style.visibility = 'visible';
				    }

				    // if queued images are visible, skip first transition in and start with duration
					startDuration();
	            }

	            if ($ts.exists(forceToIndex))
	            {
	                if (obj.OnImageChange) obj.OnImageChange();
	            }
			}

			// ------------------------------------------------


			function getCurrImg() { return getElm(id + '_' + _currentIndex); }
			function getNextImg() { return getElm(id + '_' + (_currentIndex < _images.length - 1 ? _currentIndex + 1 : 0)); }
			function getPrevImg() { return getElm(id + '_' + (_currentIndex > 0 ? _currentIndex - 1 : _images.length - 1)); }
			function getImg(index) { return getElm(id + '_' + index); }


			function startDuration()
			{
				var objImg = _images[_currentIndex];
				var elmImg = getCurrImg();

				getCurrImg().style.visibility = 'visible';

				// activating link if any
				if (objImg.Link != '')
				{
					elmImg.onclick = function ()
					{
						if (objImg.NewWindow) window.open(objImg.Link, 'rotatorimage' + _currentIndex + '_link', 'location=1,resizable=1,toolbar=1,scrollbars=1,status=1');
						else location.href = objImg.Link;
					}
					elmImg.style.cursor = 'pointer';
				}

	            // beginning duration if not paused
				if (!_isPaused)
				{
				    // if rotator is inside a lightbox and the lightbox is not opened yet, don't run the rotator
				    if (!_lightBoxContext || (_lightBoxContext && _lightBoxState == 'open'))
				    {
				        durationTimer = setTimeout(swapImages, objImg.Duration);
				        durationStartTime = new Date().getTime();
				    }
				}

				// dispatching OnImageBegin event if subscriber
				if (obj.OnImageBegin) obj.OnImageBegin();

				_isBusy = false;

				executeCommandQueue();
			}


			function gotoFunc(index)
			{
				if (!previewTransitionMode && _images.length < 2) return;

				_isBusy = true;

				clearTimeout(durationTimer);
				durationStartTime = null;

				// dispatching OnImageEnd event if subscriber
				if (obj.OnImageEnd) obj.OnImageEnd();

				var oldImg = getCurrImg();
				var newImg = getImg(index);

				// clearing link on old image
				oldImg.onclick = null;
				oldImg.style.cursor = 'default';

				// resetting all images z-index
				for (var i = 0; i < _images.length; i++) getImg(i).style.zIndex = 0;

				// setting old and new z-index
				oldImg.style.zIndex = _images.length;
				newImg.style.zIndex = _images.length - 1;

				// transition old image out
				doTransition('out', callbackTransitionOutComplete);

				function callbackTransitionOutComplete()
				{
					if (hideQueuedImages)
					{
						oldImg.style.visibility = 'hidden';
					}

					newImg.style.visibility = 'hidden';

					// Set old behind new
					oldImg.style.zIndex = _images.length - 1;
					newImg.style.zIndex = _images.length;

					_currentIndex = index;

					// dispatching OnImageChange event if subscriber
					if (obj.OnImageChange) obj.OnImageChange();

					// transition new image in
					doTransition('in', callbackTransitionInComplete);
					getCurrImg().style.visibility = 'visible';
				}

				function callbackTransitionInComplete()
				{
					// reordering the images z-index
				    setCssIndexOrder();
					startDuration();
				}
			}


			function setCssIndexOrder()
			{
				if (_images.length < 2) return;
				getCurrImg().style.zIndex = _images.length;
				var zIndex = _images.length - 1;
				var imgIndex = _currentIndex + 1;
				while (imgIndex < _images.length)
				{
					getImg(imgIndex).style.zIndex = zIndex;
					imgIndex++;
					zIndex--;
				}
				imgIndex = 0;
				while (imgIndex < _currentIndex)
				{
					getImg(imgIndex).style.zIndex = zIndex;
					imgIndex++;
					zIndex--;
				}
			}

			function swapImages()
			{
				var index = _currentIndex < _images.length - 1 ? _currentIndex + 1 : 0;
				gotoFunc(index);
			}

			function doTransition(direction, callback)
			{
				var trans = null;
				if (previewTransitionMode)
				{
					if (settings.previewtransitionobj.direction == direction) trans = settings.previewtransitionobj;
				}
				else
				{
					var transArray = _images[_currentIndex].GetTransitions().split(',');
					for (var i = 0; i < transArray.length; i++)
					{
						if (transArray[i] == '-1')
						{
							// Default HTML fallback when no other fallback is specified...
							if (direction == 'in') trans = getDefaultFallbackTransition(direction);
							else if (hideQueuedImages) trans = getDefaultFallbackTransition(direction);
						}
						else
						{
							if (typeof (transitions['trans_' + transArray[i]]) == 'undefined') continue;
							if (transitions['trans_' + transArray[i]].direction == direction)
							{
								trans = transitions['trans_' + transArray[i]];
								break;
							}
						}
					}
				}
				if (!trans)
				{
					// if no transition found just call the callback and leave...
					callback();
					return;
				}
				var funcs = [];
				var resetFuncs = [];
				var funcsCompleted = 0;
				for (var i = 0; i < trans.effects.length; i++)
				{
					var func = null;
					switch (trans.effects[i].name)
					{
					    case 'htmlfade':
					        // Html fade should not be shown in lightbox context for IE8 and below. Double opacity filters screws it up...
                            var temp = Tangora.Browser.GetType(); // just a temporary fix to get Tangora.Browser working if it is lazy loaded...
                            if (!Tangora.Browser.IE || (Tangora.Browser.IE && ScriptEngineMajorVersion() >= 9) || !getElm(id + '_lightbox_Wrapper'))
					        {
					            funcs.push(htmlfade);
					        }
					        break;
						case 'htmlwipe': funcs.push(htmlwipe); break;
					}
				}
				// executing each of the effect functions
				if (funcs.length > 0)
				{
					for (var i = 0; i < funcs.length; i++) funcs[i](direction, trans.duration, trans.effects[i], internalCallback);
				}
				else callback();
				// called from effect functions
				function internalCallback(resetFunc)
				{
					resetFuncs.push(resetFunc);
					funcsCompleted++;
					if (funcsCompleted == funcs.length)
					{
						for (var i = 0; i < resetFuncs.length; i++) resetFuncs[i]();
						callback();
					}
				}
			}

			function ease(type, direction, val)
			{
				if (direction == 'in') val = 100 - val;
				var retval = val;
				switch (type)
				{
					case 'regular':
						var log = 10;
						retval = (Math.log(((val * log) / 100) + 1) / Math.log(log)) * 100;
						break;
					case 'strong':
						var log = 50;
						retval = (Math.log(((val * log) / 100) + 1) / Math.log(log)) * 100;
						break;
				}
				if (direction == 'in') retval = 100 - retval;
				return Math.max(Math.min(retval, 100), 0);
			}

			function getDefaultFallbackTransition(direction)
			{
				var easing = {};
				easing.method = '';
				easing.type = 'none';
				var effect = {};
				effect.name = 'htmlfade';
				effect.easing = easing;
				var trans = {};
				trans.direction = direction;
				trans.duration = 1000;
				trans.effects = [];
				trans.effects.push(effect);
				return trans;
			}


			// Transitions effects ------------------------------------------------------

			function htmlfade(direction, duration, effect, callback)
			{
				var elm = getCurrImg();
				var startTime = new Date().getTime();
				var opacity = direction == 'in' ? 0 : 100;
				var timer = null;
				fade();
				function fade()
				{
					var elapsed = new Date().getTime() - startTime;
					var percent = Math.max(Math.min((elapsed / duration) * 100, 100), 0);
					var dist = ease(effect.easing.type, effect.easing.method, Math.floor(percent));
					opacity = direction == 'in' ? Math.floor(dist) : Math.floor(100 - dist);
					setOpacity();
					if ((direction == 'in' && opacity < 100) || (direction == 'out' && opacity > 0)) timer = setTimeout(fade, 10);
					else callback(reset);
				}
				function setOpacity()
				{
					elm.style.opacity = (opacity / 100).toString();

					//if (navigator.userAgent.indexOf('MSIE') != -1)
					if (typeof (document.createElement("div").style.opacity) == 'undefined')
					{
						// IE 8 and below - elm needs to be visible to have filter applied....
						var visibility = elm.style.visibility;
						elm.style.visibility = 'visible';
						elm.style.filter = 'Alpha(Opacity=' + opacity + ')';
						elm.style.visibility = visibility;
					}
				}
				function reset()
				{
					if (timer) clearTimeout(timer);
					opacity = 100;
					setOpacity();
                    // IE gives paint bugs if opacity filter is set inside lightbox (which also has an opacity filter)
					var visibility = elm.style.visibility;
					elm.style.visibility = 'visible';
					elm.style.filter = '';
					elm.style.visibility = visibility;
				}
			}

			function htmlwipe(direction, duration, effect, callback)
			{
				var elm = getCurrImg();
				var startTime = new Date().getTime();
				var top = 0;
				var right = elm.width;
				var bottom = elm.height;
				var left = 0;
				var timer = null;
				wipe();
				function wipe()
				{
					var elapsed = new Date().getTime() - startTime;
					var percent = Math.max(Math.min((elapsed / duration) * 100, 100), 0);
					var dist = ease(effect.easing.type, effect.easing.method, Math.floor(percent));
					switch (effect.startpointvertical)
					{
						case 'top':
							bottom = Math.floor((dist * elm.height) / 100);
							if (direction == 'out') bottom = elm.height - bottom;
							break;
						case 'bottom':
							top = Math.floor(elm.height - ((dist * elm.height) / 100));
							if (direction == 'out') top = elm.height - top;
							break;
					}
					switch (effect.startpointhorizontal)
					{
						case 'left':
							right = Math.floor((dist * elm.width) / 100);
							if (direction == 'out') right = elm.width - right;
							break;
						case 'right':
							left = Math.floor(elm.width - ((dist * elm.width) / 100));
							if (direction == 'out') left = elm.width - left;
							break;
					}
					elm.style.clip = 'rect(' + top + 'px,' + right + 'px,' + bottom + 'px,' + left + 'px)';
					if (percent >= 100) callback(reset);
					else timer = setTimeout(wipe, 10);
				}
				function reset()
				{
					if (timer) clearTimeout(timer);
					elm.style.clip = 'rect(auto, auto, auto, auto)';
				}
			}
		}
	}
}

