
var SWFHelper = new Object();

/**
 * Obsluga funkcji odpowiadajacych na zdarzenia
 * mva - obiekt flash z ktorym laczymy zdarzenia
 */
SWFHelper.CallbackHandler = function(/*Object*/flash, /*SWFObject*/mva) {
	
	var flash = flash;
	
	var mva = mva;

	var callbacks = {}
	
	/**
	 * Zwraca funkcje odpowiadajacam podanemu typowi zdarzenia
	 * type - typ zdarzenia
	 */
	this.getCallback = function(/*String*/type) /*Function*/
	{
		if(typeof callbacks[type] == 'function')
			return callbacks[type];
		return undefined;
	}

	/**
	 * Ustawia funkcje odpowiadajaca podanemu typowi zdarzenia
	 * type - typ zdarzenia
	 * func - funkcja do wywolania podczas zdarzenia
	 * args - ew. dodatkowe argumenty
	 */
	this.setCallback = function(/*String*/type, /*Function*/func, /*Arguments*/args)
	{
		// Do obiektu flash moze isc tylko 1 request dla jednego typu
		if(typeof callbacks[type] != 'function' && typeof func == 'function') {
			mva._request_cbs(type);
		} 

		// Ustawiamy callback
		callbacks[type] = function() { 
			func.apply(flash, (typeof args != 'undefined') ? args : arguments); 
		}
	}

	/**
	 * Usuwa funkcje odpowiadajaca podanemu typowi zdarzenia
	 * type - typ zdarzenia
	 */
	this.clearCallback = function(/*String*/type) 
	{
		// Do obiektu flash moze isc tylko 1 cancel dla jednego typu
		if(typeof callbacks[type] == 'function') {
			mva._cancel_cbs(type);
		}

		// usuwamy callback
		callbacks[type] = undefined;
	}

	this.toString = function() { return "SWFHelper.CallbackHandler()"; }
}

/**
 * ???
 */
SWFHelper.MenuHandler = function(/*Object*/flash, /*SWFObject*/mva) {

	var flash = flash;

	var mva = mva;
	
	var callbacks = {}

	var menuCount = 0;

	/**
	 * Zwraca funkcje odpowiadajacam podanemu id
	 * mid - id menu
	 */
	this.getCallback = function(/*String*/mid) /*Function*/
	{
		if(typeof callbacks[mid] == 'function')
			return callbacks[mid];
		return undefined;
	}
	
	/**
	 * Ustawia funkcje odpowiadajaca podanemu typowi zdarzenia
	 * mid - id menu
	 * func - funkcja do wywolania podczas zdarzenia
	 * args - ew. dodatkowe argumenty
	 */
	this.setCallback = function(/*String*/mid, /*Function*/func, /*Arguments*/args)
	{
        if (typeof mid != 'string') mid = "menu_" + menuCount++;
	
		// Ustawiamy callback
		callbacks[mid] = function() { 
			func.apply(flash, (typeof args != 'undefined') ? args : arguments); 
		}
		
		return mid;
	}

	/**
	 * Usuwa funkcje odpowiadajaca podanemu typowi zdarzenia
	 * type - typ zdarzenia
	 */
	this.clearCallback = function(/*String*/mid) 
	{
		// usuwamy callback
		callbacks[mid] = undefined;
	}

	/**
	 * ???
	 */
	this.isEmpty = function()
	{
		for(var id in callbacks)
			if(typeof callbacks[id] == 'function')
				return false;
		return true;
	}

	/**
	 * ???
	 */
	this.getMenuIds = function()
	{
		var result = [];
		for(var id in callbacks)
			if(typeof callbacks[id] == 'function')
				result.push(id);
		return result;
	}

	/**
	 * ???
	 */
	this.getHelper = function()
	{
		return function(tmp, type, mid, pt, mvaId) {
			var callee = callbacks[mid];
			if(callee != undefined) callee(type, pt, mvaId);
		}
	}

	this.toString = function() { return "SWFHelper.MenuHandler()"; }
}

/**
 * ???
 */
