/**
	 * Klasa do obsługi Google Maps API
	 * 
	 * @class GMapsApi
	 * @author tomek
	 */
var GMapsAPI = function()
{
    if(!GBrowserIsCompatible())
    {
        alert("Przepraszamy, niestety twoja przeglądarka nie jest kompatybilna z mapami google.");
        return false;
    }
		
    /**
		 * Pole zawierające główny obiekt mapy API
		 * 
		 * @type GMap2
		 */
    var map;
		
    /**
		 * Pola obsługujące wyszukiwanie obiektów na mapie
		 * 
		 * @type GSSearchControl, GSLocalSearch
		 */
    var search, searcher;

    /**
		 * Zmienna określa czy główny obiekt API został już utworzony
		 * 
		 * @type bool 
		 */
    var init = false;
						
    /**
		 * Aktualny środek(punkt początkowy) mapy, zawiera obiekt 
		 * reprezentujący współrzędne geograficzne
		 * 
		 * @type GLatLng
		 */
    var center = new GLatLng(50.251613, 18.917531);
		
    /**
		 * Ustawia centralny punkt na mapie
		 * 
		 * @param latlng	GLatLng		Dane geograficzne(jako obiekt GLatLng)
		 * @param reset		bool		Jeżeli obiekt mapy jest już utworzony określa wycentrować widok w nowym punkcie
		 * @return void
		 */
    this.setCenter = function(latlng, reset)
    {
        if(latlng instanceof GLatLng)
        {
            center = latlng;
        }
			
        if(reset && init)
        {
            map.setCenter(center, this.zoom);
        }
    };

    /**
     * Tablica przechowująca ikony
     */
    var icons;

    /**
     * Wczytuje tablice ikon wg kategorii
     *
     * @param ico   Array   Tablica ikona w formacie { nazwa_kategorii: obiekt_GIcon(), ..}
     * @return void
     */
    this.setIcons = function(ico)
    {
        icons = ico;
    };
				
    /**
		 * Element w dokumencie, w którym umieści się automatycznie mapa 
		 */
    this.place = document.getElementById('map');

    /**
		 * Parametry mapy głównej
		 */
    this.params = {
        size: new GSize(600, 400)
    };

    /**
		 * Podstawowy zoom mapy
		 */
    this.zoom = 10;

    /**
		 * Tworzy obiekt mapy - główna metoda inicjująca
		 * 
		 * @return GMap2
		 */
    this.initialize = function()
    {
        if(init) return false;

        map = new google.maps.Map2(this.place, this.params);
        map.setCenter(center, this.zoom);
        init = true;
        return map;
    };

    /**
		 * Ustawia wygląd, działanie zoomu, typy map i kontrole w obiekcie głównym
		 * 
		 * @return GMap2
		 */
    this.run = function()
    {
        if(init == false)
        {
            alert('Najpierw zainicjuj API metodą initialize()!');
            return false;
        }
			
        map.setUIToDefault();
        map.enableContinuousZoom();
        map.addMapType(G_PHYSICAL_MAP);
        map.addControl(new GLargeMapControl());
        map.addControl(new GMapTypeControl());

        return map;
    };

    /**
		 * Przechowuje wszystkie dymki markerów
		 *
		 * @type Array of GEventListener objects
		 */
    var listeners = Array();

		
    /**
		 * Tablica markerów znajdujących się na mapie
		 */
    var GMarkers = Array();

    /**
		 * @see var GMarkers
		 */
    this.GMarkers = GMarkers;

    /**
     *  Dodaje nowego markera na mapę
     *
     *  @param marker   GMarker
     *  @param text     string
     *  @param id       integer
     *  @param addon    bool        Jeżeli jest ustawiony na true to w każdym dymku markera pojawi się opcja dodaj do trasy, wymaga podania argumentu adress
     *  @param adress   string      Argument wymagany do addon
     *
     *  @return void
     *
     */
    var addMarker = function(marker, text, id, addon, adress)
    {
        if(!id)
        {
            var i = GMarkers.length;
            while(GMarkers[i] != undefined)
            {
                i++;
            }
            id = i;
        }

        if(GMarkers[id] instanceof GMarker)
        {
            return false;
        }
        
        map.addOverlay(marker);
        GMarkers[id] = marker;
        var point = marker.getLatLng();

        if(text)
        {
            if(listeners[point.lat()+','+point.lng()])
            {
                GEvent.removeListener(listeners[point.lat()+','+point.lng()]['event']);
                text = text+"<br/><hr/><br/>"+listeners[point.lat()+','+point.lng()]['text'];
                map.removeOverlay(GMarkers[listeners[point.lat()+','+point.lng()]['marker_id']]);
            }

            if(addon && adress)
                var dAddon = '<a href="#" class="event-add-marker" lat="'+point.lat()+'" lng="'+point.lng()+'" adres="'+adress+'">Dodaj do trasy</a>';

            listeners[point.lat()+','+point.lng()] = {
                event:
                GEvent.addListener(marker, "click", function(){
                    marker.openInfoWindowHtml("<div class='info-window'>"+text+dAddon+"</div>");
                }),
                text:
                text,
                marker_id: id
            };
        }

    };

    /** Dodaje nowy marker
     */
    this.addMarker = function(marker, text, id, addon, adress)
    {
        return addMarker(marker, text, id, addon, adress);
    };

    /** Usuwa markera
     */
    var deleteMarker = function(id)
    {
        if(id instanceof GMarker)
        {
            for(var i in GMarkers)
            {
                if(GMarkers[i] == id)
                    id = i;
            }
        }

        if(GMarkers[id] instanceof GMarker)
        {
            var latlng = GMarkers[id].getLatLng();
            if(listeners[latlng.lat()+','+latlng.lng()])
            {
                GEvent.removeListener(listeners[latlng.lat()+','+latlng.lng()]['event']);
                listeners.splice(latlng.lat()+','+latlng.lng(), 1);
            }

            GMarkers.splice(id, 1);
        }       
    };
    
    var deleteMarkers = function()
    {
      for(var i in GMarkers)
      {
        var latlng = GMarkers[i].getLatLng();
        if(listeners[latlng.lat()+','+latlng.lng()])
        {
           GEvent.removeListener(listeners[latlng.lat()+','+latlng.lng()]['event']);
        }
      }
      listeners = Array();
      GMarkers = Array();
    };
    
    this.deleteMarkers = function()
    {
      deleteMarkers();
    };

				
    /**
		 * Zwraca główny obiekt mapy
		 * 
		 * @return GMap2 
		 */
    this.getMapObject = function()
    {
        return map;
    };

    /**
		 * Dodaje możliwość wyszukiwania markerów w pobliżu przy pomocy google api
		 */
    this.search = function(query)
    {
        var search_control = new google.search.SearchControl();
        var searcher = new google.search.LocalSearch();
       						
        searcher.setCenterPoint(map);

        var options = new google.search.SearcherOptions();
        //  options.setExpandMode(GSearchControl.EXPAND_MODE_OPEN);

        search_control.addSearcher(searcher, options);
     		    
        search_control.setSearchCompleteCallback(searcher , function()
        {
            var results = searcher.results;
            for (var i = 0; i < results.length; i++)
            {
                var result = results[i];
                var marker = new GMarker(new GLatLng(parseFloat(result.lat), parseFloat(result.lng)), {
                    icon: icons[query]
                });
                var ht = result.html.cloneNode(true);
                for(var k = 0; k < 3; k++)
                {
                    var last = ht.lastChild;
                    last.parentNode.removeChild(last);
                }
                var adressP = $(ht).children(".gs-address");
                var adress = adressP.children(".gs-street").text()+", "+adressP.children(".gs-city").text();
                var text = $(ht).html();
                result.marker = marker;
                addMarker(marker, text, undefined, true, adress);
            }

        });
        search_control.draw(document.getElementById('mapsearch'));
        search_control.execute(query);        
        return search_control;
    };
        
				
    /**
		 * Przechowuje obiekt geokodujący
		 * 
		 * @type GClientGeocoder
		 */
    var geocoder;
		
    /**
		 * Zwraca(w przypadku gdy nie istnieje to najpierw tworzy) obiekt geokodera
		 * 
		 * @return GClientGeocoder
		 */
    var getGeocoder = function()
    {
        if(!geocoder)
            geocoder = new GClientGeocoder();
			
        return geocoder;
    };

    this.getGeocoder = function()
    {
        return getGeocoder();
    };
    	 		 
    /**
		 * Pobiera makery z zewnętrznego pliku xml(lub generującego xml)
		 * i w zależności od drugiego parametru geokoduje adresy
		 * 
		 * @param 	file	string		Ścieżka zewnętrznego pliku
		 * @param	update	callback	Funkcja aktualizująca dane w bazie 
		 * @param   parsingParams   Array
         *
		 * @return	boolean		True lub false w zależności od pomyślności wykonania operacji
		 */
    this.getFromXML = function(file, update, parsingParams)
    {
        if(!file) file = 'get_markers.php';

        /**
			 * Domyślna struktura pliku xml
			 * /////////////////////////////////////////////////////////////////////
			 * Każda struktura xml musi zawierać parametry:
			 * MAIN_NODE - nazwa węzła będącego obiektem(markerem) mającego w atrybutach poniższe dane
			 * NAME_ATTR - nazwa atrybutu określającego nazwę obiektu
			 * CATEGORY_ATTR - nazwa atrybutu określającego kategorię obiektu
			 * ADRESS_ATTR - nazwa atrybutu zawierającego adres dla ewentualnego geokodowania
			 * LAT_ATTR - nazwa atrybutu przechowującego szerokość geograficzną
			 * LNG_ATTR - nazwa atrybutu przechowującego długość geograficzną
			 * parametry opcjonalne:
			 * HTML_ATTR - nazwa atrybutu zawierającego html dymka(chmurki) markera 
			 * 	HTML_ATTR_OPEN_TAG - tag otwierający zawartość HTML_ATTR(przydatne jeżeli chcemy zastosować własny wygląd dymka poprzez CSS)
			 *  HTML_ATTR_CLOSE_TAG - tag zamykający zawartość HTML_ATTR
			 * ADD_MARKER_FUNC - jeżeli chcemy użyć własnej funkcji dodawania markerów, przypisujemy ją temu parametrowi
			 * ADD_HTML_TO_MARKER - tu definiujemy własną funkcję dodawania dymków do markerów
			 * 
			 * @type Array
			 */
        var defaultParsingParams =
        {
            MAIN_NODE:		'marker',
            NAME_ATTR:		'nazwa',
            CATEGORY_ATTR:	'kategoria',
            HTML_ATTR:      'tekst'
        };
			
        if(!parsingParams || (!parsingParams['MAIN_NODE'] || !parsingParams['NAME_ATTR']) || !parsingParams['CATEGORY_ATTR'])
            parsingParams = defaultParsingParams;
			
        (!parsingParams['ADRESS_ATTR']) ? 	parsingParams['ADRESS_ATTR'] = 'adres' : null;
        (!parsingParams['LAT_ATTR']) 	?	parsingParams['LAT_ATTR'] = 'lat' : null;
        (!parsingParams['LNG_ATTR']) 	?	parsingParams['LNG_ATTR'] = 'lng' : null;
						
        GDownloadUrl(file, function(data, requestCode)
        {
            if(requestCode == 200)
            {
                var xml = GXml.parse(data);
                var markers = xml.documentElement.getElementsByTagName(parsingParams['MAIN_NODE']);
                var geo = getGeocoder();
                var j = 0;

                function addIn(point, title, text, adress, id, category, up)
                {
                    if(point)
                    {
                        var params = {
                            title: title
                        };

                        if(up)
                        {
                            update(point, adress, id);
                        }
                        
                        if(icons[category])
                            params['icon'] = icons[category];
                        var marker = new GMarker(point, params);
                        addMarker(marker, text, id, true, adress);
                    }
                }
							
					
                function add(title, text, adress, id, category, p)
                {
                    if(p)
                    {
                        addIn(p, title, text, adress, id, category);
                        return function(){};
                    }
                    else
                    {
                        return function(point)
                        {
                            addIn(point, title, text, adress, id, category, true);
                        };
                    }
                }
                for(var i=0; i<markers.length; i++)
                {
                    var name 	 = markers[i].getAttribute(parsingParams['NAME_ATTR']);
                    var lat 	 = markers[i].getAttribute(parsingParams['LAT_ATTR']);
                    var lng 	 = markers[i].getAttribute(parsingParams['LNG_ATTR']);
                    var adress 	 = markers[i].getAttribute(parsingParams['ADRESS_ATTR']);
                    var category = markers[i].getAttribute(parsingParams['CATEGORY_ATTR']);
                    var html 	 = markers[i].getAttribute(parsingParams['HTML_ATTR']);
                    var id 		 = markers[i].getAttribute('id');
                    if(name)
                    {
                        if(lat != 0 && lng != 0)
                        {
                            add(name, html, adress, id, category, new GLatLng(lat, lng));
                        }
                        else
                        {
                            // można tutaj wstawić ogranicznik
                            // np. if(i>20)
                            geo.getLatLng(adress, add(name, html, adress, id, category));
                        }
                    }
                }
                return true;
            }
            else
            {
                alert('Nie mog\u0142em otworzyć pliku');
                return false;
            }
        });
    };
    
    /* Ustawianie zoomu */
    this.setZoom = function(zoom)
    {
    	map.setZoom(zoom);
    };
    
};
