/*
	HME JavaScript Tiler Library
	Copyright 2008 Michał Andrzej Woźniak <rysiek_at_rysiek.ath.cx>

	Dual-licensed under:
	- Creative Commons Attribution-ShareAlike License
	  [http://creativecommons.org/licenses/by-sa/2.0/]
	- Affero General Public License
	  [http://www.gnu.org/licenses/agpl.txt]

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

// silnik jest includowany?
if (typeof HME_ENGINE_INCLUDED == 'undefined') {
	// nie jest - plujemy się!
	alert('Please include the HME Javascript Engine Library (usually named engine.js)!');

// znacznik, że już ten plik został includowany
} else if (typeof HME_TILER_ENGINE_INCLUDED == 'undefined') {
	/* --- flaga "jestem" ------------------------------------------------------ */
	var HME_TILER_ENGINE_INCLUDED = true;

	// magiczna klasa tilera
	function hmeTiler(aXTiles, aYTiles, aParent, aTop, aLeft, aWidth, aHeight, aZBase) {

		// dom objects used
		var _parent   = (aParent) ? aParent : false
		var _dom      = new Object()
		var _img      = new Image()

		// private fields
		var _data      = new Object()
		var _state     = new Object()
		var _settings  = new Object()
		var _events    = new Object()
		var _callbacks = new Object()

		// data
		_data.x = (aTop) ? aTop : 0
		_data.y = (aLeft) ? aLeft : 0
		_data.w = (aWidth) ? aWidth : 0
		_data.h = (aHeight) ? aHeight : 0
		_data.z = (aZBase) ? aZBase : 0
		// tiles
		_data.tiles = new Object()
		_data.tiles.x_num = aXTiles
		_data.tiles.y_num = aYTiles
		_data.tiles.w = (aWidth) ? _data.w / _data.tiles.x_num : -1
		_data.tiles.h = (aHeight) ? _data.h / _data.tiles.y_num : -1
		_data.tiles.sets = 2
		// static
		_data.static = new Object()
		_data.static.x = (aTop) ? true : false
		_data.static.y = (aLeft) ? true : false
		_data.static.w = (aWidth) ? true : false
		_data.static.h = (aHeight) ? true : false
		_data.static.z = (aZBase) ? true : false
		// images
		_data.images   = new Array()

		// callbacks
		_callbacks.tile_opacity   = false
		_callbacks.tile_steps     = false
		_callbacks.get_next_image = false

		// settings
		// timeouts and intervals
		_settings.timeouts = new Object()
		_settings.timeouts.download          = 10000
		_settings.timeouts.display           = 5000
		_settings.timeouts.transition_step   = 20
		// transition settings
		_settings.transition = new Object()
		_settings.transition.max_count       = 0
		_settings.transition.max_steps       = 100
		_settings.transition.min_steps       = 25
		// default step generating function settings
		_settings.tile_steps = new Object()
		_settings.tile_steps.max             = 50
		_settings.tile_steps.min             = 10
		// default opacity generating function settings
		_settings.tile_opacity = new Object()
		_settings.tile_opacity.max           = 1.0
		_settings.tile_opacity.min           = 0.7

		// flags and counters
		_state.initialised = false
		_state.flags       = new Object()
		_state.timeouts    = new Object()

		// events
		_events.on_start             = false
		_events.on_stop              = false
		_events.on_pause             = false
		_events.on_unpause           = false
		_events.on_transition_start  = false
		_events.on_transition_end    = false
		_events.on_transition_step   = false
		_events.on_image_load_start  = false
		_events.on_image_load        = false
		_events.on_download_timeout  = false
		_events.on_download_error    = false
		_events.on_display_timeout   = false

		/* --- inicjalizacja ----------------------------------------------------- */
		function doInitState() {
			// flagi działania
			_state.flags.running         = false
			_state.flags.paused          = false
			// flagi stanu
			_state.flags.img_loaded      = false
			_state.flags.img_timeout     = false
			_state.flags.display_timeout = false
			_state.flags.transitioned    = false
			// timeouty i intervale
			_state.timeouts.dispatcher   = false
			_state.timeouts.loader       = false
			_state.timeouts.display      = false
			// inne
			_state.active_tileset        = -1
			_state.next_tileset          = -1
			_state.step                  = -1
			_state.previous_image        = false
			_state.active_image          = false
			_state.loading_image         = false
			_state.transition_count      = 0
		}

		// generalna inicjalizacja
		function doInit() {
			dbgWrite('hmeTiler :: doInit()')
			doInitObjects()
			doInitState()
			_state.initialised = true
		}

		// inicjalizacja objectów
		function doInitObjects() {
			dbgWrite('hmeTiler ::doInitObjects() : start')
			doInitParent()
			dbgWrite('hmeTiler ::doInitObjects() : +- _parent : ' + _parent.tagName + ' : ' + _parent.clientWidth + ' : ' + _parent.clientHeight)
			doInitDimensions()
			doInitContainer()
			doInitTilesets()
			doInitTiles()
			// zapewniamy sobie, że nic się nie s... podczas resize'u
			addOnResizeHandler(doHandleOnResize)
		}

		//inicjalizacja parenta
		function doInitParent() {
			dbgWrite('hmeTiler :: doInitParent() : start')
			if (_parent) {
				dbgWrite('hmeTiler :: doInitParent() : +- _parent was set')
				if (typeof(aParent) == 'string') {
					dbgWrite('hmeTiler :: doInitParent() :    +- was a string: ' + _parent)
					_parent = findObj(_parent)
				}
			} else {
				dbgWrite('hmeTiler :: doInitParent() : +- _parent was not set; setting to body...')
				_parent = document.body
				dbgWrite('hmeTiler :: doInitParent() :    +- ' + _parent.tagName + ' : ' + _parent.clientWidth + ' : ' + _parent.clientHeight)
			}
		}

		// inicjalizacja rozmiarów itp
		function doInitDimensions() {
			// x
			if (!_data.static.x) {
				_data.x = getoffsetLeft(_parent)
				dbgWrite('hmeTiler :: left         : ' + _data.x)
			}
			// y
			if (!_data.static.y) {
				_data.y = getoffsetTop(_parent)
				dbgWrite('hmeTiler :: top          : ' + _data.y)
			}

			// szerokość
			if (!_data.static.w) {
				_data.w = _parent.clientWidth
				_data.tiles.w = _data.w / _data.tiles.x_num
				dbgWrite('hmeTiler :: width        : ' + _data.w)
				dbgWrite('hmeTiler :: tile width   : ' + _data.tiles.w)
			}
			// wysokość
			if (!_data.static.h) {
				_data.h = _parent.clientHeight
				_data.tiles.h = _data.h / _data.tiles.y_num
				dbgWrite('hmeTiler :: height       : ' + _data.h)
				dbgWrite('hmeTiler :: tile height  : ' + _data.tiles.h)
			}
			// z-index
			if (!_data.static.z) {
				if (_parent.style) {
					_data.z = _parent.style.zIndex
				} else {
					_data.z = 0
				}
				dbgWrite('hmeTiler :: z-index      : ' + _data.z)
			}
		}

		// inicjalizacja kontenera DOM
		function doInitContainer(aDimsOnly) {
			if (!aDimsOnly) {
				_dom.container                  = document.createElement('div')
				_dom.container.id               = 'hme_tiler_' + _parent.id + '_container'
			}
			_dom.container.style.position   = 'absolute'
			_dom.container.style.top        = _data.y + 'px'
			_dom.container.style.left       = _data.x + 'px'
			_dom.container.style.width      = _data.w + 'px'
			_dom.container.style.height     = _data.h + 'px'
			if (_data.z) _dom.container.style.zIndex     = _data.z
			if (!aDimsOnly) _parent.appendChild(_dom.container)
			// position fixes
			dx = _data.x - getoffsetLeft(_dom.container)
			dy = _data.y - getoffsetTop(_dom.container)
			if (dx != 0) _dom.container.style.left = (_data.x + dx) + 'px'
			if (dy != 0) _dom.container.style.top  = (_data.y + dy) + 'px'
		}

		// inicjalizacja zespołów płytek
		function doInitTilesets(aDimsOnly) {
			if (!aDimsOnly) _dom.tilesets = new Array()
			for (var i = 0; i < _data.tiles.sets; i++) {
				if (!aDimsOnly) {
					_dom.tilesets[i] = document.createElement('div')
					_dom.tilesets[i].id               = 'hme_tiler_' + _parent.id + '_tileset' + i
					_dom.tilesets[i].style.position   = 'absolute'
				}
				_dom.tilesets[i].style.top        = 0 + 'px'
				_dom.tilesets[i].style.left       = 0 + 'px'
				_dom.tilesets[i].style.width      = _data.w + 'px'
				_dom.tilesets[i].style.height     = _data.h + 'px'
				if (_data.z) _dom.tilesets[i].style.zIndex     = _z
				if (!aDimsOnly) _dom.container.appendChild(_dom.tilesets[i])
			}
		}

		// inicjalizacja płytek
		function doInitTiles(aDimsOnly) {
			// ile mamy zespołów?
			for (var i = 0; i < _data.tiles.sets; i++) {
				// tablica płytek w zespole
				if (!aDimsOnly) _dom.tilesets[i].tiles = new Array()
				// tworzymy - ile kolumn?
				for (var j = 0; j < _data.tiles.x_num; j++) {
					// tablica płytek w kolumnie
					if (!aDimsOnly) _dom.tilesets[i].tiles[j] = new Array()
					// ile wierszy?
					for (var k = 0; k < _data.tiles.y_num; k++) {
						if (!aDimsOnly) {
							_dom.tilesets[i].tiles[j][k] = document.createElement('div')
							_dom.tilesets[i].appendChild(_dom.tilesets[i].tiles[j][k])
							_dom.tilesets[i].tiles[j][k].start_step     = -1
							_dom.tilesets[i].tiles[j][k].end_step       = -1
							_dom.tilesets[i].tiles[j][k].target_opacity = -1
							// właściwości danego pola
							_dom.tilesets[i].tiles[j][k].style.position   = 'absolute'
							_dom.tilesets[i].tiles[j][k].style.opacity    = 0
							_dom.tilesets[i].tiles[j][k].style.filter  = 'alpha(opacity=0)';
						}
						// wymiary dla danego pola
						_dom.tilesets[i].tiles[j][k].x              = j * _data.tiles.w
						_dom.tilesets[i].tiles[j][k].y              = k * _data.tiles.h
						_dom.tilesets[i].tiles[j][k].style.top        = _dom.tilesets[i].tiles[j][k].y + 'px'
						_dom.tilesets[i].tiles[j][k].style.left       = _dom.tilesets[i].tiles[j][k].x + 'px'
						_dom.tilesets[i].tiles[j][k].style.width      = _data.tiles.w + 'px'
						_dom.tilesets[i].tiles[j][k].style.height     = _data.tiles.h + 'px'
					}
				}
			}
		}

		/* --- rozpoczynanie i kończenie ----------------------------------------- */
		function doStartTransition() {
			if (!_state.flags.running) return false
			_state.flags.display_timeout = false
			_state.transition_count++
			// jadziem
			doFireEvent(_events.on_transition_start)
			_state.timeouts.dispatcher = setInterval(function(){doDispatch()}, _settings.timeouts.transition_step)
		}

		function doEndTransition() {
			if (!_state.flags.running) return false
			dbgWrite('doEndTransition() :: transition ended!')
			// display timeout
			_state.timeouts.display = setTimeout(function(){doHandleDisplayTimeout()}, _settings.timeouts.display)
			// czyścimy ustawienia
			if (_state.active_tileset > 0) {
				for (var i = 0; i < _data.tiles.x_num; i++) {
					for (var j = 0; j < _data.tiles.y_num; j++) {
						_dom.tilesets[_state.active_tileset].tiles[i][j].style.opacity  =  0
						_dom.tilesets[_state.active_tileset].tiles[i][j].style.filter   = 'alpha(opacity=0)';
						_dom.tilesets[_state.active_tileset].tiles[i][j].start_step     = -1
						_dom.tilesets[_state.active_tileset].tiles[i][j].end_step       = -1
						_dom.tilesets[_state.active_tileset].tiles[i][j].target_opacity = -1
					}
				}
			}
			_state.active_tileset = _state.next_tileset
			_state.next_tileset   = -1
			_state.step           = -1
			_state.flags.transitioned = true
			doFireEvent(_events.on_transition_end)
			if ( (_state.flags.img_loaded) && (_state.flags.display_timeout) && (!_state.flags.paused) ) {
				dbgWrite('doEndTransition() :: +- running doMoveImages()...')
				doMoveImages()
				dbgWrite('doEndTransition() :: +- running doNextImage()...')
				doNextImage()
			}
		}

		function doGetImgSrc(anImg) {
			if (typeof(anImg) == 'number') {
				return _data.images[anImg]
			} else if (typeof(anImg) == 'string') {
				return anImg
			} else if ( (typeof(anImg) == 'object') && (typeof(anImg.src) == 'string') ) {
				return anImg.src
			} else {
				return false
			}
		}

		function doPrepareNextTileset() {
			if (!_state.flags.running) return false
			ix = (_data.w - _img.width) / 2
			iy = (_data.h - _img.height) / 2
			for (var i = 0; i < _data.tiles.x_num; i++) {
				for (var j = 0; j < _data.tiles.y_num; j++) {
					steps = _settings.tile_steps.min + ( Math.random() * (_settings.tile_steps.max - _settings.tile_steps.min))
					_dom.tilesets[_state.next_tileset].tiles[i][j].style.opacity  = 0
					_dom.tilesets[_state.next_tileset].tiles[i][j].style.filter   = 'alpha(opacity=0)';
					if (typeof(_callbacks.tile_steps) == 'function') {
						[_dom.tilesets[_state.next_tileset].tiles[i][j].start_step, _dom.tilesets[_state.next_tileset].tiles[i][j].end_step] = _callbacks.tile_steps(i, j, doGetData(), doGetSettings(), doGetState())
					} else {
						_dom.tilesets[_state.next_tileset].tiles[i][j].start_step     = Math.ceil(Math.random() * (_settings.transition.max_steps - steps))
						_dom.tilesets[_state.next_tileset].tiles[i][j].end_step       = Math.ceil(_dom.tilesets[_state.next_tileset].tiles[i][j].start_step + steps)
					}
					if (typeof(_callbacks.tile_opacity) == 'function') {
						_dom.tilesets[_state.next_tileset].tiles[i][j].target_opacity = _callbacks.tile_opacity(i, j, doGetData(), doGetSettings(), doGetState())
					} else {
						_dom.tilesets[_state.next_tileset].tiles[i][j].target_opacity = _settings.tile_opacity.min + (Math.random() * (_settings.tile_opacity.max - _settings.tile_opacity.min))
					}
					tix = ix - _dom.tilesets[_state.next_tileset].tiles[i][j].x
					tiy = iy - _dom.tilesets[_state.next_tileset].tiles[i][j].y
					_dom.tilesets[_state.next_tileset].tiles[i][j].style.background = 'url(\'' + doGetImgSrc(_state.active_image) + '\') no-repeat ' + tix + 'px ' + tiy + 'px'
				}
			}
		}

		function doNextImage(anImg) {
			if (!_state.flags.running) return false
			// nie chcemy zbyt dużo ;)
			if ( (_settings.transition.max_count > 0) && (_state.transition_count >= _settings.transition.max_count) ) {
				return false
			}
			// flagi
			_state.flags.img_loaded      = false
			// przechodzimy, czy tylko ładujemy obrazek?
			dbgWrite('doNextImage() :: next : ' + _state.active_image + ' [' + typeof(_state.active_image) + ']')
			var perform_transition = (typeof(_state.active_image) != 'boolean')
			if (perform_transition) {
				dbgWrite('doNextImage() :: +- with transition')
				// flagi
				_state.flags.transitioned    = false
				_state.flags.display_timeout = false
				// na co przechodzimy?
				_state.next_tileset = (_state.active_tileset >= _data.tiles.sets - 1) ? 0 : (_state.active_tileset + 1)
				// przygotowanie
				doPrepareNextTileset()
			} else {
				// flagi
				_state.flags.transitioned    = true
				_state.flags.display_timeout = true
			}
			// ładujemy następny obrazek
			doStartLoadingNextImg(anImg)
			// jadziem!
			if (perform_transition) {
				doStartTransition()
			} else {
				dbgWrite('doNextImage() :: +- without transition')
				_state.flags.display_timeout = true
			}
		}

		function doStartLoadingNextImg(anImg) {
			if (!_state.flags.running) return false
			dbgWrite('doStartLoadingNextImg() :: anImg : ' + anImg + ' [' + typeof(anImg) + ']')
			dbgWrite('doStartLoadingNextImg() :: active: ' + _state.previous_image + ' [' + typeof(_state.previous_image) + ']')
			// mamy podany na tacy?
			if (anImg) {
				dbgWrite('doStartLoadingNextImg() :: +- using anImg...')
				_state.loading_image = anImg
			// nie, musimy sobie znaleźć sami
			} else {
				// mamy callback?
				if (typeof(_callbacks.get_next_image) == 'function') {
					_state.loading_image = _callbacks.get_next_image()
					dbgWrite('doStartLoadingNextImg() :: +- callback: ' + _state.loading_image + '[' + typeof(_state.loading_image) + ']...')
				// nie - z tablicy
				} else if (typeof(_state.active_image) == 'number') {
					_state.loading_image = (_state.active_image >= _data.images.length - 1) ? 0 : (_state.active_image + 1)
					dbgWrite('doStartLoadingNextImg() :: +- by the numbers: ' + _state.loading_image + '[' + typeof(_state.loading_image) + ']')
					dbgWrite('doStartLoadingNextImg() ::    [ from : ' + _state.active_image + '; ' + _data.images.length + ' - 1]')
				} else {
					dbgWrite('doStartLoadingNextImg() :: +- default: 0')
					_state.loading_image = 0
				}
			}
			// rozpoczynamy ładowanie
			_state.flags.img_loaded = false
			if (typeof(_state.loading_image) == 'number') {
				_img.src = _data.images[_state.loading_image]
			} else {
				_img.src = _state.loading_image
			}
			dbgWrite('doStartLoadingNextImg() :: +- starting loading image: ' + _img.src + ' : ' + _state.loading_image)
			doFireEvent(_events.on_image_load_start)
			_state.timeouts.loader = setTimeout(function(){doHandleImgTimeout()}, _settings.timeouts.download)
		}

		function doMoveImages() {
			_state.previous_image     = _state.active_image
			_state.active_image       = _state.loading_image
			_state.loading_image    = false
			dbgWrite('doMoveImgs() :: +- _state.active_image   = ' + _state.active_image + ' [' + typeof(_state.active_image) + ']')
			dbgWrite('doMoveImgs() :: +- _state.previous_image = ' + _state.previous_image + ' [' + typeof(_state.previous_image) + ']')
			dbgWrite('*** doMoveImgs() :: END OF EVENT ***')
		}

		function doStart(aMaxCount) {
			// jesteśmy zainicjalizowani?
			if (!_state.initialised) {
				return false
			}
			// a może już działamy?
			if (_state.flags.running) {
				return false
			}
			_state.flags.running = true
			_state.flags.paused  = false
			_state.transition_count = 0
			if (aMaxCount > 0) {
				_settings.transition.max_count = aMaxCount
			} else {
				_settings.transition.max_count = 0
			}
			// jadziem
			_state.display_timeout = true
			doFireEvent(_events.on_start)
			doNextImage()
		}

		function doStop() {
			// jesteśmy zainicjalizowani?
			if (!_state.initialised) {
				return false
			}
			// czy działamy?
			if (!_state.flags.running) {
				return false
			}
			// czyścimy timeouty i interwały
			clearInterval(_state.timeouts.dispatcher)
			clearTimeout(_state.timeouts.loader)
			clearTimeout(_state.timeouts.display)
			// chowamy wsio
			for (var i=0; i<_data.tiles.x_num; i++)
				for (var j=0; j<_data.tiles.y_num; j++) {
					if (_state.active_tileset >= 0){
						_dom.tilesets[_state.active_tileset].tiles[i][j].style.opacity = 0
						_dom.tilesets[_state.active_tileset].tiles[i][j].style.filter  = 'alpha(opacity=0)';
					}
					if (_state.next_tileset >= 0) {
						_dom.tilesets[_state.next_tileset].tiles[i][j].style.opacity = 0
						_dom.tilesets[_state.next_tileset].tiles[i][j].style.filter  = 'alpha(opacity=0)';
					}
				}
			doFireEvent(_events.on_stop)
			// czyścimy zmienne stanu
			doInitState()
		}

		function doPause() {
			// jesteśmy zainicjalizowani?
			if (!_state.initialised) {
				return false
			}
			if (_state.flags.running) {
				_state.flags.paused = !_state.flags.paused
				if (!_state.flags.paused) {
					doFireEvent(_events.on_unpause)
					if ( (_state.flags.img_loaded) && (_state.flags.transitioned) && (_state.flags.display_timeout) ) {
						doMoveImages()
						doNextImage()
					}
				} else {
					doFireEvent(_events.on_pause)
				}
			}
		}

		/* --- dyspozytor -------------------------------------------------------- */
		function doDispatch() {
			if (!_state.flags.running) return false
			doFireEvent(_events.on_transition_step)
			// lokalne zmienne
			var ls = 0
			var ts = 0
			// który to już krok?
			_state.step++
			// magia pojawiania się i znikania
			for (var i = 0; i < _data.tiles.x_num; i++) {
				for (var j = 0; j < _data.tiles.y_num; j++) {
					// policzmy
					ls = _state.step - _dom.tilesets[_state.next_tileset].tiles[i][j].start_step
					ts = _dom.tilesets[_state.next_tileset].tiles[i][j].end_step - _dom.tilesets[_state.next_tileset].tiles[i][j].start_step
					if  ((ls >= 0) && (ls <= ts) ) {
						nop = (ls / ts) * _dom.tilesets[_state.next_tileset].tiles[i][j].target_opacity
						// zmiana na plus
						_dom.tilesets[_state.next_tileset].tiles[i][j].style.opacity = nop
						_dom.tilesets[_state.next_tileset].tiles[i][j].style.filter  = 'alpha(opacity=' + (nop * 100) + ')';
						// zmiana na minus
						if (_state.active_tileset > -1) {
							aop = (1 - (ls / ts)) * _dom.tilesets[_state.active_tileset].tiles[i][j].target_opacity
							_dom.tilesets[_state.active_tileset].tiles[i][j].style.opacity = aop
							_dom.tilesets[_state.active_tileset].tiles[i][j].style.filter  = 'alpha(opacity=' + (aop * 100) + ')';
						}
					}
				}
			}
			// jadziem dalej?
			if (_state.step >= _settings.transition.max_steps) {
				// nope - kończymy
				clearInterval(_state.timeouts.dispatcher)
				_state.timeouts.dispatcher = false
				doEndTransition()
			}
		}

		/* --- obsługa zdarzeń --------------------------------------------------- */
		function doHandleOnResize() {
			doInitDimensions()
			doInitContainer(true)
			doInitTiles(true)
			doInitTilesets(true)
		}

		function doHandleOnLoad() {
			// inicjalizacja
			doInit()
		}

		function doHandleImgOnLoad() {
			clearTimeout(_state.timeouts.loader)
			if (!_state.flags.running) return false
			_state.timeouts.loader   = false
			_state.flags.img_loaded = true
			doFireEvent(_events.on_image_load)
			dbgWrite('doHandleImgOnLoad()      :: img loaded!')
			if ( (_state.flags.display_timeout) && (_state.flags.transitioned) && (!_state.flags.paused) ) {
				dbgWrite('doHandleImgOnLoad() :: +- starting doMoveImages()...')
				doMoveImages()
				dbgWrite('doHandleImgOnLoad() :: +- starting doNextImage()...')
				doNextImage()
			}
		}

		function doHandleDisplayTimeout() {
			clearTimeout(_state.timeouts.display)
			if (!_state.flags.running) return false
			_state.timeouts.display      = false
			_state.flags.display_timeout = true
			doFireEvent(_events.on_display_timeout)
			dbgWrite('doHandleDisplayTimeout() :: display timeout!')
			if ( (_state.flags.img_loaded) && (_state.flags.transitioned) && (!_state.flags.paused) ) {
				dbgWrite('doHandleDisplayTimeout() :: +- starting doMoveImages()...')
				doMoveImages()
				dbgWrite('doHandleDisplayTimeout() :: +- starting doNextImage()...')
				doNextImage()
			}
		}

		function doHandleImgTimeout() {
			//_state.flags.img_timeout = true // zbędne? jak się tym zająć? załadować nowy obrazek? przerwać?..
			dbgWrite('doHandleImgTimeout() :: image download timeout!')
			doFireEvent(_events.on_download_timeout)
			//doStartLoadingNextImg()
		}

		/* --- narzędziówka ------------------------------------------------------ */
		function doFireEvent(anEvent) {
			if (typeof(anEvent) == 'function') anEvent(doGetData(), doGetSettings(), doGetState())
		}

		function doAddImg(anUrl) {
			// jesteśmy zainicjalizowani?
			if (!_state.initialised) {
				return false
			}
			var l = _data.images.length
			_data.images[l] = anUrl
			return l // return the current img id
		}

		function doGetRunning() {
			return _state.flags.running
		}

		function doGetPaused() {
			return _state.flags.paused
		}

		function doGetData() {
			return _data
		}

		function doGetSettings() {
			return _settings
		}

		function doGetState() {
			return _state
		}

		//
		_img.onload = doHandleImgOnLoad

		//
		this.init           = doInit

		//
		this.start          = doStart
		this.pause          = doPause
		this.stop           = doStop
		this.addImg         = doAddImg

		this.running        = doGetRunning
		this.paused         = doGetPaused

		// events, settings, etc
		this.events    = _events
		this.settings  = _settings
		this.callbacks = _callbacks
		this.getState  = function() { return _state }
		this.getData   = function() { return _data }
		this.getImage  = function() { return _img }
		this.getDom    = function() { return _dom }
		this.getParent = function() { return _parent }

		// inicjalizacja przy onload
		//addOnLoadHandler(doHandleOnLoad)
	}
}