SWFHelper.MenuPOIHandler = function(/*Object*/flash, /*SWFObject*/mva) {

	var flash = flash;

	var mva = mva;
	
	var callbacks = {}

	var menuCount = 0;

	/**
	 * Zwraca funkcje odpowiadajacam podanemu id
	 * mid - id menu
	 */
	this.getCallback = function(/*String*/mid) /*Function*/
	{
		if(typeof callbacks[mid] == 'function')
			return callbacks[mid];
		return undefined;
	}
	
	/**
	 * Ustawia funkcje odpowiadajaca podanemu typowi zdarzenia
	 * mid - id menu
	 * func - funkcja do wywolania podczas zdarzenia
	 * args - ew. dodatkowe argumenty
	 */
	this.setCallback = function(/*String*/mid, /*Function*/func, /*Arguments*/args)
	{
        if (typeof mid != 'string') mid = "menu_" + menuCount++;
	
		// Ustawiamy callback
		callbacks[mid] = function() { 
			func.apply(flash, (typeof args != 'undefined') ? args : arguments); 
		}
		
		return mid;
	}

	/**
	 * Usuwa funkcje odpowiadajaca podanemu typowi zdarzenia
	 * type - typ zdarzenia
	 */
	this.clearCallback = function(/*String*/mid) 
	{
		// usuwamy callback
		callbacks[mid] = undefined;
	}

	/**
	 * ???
	 */
	this.isEmpty = function()
	{
		for(var id in callbacks)
			if(typeof callbacks[id] == 'function')
				return false;
		return true;
	}

	/**
	 * ???
	 */
	this.getMenuIds = function()
	{
		var result = [];
		for(var id in callbacks)
			if(typeof callbacks[id] == 'function')
				result.push(id);
		return result;
	}

	/**
	 * ???
	 */
	this.getHelper = function()
	{
		return function(tmp,type, pid, mid, mvaId) {

			var callee = callbacks[mid];
			if(callee != undefined) callee(type, pid);
		}
	}

	this.toString = function() { return "SWFHelper.MenuPOIHandler()"; }
}

/**
 * Implementacja pojedynczego obiektu flash
 * objectId - id obiektu flash w kodzie html
 * func - funkcja typu callback do inicjalizacji obiektu
 * args - argumenty dla opisanej wyzej funkcji
 */
