/**
 * Class for GPX File parsing, plotting and stuff
 * 
 * @author Dr. Helga (http://www.drhelga.de), GPX-Parser-Function inspired by j.berkmeier (http://www.j-berkemeier.de)
 * 
 * @param pGpxFile
 * @param pMapElement
 * @return
 */

function dhMap (pGpxFile,pMapElement) {
        
    var self = this;
    var tracks = Array();
    var tracksegments = Array();
    var elevations = Array();
    var tracklengths = Array();
    var gpxfile = pGpxFile;
    var cycleMapBaseUrl = "http://c.andy.sandbox.cloudmade.com/tiles/cycle/";
    var map;
    var waypoints = Array();
    var trackStart;
    var trackEnd;
    var latmin=1000,latmax=-1000,lonmin=1000,lonmax=-1000;
    var debugArea;
    var mapFeatures = Array();
    var managers = Array();
    var radkarte;
    
    /**
     * initialize the map
     */
    
    this.init = function() {
      if (GBrowserIsCompatible()) {
    	  
         map = new GMap2(document.getElementById(pMapElement));
         new GKeyboardHandler(map);
         
         var customUI = map.getDefaultUI();
         map.setUI(customUI);
         
//         map.addControl(new GLargeMapControl());
         
         map.addMapType(G_PHYSICAL_MAP);
         radkarte = self.createCycleMap('Radkarte');
         map.addMapType(radkarte);
         
//         map.addControl(new GMapTypeControl());
         if(initialCenter == null) {
        	 map.setCenter(self.getCenter(),self.getZoom(map));
         } else {
        	 map.setCenter(new GLatLng(initialCenter.lat,initialCenter.lng),initialCenter.zoom);
        	 initialmarker = self.createMarker('','',initialCenter.lat,initialCenter.lng,initialCenter.icon,'',false);
        	 map.addOverlay(initialmarker);
         }
         //map.setMapType(radkarte);
         
//         map.addControl(new GOverviewMapControl());
         
         /*for (var i=0;i<mapFeatures.length;i++) {
    	 	var pMarkers = Array();
         //for(var j=0;j<mapFeatures[i][1].length;j++) {
        	 var marker;
        	 var pFeatures = mapFeatures[i][1];
        	 for(var k=0;k<pFeatures.length;k++) {
        		 pFeature=pFeatures[k];
        		 marker = self.createMarker(pFeature.nid,pFeature.title,pFeature.lat,pFeature.lng,pFeature.icon,pFeature.xhtml);
 	        	 pMarkers.push(marker);
        	 }
        	 
         //}
         var pManager = new MarkerManager(map);
         pManager.addMarkers(pMarkers,9);
         managers[mapFeatures[i][0]] = pManager;
         pManager.refresh();
     }*/
         
         self.initListeners(map);
         self.map = map;
         //debugArea = document.getElementById('txtDebug');
         
      } else {
           //alert('FAILED TO INITIALIZE MAP');       
      }
    };
    
    /**
     * Listeners
     */
    this.initListeners = function(pMap) {
    	/*GEvent.addListener(pMap,"click",self.mapOnClick);
        GEvent.addListener(pMap,"mouseover",self.mapOnMouseOver);
        GEvent.addListener(pMap,"mousemove",self.mapOnMouseMove);
        GEvent.addListener(pMap,"singlerightclick",self.mapOnSingleRightClick);*/
    	GEvent.addListener(pMap,"infowindowclose", self.infoWindowOnClose);
    };
    
    /**
     * Events
     */
    this.mapOnClick = function(overlay, latlng) {
    	debugArea.value = latlng;
    };
    
    this.mapOnMouseOver = function(latlng) {
    	//debugArea.value = latlng;
    };
    
    this.mapOnMouseMove = function(latlng) {
    	//debugArea.value = latlng;
    };
    
    this.mapOnSingleRightClick = function(point,srcElement,overlay) {
    	debugArea.value = "Element: " + srcElement + " x: " + Math.round(point.x) + " y: " + Math.round(point.y);
    	var context = document.getElementById('context');
    	context.style.visibility = 'visible';
    };
    
    /**
     * Create the cycle map
     */
    this.createCycleMap = function(pMapName) {
    	var copycol = new GCopyrightCollection("");
        var copy = new GCopyright(1, new GLatLngBounds(new GLatLng(-90,-180),new GLatLng(90,180)), 0, "&copy; <a href='http://creativecommons.org/licenses/by-sa/2.0/'>cc-by-sa</a> by <a href='http://www.openstreetmap.org>OpenStreetMap</a> contributors");
        copycol.addCopyright(copy);
       
        var tileCycle = new GTileLayer(copycol,1,18);
        tileCycle.getTileUrl=self.cycleMapGetTileUrl;
        tileCycle.isPng = function () { return true;};
        tileCycle.getOpacity = function() {return 1.0;};
        
        var layer0 = [tileCycle];
        var cycleMap = new GMapType(layer0, G_SATELLITE_MAP.getProjection(), pMapName, G_SATELLITE_MAP);
        
        return cycleMap;
    };
    
     /**
      * Find the tiles for the cycle map
      */
    this.cycleMapGetTileUrl = function(a,b,c) {        
        var url = cycleMapBaseUrl + b + "/" + a.x + "/" + a.y + ".png";
        return url;  
    };
    
    /**
     * Download the gpx data file
     */
    this.download = function(loadFeature) {
        GDownloadUrl(gpxfile,function(data,responseCode) {self.onDownload(data,responseCode,loadFeature);});
    };
    
    /**
     * Download has a response for us
     */
    this.onDownload = function(data, responseCode,loadFeature) {
        if (responseCode != 200 && responseCode != 0 ) {
            alert("Beim Oeffnen der Datei " + gpxfile + " ist der Fehler " + responseCode + " aufgetreten!");
            return;
          }
          self.parseGPX(data);
          self.init();
          self.plotTracks();
          if(loadFeature != false) {
        	  self.showFeature(loadFeature.name,loadFeature.loadRPC,loadFeature.data);
          }
    };
    
    /**
     * Calculate the map's center based where the most north and most south point is
     */
    this.getCenter = function() {
    	var center = new GLatLng((latmax+latmin)/2,(lonmax+lonmin)/2);
    	return center;
    };
    
    /**
     * Calculate the zoom to have the route fitting well into the map
     */
    this.getZoom = function(pMap) {
    	var zoom = pMap.getBoundsZoomLevel(new GLatLngBounds(new GLatLng(latmin,lonmin),new GLatLng(latmax,lonmax)));
    	return zoom;
    };
    
    /**
     * plot the tracks to the map
     */
    this.plotTracks = function() {
        for(var i=0;i<tracks.length;i++) {
            self.plotTracksegments(tracks[i]);
        }

    };
    
    /**
     * plot a single tracksegment
     */
    this.plotTracksegments = function(pTrack) {
    	for(var i=0;i<pTrack.length;i++) {
    		self.plotTracksegment(pTrack[i]);
    	}
    };
     
    this.plotTracksegment = function(pTracksegment) {
     	var polyline = new GPolyline(pTracksegment, "#9d0d15", 3, 1);
     	map.addOverlay(polyline);
     };
    
    /**
     * create an icon
     */
    this.createIcon = function(pUri) {
    	var baseIcon = new GIcon();
    	baseIcon.iconSize = new GSize(32, 32);
    	baseIcon.shadow = false;
    	baseIcon.iconAnchor = new GPoint(16, 16);
    	baseIcon.image = pUri;
    	return baseIcon;
    };
    
    /**
     * create a marker
     */
    this.createMarker = function(pID,pName,pLat,pLng,pIconUri,pXhtml,pEvent) {
    	var pIcon = self.createIcon(pIconUri);
    	var pOptions = {icon:pIcon};
    	var pPoint = new GLatLng(pLat,pLng);
    	var pMarker = new GMarker(pPoint,pOptions);
    	if(pEvent == true) {
    		GEvent.addListener(pMarker, "click", function() {
    			map.closeInfoWindow();
    			map.openInfoWindowHtml(pPoint, pXhtml);
    		});
    	}
    	return pMarker;
    	//return false;
    };
    
    this.infoWindowOnClose = function() {
    	map.returnToSavedPosition();
    };
    
    /**
     * plot a marker to the map
     */
    this.plotMarker = function(pMarker) {
    	map.addOverlay(pMarker);
    };
    
    /**
     * parse the downloaded gpx file into some arrays and stuff
     * let's go nuts ...
     */
    this.parseGPX = function(data) {
    	//we need to reset the latlong mins and maxes
    	latmin=1000;latmax=-1000;lonmin=1000;lonmax=-1000;
        var myXML = new GXml.parse(data);
        var trk = myXML.documentElement.getElementsByTagName("trk");
        for(var k=0;k<trk.length;k++) {
            var pTrkSeg = Array();
        	var name = trk[k].getElementsByTagName("name");
            var trkseg = trk[k].getElementsByTagName("trkseg");
            for(var j=0;j<trkseg.length;j++) {
            	
            	//let's reset the polylines for each new tracksegment
                var polylines = Array();
                var trkpts = trkseg[j].getElementsByTagName("trkpt");
                for(var i=0;i<trkpts.length;i++) {
                	
                	//now lets parse some latlng values
                    var lat = parseFloat(trkpts[i].getAttribute("lat"));
                    var lon = parseFloat(trkpts[i].getAttribute("lon"));
                    
                    /*
                     * see if there might be higher or lower maxes or mins as the ones stored, 
                     * if so, overwrite them (the stored ones) 
                     * in order to always have the latest shit in these vars 
                    */
                    if(lat<latmin) latmin=lat; if(lat>latmax) latmax=lat;
                    if(lon<lonmin) lonmin=lon; if(lon>lonmax) lonmax=lon;
                    
                    //now put this in the polyline array thats used in the trackarray
                    polylines.push(new GLatLng(lat,lon));
                    
                    //and store all the points all in the waypoint array for backup :-)
                    waypoints.push(new GLatLng(lat,lon));
                    
                    //
                    if(j==0 && i==0) {
                    	trackStart = new GLatLng(lat,lon);
                    }
                    if(j==trkseg.length-1 && i==trkpts.length-1) {
                    	trackEnd = new GLatLng(lat,lon);
                    }
                    
                    //lets find some elevation values an store them in an array
                    //var h = parseFloat(trkpts[i].getElementsByTagName("ele")[0].firstChild.data);
                    //elevations.push(h);
                }
                
                //add the polylines to the tracksegment
                
                tracksegments.push(polylines);
                pTrkSeg.push(polylines);
            }
            tracks.push(pTrkSeg);
        }
    };
    
    this.loadFeature = function(pFeatureName)
    {
    	var loading = document.getElementById('maploading');
    	loading.className = 'loadingvisible';
    	var req = new Request.JSON({
    		url:'/api/json/' + pFeatureName,
    		onSuccess:function(data1,data2) {self.loadFeatureOnSuccess(data1,data2,pFeatureName);},
    		onFailure:function() {
    			var loading = document.getElementById('maploading');
    			loading.className = 'loadinghidden';
    			alert('Beim Laden der Icons ist ein Fehler aufgetreten');
    		}
    	}).post({'apikey':'1234567'});
    };
    
    this.loadFeatureOnSuccess = function (pDataJson,pDataText,pFeatureName) {
    	var loading = document.getElementById('maploading');
    	loading.className = 'loadinghidden';
    	var pFeatures = pDataJson;
    	var pMarkers = Array();
    	var marker;
    	for(var k=0;k<pFeatures.length;k++) {
    		pFeature=pFeatures[k];
    		marker = self.createMarker(pFeature.nid,pFeature.title,pFeature.lat,pFeature.lng,pFeature.icon,pFeature.xhtml,true);
    		pMarkers.push(marker);
    	}
    	
    	var pManager = new MarkerManager(map);
    	
    	pManager.addMarkers(pMarkers,9);
    	managers[pFeatureName] = pManager;
    	pManager.refresh();
    };
    
    this.addMapFeature = function (pFeatureId,pFeature)
    {
    	var feature = Array(pFeatureId,pFeature);
    	mapFeatures.push(feature);
    };
    
    this.swapFeatureLink = function (pName) 
    {
    	var cbx = document.getElementById('cbx' + pName);
    	if(cbx.checked == true) {
    		self.hideFeature(pName);
    		cbx.checked = false;
    	} else {
    		self.showFeature(pName,true,null);
    		cbx.checked = true;
    	}
    };
    
    this.swapFeatureBox = function (pName)
    {
    	var cbx = document.getElementById('cbx' + pName);
    	if(cbx.checked == true) {
    		self.showFeature(pName,true,null);
    	} else {
    		self.hideFeature(pName);
    	}
    };
    
    this.hideFeature = function (pName) 
    {
    	if(managers[pName]) {
    		var featureManager = managers[pName];
    		featureManager.hide();
    	}
    	var tr = document.getElementById('tr' + pName);
		tr.className = 'normaltr';
    };
    
    this.showFeature = function (pName, pLoadFromRPC, pData) 
    {
    	if(managers[pName]) {
    		var featureManager = managers[pName];
        	featureManager.show();
    	} else {
    		if(pLoadFromRPC == true) {
    			self.loadFeature(pName);
    		} else {
    			self.loadFeatureOnSuccess(pData,null,pName);
    		}
    	}
    	if(document.getElementById('cbx' + pName)) {
    		var cbx = document.getElementById('cbx' + pName);
    		cbx.checked = true;
    		var tr = document.getElementById('tr' + pName);
    		tr.className = 'highlighttr';
    	}
    };
 }