SWFHelper.Flash = function(/*String*/objectId, /*Function*/func, /*Arguments*/args) {

	/**
	 * Id obiektu flash
	 */
	var objectId = objectId;

	/**
	 * ???
	 */	
	var defaultCoords = undefined;
	
	/**
	 * ???
	 */	
	var defaultScaleId = undefined;

	/**
	 * ???
	 */
	var homePoint = undefined;

	/**
	 * ???
	 */
	var objectData = undefined; 
	
	/**
	 * Dane aktualnie wysiwtlanej mapy.
	 */
	var routeData = undefined;

	/**
	 * Obiekt odpowiadajacy za komunikacje z flash-em
	 */
	var mva = function(objectId) {
		var result = undefined;
		if(document.getElementById) {
			var result = document.getElementById(objectId);
			if(result.localname == "OBJECT") {
				result = result.getElementsByTagName("embed")[0];
			}
		} else {
			result = document[objectId];
		}
		return result;
	} (objectId);
	if(mva == undefined) return;

	/**
	 * Informacja o tym czy poprawnie zainicjalizowano flash
	 */
	var initialised = function() {
		var result = false;
		if(typeof mva.ei_initialized == 'function') {
			result =  mva.ei_initialized();
		}
		return result;
	} ();
	if(initialised == false) return undefined;

	/**
	 * Obsluga funkcji typu callback dla roznych menu mapy
	 */
	var menuCallbacks = new SWFHelper.MenuHandler(this, mva);

	/**
	 * Obsluga funkcji typu callback dla roznych menu POI
	 */
	var menuPOICallbacks = new SWFHelper.MenuPOIHandler(this, mva);

	/**
	 * Obsluga funkcji typu callback dla roznych typow
	 */
	var callbacks = new SWFHelper.CallbackHandler(this, mva);

	/**
	 * Zwraca opis wersji interface
	 * return - opis wersji
	 */	
	this.getVersion = function() /*String*/
	{
		return mva.ei_version();
	}

	/**
	 * Ustaw punkt srodkowy widoku o typie S1992, oraz zmienia skale
	 * x, y - wspolzedne punktu srodkowego
	 * scale - numer kolejny skali (liczony od 0)
	 * time - czas (w ms) w jakim dokonuje sie przesuniecie (animacja)
	 * noAnim - bez animacji
	 */	
	this.setCoords = function(/*Number*/x, /*Number*/y, /*Short*/scale, /*Number*/time, /*Boolean*/noAnim) 
	{
		mva.mv_set_coords(x, y, scale, time, noAnim);
	}

	/**
	 * Zwraca wspolzedne punktu srodkowego jako wartosci typu S1992
	 * return - wspolzedne srodka w postaci tablicy 2-elemntowej
	 */
	this.getCoords = function() /*[Number, Number]*/ 
	{
		return mva.mv_get_coords();
	}

	/**
	 * Ustawia kategorie filtrowania POI wyswietlane we Flashu.
	 * 
	 */
	this.treeViewSetNodes = function(nodes) {
		mva.tree_view_set_nodes(nodes); 
	}

	/**
	 * ???
	 */
	this.defaultCoords = function() /*[Number, Number]*/
	{
		if(defaultCoords == undefined) {
			defaultCoords = this.getCoords();
		}	
		return defaultCoords;
	}

	/**
	 * Zwraca indeks aktualnie ustawionej skali (liczony od 0)
	 * return - indeks skali
	 */
	this.getScaleId = function() /*Short*/
	{	
		return mva.mv_get_scale();
	}

	/**
	 * ???
	 */
	this.getScaleDenom = function() /*Number*/
	{	
		return this.toScaleDenom(this.getScaleId());
	}

	/**
	 * ???
	 */
	this.defaultScaleId = function() /*Short*/
	{
		if(defaultScaleId == undefined) {
			defaultScaleId = this.getScaleId();
		}	
		return defaultScaleId;
	}

	/**
	 * ???
	 */
	this.defaultScaleDenom = function() /*Number*/
	{	
		return this.toScaleDenom(this.defaultScaleId());
	}

	/**
	 * ???
	 */
	this.toScaleId = function(/*Number*/denom) /*Short*/
	{
		return mva.mv_scale_denom_to_index(denom);
	}

	/**
	 * ???
	 */
	this.toScaleDenom = function(/*Short*/index) /*Number*/
	{
		return mva.mv_scale_index_to_denom(index);
	}

	/**
	 * ???
	 */
	this.setHomePoint = function(/*Array*/coords, /*Integer*/scale)
	{	
		homePoint = { 
			coords: coords || this.getCoords(), 
			scale: scale || this.getScaleDenom()
		}
	}
	
	/**
	 * ???
	 */
	this.getHomePoint = function() /*[coords:Array, scale:Integer]*/
	{
		return {
			coords: homePoint.coords,
			scale: homePoint.scale
		};
	}

	/**
	 * ???
	 */
	this.showHomePoint = function()
	{
		var coords = (homePoint != undefined) ? homePoint.coords : this.defaultCoords();
		var scale = (homePoint != undefined) ? homePoint.scale : this.defaultScaleDenom();
		this.setCoords(coords[0], coords[1], this.toScaleId(scale));
	}

	/**
	 * ???
	 */
	this.getCoverId = function() /*String*/
	{
		return mva.mv_get_layer_id();
	}
	
	/**
	 * ???
	 */
	this.setCoverId = function(/*String*/id)
	{
		mva.mv_set_layer_id(id);
	}

	/**
	 * Dopasuj mape do podanych wymiarow
	 * left, top, right, bottom - wymiary mapy
	 * part - ???
	 * areaOnly - ???
	 */
    this.fitBBox = function(/*Number*/left, /*Number*/top, /*Number*/right, /*Number*/bottom, /*Number*/part, /*Boolean*/areaOnly) 
    {
		part = (part == undefined) ? 1.0 : part;
        mva.mv_fit_bbox(left, top, right, bottom, part, areaOnly);
    }
    
	/**
	 * Przesun mape o zadany wektor
	 * dx, dy - wektor o jaki przesuwamy mape
	 * time - czas (w ms) w jakim dokonuje sie przesuniecie (animacja)
	 * noAnim - bez animacji
	 */
    this.pan = function(/*Number*/dx, /*Number*/dy, /*Number*/time, /*Boolean*/noAnim) 
    {
        mva.mv_pan(dx, dy, time, noAnim);
    }

	/**
	 * Zwraca informacje o aktualnych wymiarach widoku mapy jako S1992
	 * return - wymiary mapy
	 */
    this.getViewPort = function() /*[left:Integer, top:Integer, right:Integer, bottom:Integer]*/
    {
        return mva.mv_get_vp_ref();
    }

	/**
	 * Wlacza wyswietlanie kafelkow trasy
	 * routeId - id trasy
	 * left, top, right, bottom - bounding box trasy
	 */
	this.routeOn = function(/*String*/routeId, /*Number*/left, /*Number*/top, /*Number*/right, /*Number*/bottom) 
	{
		routeData = {
			routeId: routeId,
			left: left,
			top: top,
			right: right,
			bottom: bottom
		}
		mva.mv_route_on(routeId, left, top, right, bottom);
	}

	/**
	 * Wylacza wyswietlanie kafelkow trasy
	 */
	this.routeOff = function() 
	{
		routeData = undefined;
		mva.mv_route_off();
	}

	this.getRouteId = function()
	{
		return routeData == undefined ? undefined : routeData.routeId;
	}

	this.getRouteTop = function()
	{
		return routeData == undefined ? undefined : routeData.top;
	}

	this.getRouteLeft = function()
	{
		return routeData == undefined ? undefined : routeData.left;
	}

	this.getRouteBottom = function()
	{
		return routeData == undefined ? undefined : routeData.bottom;
	}

	this.getRouteRight = function()
	{
		return routeData == undefined ? undefined : routeData.right;
	}

	/**
	 *
	 */
	this.getObjectId = function()
	{
		return objectData == undefined ? undefined : objectData.objectId;
	}

	/**
	 *
	 */
	this.getObjectAddress = function()
	{
		return objectData == undefined ? undefined : objectData.address;
	}

	/**
	 * Ustawia punkty POI
	 * type - typ punktu POI (np. 'poi-r' - POI tras)
	 * POIs - lista punktow poi, przy czym kazdy element to [x:Number, y:Number, id:String, nr:Integer, title:String, body:String, radius:Number]
	 * scale - indeks skali przy jakiej widoczne beda punkty
	 * bbox - wymiary mapy w postaci [left:Integer, top:Integer, right:Integer, bottom:Integer]
	 * centre - punkt centralny mapy 
	 */
    this.setPOIs = function(/*String*/type, /*Array*/POIs, /*Short*/scale, /*BBox*/bbox, /*Array*/centre) 
    {
        mva.poi_set_pois(type, POIs, scale, bbox, centre);
    }

	/**
	 * Usuwa punkty POI
	 * type - typ punktu POI
	 * scale - indeks skali dla jakiej usunac punkty
	 */
    this.clearPOIs = function(type, scale) 
    {
        mva.poi_clear_pois(type, scale);
    }

	/**
	 * Zwraca liste pounktow POI
	 * type - typ punktow POI
	 */
    this.getPOIs = function(type) /*Array*/
    {
        return mva.poi_get_pois(type);
    }

	/**
	 * Pokazuje, lub ukrywa POI na podanej warstwie (danego typu)
	 * type - typ punktow POI (warstwa)
	 * doEnable - wlaczany (true), wylaczamy (false)
	 */
    this.enablePOIs = function(type, doEnable) 
    {
        mva.poi_enable(type, doEnable);
    }

	/**
	 * ???
	 */
	this.enableHistory = function(type, doEnable)
	{
		mva.poi_enable_history(type, doEnable);
	}

	/**
	 * ???
	 */
	this.enableRadius = function(type, doEnable)
	{
		mva.poi_enable_radius(type, doEnable);
	}

	/**
	 * Dodaje nowy POI
	 * type - typ punktow POI
	 * data - dane punktu w postaci [x:Number, y:Number, id:String, nr:Integer, title:String, body:String, radius:Number]
	 * scale - skala dla jakiej dodajemy POI
	 */
    this.addPOI = function(type, data, scale) 
    {
        mva.poi_add_poi(type, data, scale);
    }
    
	/**
	 * Usuwa konkretny punkt POI
	 * type - typ punktow POI
	 * pid - id POI do usuniecia
	 */
    this.removePOI = function(type, pid) 
    {
        mva.poi_remove_poi(type, pid);
    }
    
	/**
	 * Zwraca konkretny punkt POI 
	 * type - typ punktow POI
	 * pid - id POI ktorego dane maja byc zwrocone
	 * return - dane punktu POI
	 */
    this.getPOI = function(type, pid) /*[x:Number, y:Number, id:String, nr:Integer]*/
    {
        return mva.poi_get_poi(type, pid);
    }

	/**
	 * Zwraca funkcje odpowiadajacam podanemu typowi zdarzenia
	 * type - typ zdarzenia
	 */
	this.getCallback = function(/*String*/type) /*Function*/
	{
		return callbacks.getCallback(type);
	}

	/**
	 * Ustawia funkcje odpowiadajaca podanemu typowi zdarzenia
	 * type - typ zdarzenia
	 * func - funkcja do wywolania podczas zdarzenia
	 * args - ew. dodatkowe argumenty
	 */
	this.setCallback = function(/*String*/type, /*Function*/func, /*Arguments*/args)
	{
		callbacks.setCallback(type, func, args);
	}

	/**
	 * Usuwa funkcje odpowiadajaca podanemu typowi zdarzenia
	 * type - typ zdarzenia
	 */
	this.clearCallback = function(/*String*/type) 
	{
		callbacks.clearCallback(type);
	}

	/**
	 * ???
	 */
    this.requestPOIsUpdates = function(type, sizeFactor, shift, func) 
    {
		this.setCallback('pm_update_cb', func);
        mva.poi_request_updates(type, sizeFactor, shift);
    }
    
	/**
	 * ???
	 */
    this.cancelPOIsUpdates = function(type) 
    {
		this.clearCallback('pm_update_cb');
        mva.poi_cancel_updates(type);
    }
    
    /**
	 * Wywolanie dymka prostego
	 */
    this.simulatePoiMouseOver = function(type, poi_id)
	{
    	//console.log('handler.simulatePoiMouseOver, layer: ' + type + ', poi id: ' + poi_id);
		mva.simulate_poi_mouse_over(type, poi_id);
	}
	
	/**
	 * Opuszczenie pojki przez kursor
	 */
	this.simulatePoiMouseOut = function(type, poi_id)
	{
		mva.simulate_poi_mouse_out(type, poi_id);
	}
	
	/**
	 * Wywolanie dymka szczegolowego
	 */
	this.simulatePoiMouseClick = function(type, poi_id)
	{
		mva.simulate_poi_mouse_click(type, poi_id);
	}

	/**
	 * ???
	 */
    this.enablePOIsMenu = function(type, isPOI, menuId, isEnable) 
    {
        mva.poi_menu_enable(type, isPOI, menuId, isEnable);
    }

	/**
	 * ???
	 */
    this.getPOIMenuIds = function(isPOI) 
	{
		if(isPOI == true) {
			return menuPOICallbacks.getMenuIds();
		} else {
			return menuCallbacks.getMenuIds();
		}
	}

	/**
	 * ???
	 */
    this.addPOIsMenu = function(type, isPOI, menuId, caption, func) /*String*/
    {
    	var cbType = undefined;
    	var cbHandler = undefined;
		if(isPOI == true) {
			cbType = 'pm_poi_menu_selected';
			cbHandler = menuPOICallbacks;
		} else {
			cbType = 'pm_menu_selected';
			cbHandler = menuCallbacks;
		}
		menuId = cbHandler.setCallback(menuId, func);
		if(callbacks.getCallback(cbType) == undefined) 		
			callbacks.setCallback(cbType, cbHandler.getHelper());
    	mva.poi_menu_add(type, isPOI, menuId, caption);
		return menuId;
	}

	/**
	 * ???
	 */
    this.removePOIsMenu = function(type, isPOI, menuId) 
    {
    	var cbType = undefined;
    	var cbHandler = undefined;
		if(isPOI == true) {
			cbType = 'pm_poi_menu_selected';
			cbHandler = menuPOICallbacks;
		} else {
			cbType = 'pm_menu_selected';
			cbHandler = menuCallbacks;
		}
		cbHandler.clearCallback(menuId);
		if(cbHandler.isEmpty())				
			callbacks.clearCallback(cbType);
        mva.poi_menu_remove(type, isPOI, menuId);
	}

	/**
	 * ???
	 */
	var getWheelEventHandler = function(isAWK) 
	{
		return function(e) {
            if (mva != e.target) {
                e.returnValue = true;
                return;
            }

            var d = 0;
			if (!e) e = window.event;
            if (e.wheelDelta) {
                d = e.wheelDelta / 120;
                if (window.opera) d = -d;
            } else if (e.detail) {
                d = -e.detail / 3;
            }
            
            if (isAWK) d /= 3;
            if (d != 0) {
                try {
                    mva._ext_mw_event(d);
                } catch (err) {
                }
            }
            if (e.preventDefault) e.preventDefault();
            e.returnValue = false;
		}
	}

	/**
	 *
	 */
	var init = function() {
        if (typeof func == 'function') {
            try {
            	func.apply(this, (args != undefined) ? args : []);
            } catch (err) {
				// TODO Logowanie na konsole
                alert("Flash.init(" + [err.name, err.message] + ")");
            }
        }

	    //var isMac = (navigator.appVersion.toLowerCase().indexOf("mac") != -1);
	    if((typeof mva._ext_mw_event != 'undefined') && window.addEventListener) {
	        var isAWK = (navigator.userAgent.indexOf('AppleWebKit') != -1);
	        var wheel = getWheelEventHandler(isAWK);
	        window.addEventListener('DOMMouseScroll', wheel, false);
	        window.onmousewheel = document.onmousewheel = wheel;
		}
	};
	this.setCallback('mv_init', init);
	
	this.toString = function() { return "SWFHelper.Flash(" + objectId + ")"; }
}

/**
 * Obsluguje kilka instancji obiektow flash
 */
SWFHelper.FlashFactory = function() {
	
	/**
	 * Tablica przechowujaca obiekty obslugujace flash-e
	 */
	var flash = {};

	/**
	 * Zapisujemy wartosc this, gdyz jest ona zalezna od kontekstu,
	 * i nie zawsze mozemy poprawnie korzystac ze slowa kluczowego this
	 */
	var self = this;
	
	/**
	 * ???
	 */
	this.initFlash = function(/*String*/objectId, /*Function*/func, /*Arguments*/args) {
		flash[objectId] = [func, args];
	}
	
	/**
	 * ???
	 */
	this.getFlash = function(/*String*/objectId) {
		if(typeof flash[objectId] == 'undefined') return undefined;
		if(flash[objectId].constructor == Array)
			flash[objectId] = new SWFHelper.Flash(objectId, flash[objectId][0], flash[objectId][1]);
		return flash[objectId];
	}
	
	/**
	 * ???
	 */
	this.doCallback = function(/*String*/objectId, /*String*/callbackType) {
		//alert("doCallback(" + objectId + ", " + callbackType + ")");
		//console.debug(arguments);
		//if(arguments.length > 2)alert(arguments[2][1]);
		var callee = self.getFlash(objectId);
		var callback = callee.getCallback(callbackType);
		if(typeof callback == "function") {
	        try {
	        	var arr = new Array();
				if (arguments.length > 2) {
					for(var i=0; i< arguments[2].length; i++) {
						arr[i+1] = arguments[2][i];
					}
					arr[arr.length] = objectId;
					callback.apply(callee, arr);
				} else {
					arr[arr.length] = objectId;
					callback.apply(callee, arr);
				}
	        } catch (err) {
	            alert("FlashFactory.doCallback(" + [err.name, err.message] + ")");
	        }
		}
	}

	this.toString = function() { return "SWFHelper.FlashFactory()"; }
}

/**
 * Obiekt stworzony na potrzeby flash-a.
 */
var mv = new SWFHelper.FlashFactory();
mv.dispatch_flash_call = mv.doCallback;
