/**
 * Main map functions
 */
MAPUTILS  = function () {

    //global map object
    MAPUTILS.prototype.map;
    MAPUTILS.prototype.counter = 0;

    //default map settings
    MAPUTILS.prototype.currentLat = 45.383;
    MAPUTILS.prototype.currentLng = -75.677;
    MAPUTILS.prototype.currentZoom = 0;

    MAPUTILS.prototype.initMap = function() {

        //check if map object has been loaded or created
        try{
            document.getElementById('map').innerHTML;
        }catch(e){
            if (this.counter > 60) {
                alert('Can\'t load map! Can\'t find map object!');
            } else {
                setTimeout("maputil.initMap()", 1000);
            }
            return false;
        }

        //If gmaps main.js didn't load try to call init again after 60 tries we give up
        if (typeof GMap != "function") {
            if (this.counter > 60) {
                document.getElementById('map').innerHTML = 'Can\'t load map! Gmap server timeout! ';
            } else {
                setTimeout("maputil.initMap()", 1000);
            }
            this.counter++;
            return false;
        }

        //if browser not compatible update map tag with error msg
        if (!GBrowserIsCompatible()) {
            document.getElementById('map').innerHTML = 'Can\'t load map because your browser is too old!';
            return false;
        }

        //init gmaps object
        this.map = new GMap2(document.getElementById("map"));


        //set center of the map
        this.map.setCenter(new GLatLng(this.currentLat, this.currentLng), this.currentZoom);
        this.map.setMapType(G_HYBRID_MAP);

        //add controls and mouse functions
        this.map.enableDoubleClickZoom();
        this.map.enableContinuousZoom();
        this.map.enableScrollWheelZoom();
        //this.map.addControl(new GOverviewMapControl (/*new GSize(200,180)*/));

        this.map.addControl(new GMenuMapTypeControl());
        this.map.addControl(new GLargeMapControl3D());


        //add zoomend event
        GEvent.addListener(maputil.map, "zoomend", function() {
            if(maputil.map.getZoom()>10) googleSearch.getResults();
            marker.reload();
        });

        GEvent.addListener(maputil.map, "drag", function() {
            marker.hidePointLabelElement();
            marker.hideBubble();
        });

        GEvent.addListener(maputil.map, "click", function() {
            marker.hideBubble();
        });

        //call markers processMarkeres method which will show the markes on the map
        marker.processMarkeres();

        //if zoom is 0 try marker bounds
        if(this.currentZoom == 0) maputil.map.setCenter(marker.getMarkerCenter(),marker.getZoomLevel());

        maptools.add();

    }

}

/**
  * Marker class. Handle markers and lables
 */
MARKERS  = function () {
    //this will store the markers
    MARKERS.prototype.markersDb = new Array();
    MARKERS.prototype.markersDb2 = new Array();

    //define icons path
    MARKERS.prototype.markerIconsPath = '/imgs/icons/';

    //store bounds
    MARKERS.prototype.bounds = new GLatLngBounds();


    MARKERS.prototype.showPointLabel = function (anchor){
        marker.showLabel(anchor.id);
        anchor.style.zIndex=4;
        anchor.style.color = '#ecf73a';
        return false;
    }

    MARKERS.prototype.hidePointLabel = function (anchor){
        anchor.style.zIndex=1;
        anchor.style.color = '#fff';
        this.hidePointLabelElement();
        return false;
    }

    MARKERS.prototype.hidePointLabelElement = function (){
        try{
            document.getElementById("infoLabel").style.display = 'none';
        }catch(e){}
    }

    MARKERS.prototype.processMarkeres = function(){
        var pointsHtml = '';
        //go through markersDb and build up a layer for the map
        for(i=0;i<this.markersDb.length;i++){
             p = this.markersDb[i];
            //calculate marker positions in pixel
            var pos = maputil.map.fromLatLngToDivPixel(new GLatLng( p[1],  p[2]));
            //extends bounds
            this.bounds.extend(new GLatLng( p[1], p[2]));

            //set offset params to center marker to position
            var x = parseInt(pos.x) - 6;
            var y = parseInt(pos.y) - 30;

            //create a ne marker achor
            pointsHtml += '<a href="javascript:void(0)" class="marker" ';
            pointsHtml += 'onclick="marker.infoWindow('+p[1]+','+p[2]+','+p[0]+')" ';

            //set style  and icon
            pointsHtml += 'style="';
            pointsHtml += "background:url('" + this.markerIconsPath + p[3] + '.png' + "') no-repeat;";

            pointsHtml += 'top:' + y + 'px;left:' + x + 'px;" ';
            pointsHtml += 'id="marker_' + p[0] + '" ';

            //hover text
            pointsHtml += "rel='" + p[4] + "' ";

            //add events to markers
            pointsHtml += 'onmouseover="marker.showPointLabel(this)" ';
            pointsHtml += 'onmouseout="marker.hidePointLabel(this)" ';
            pointsHtml += 'onclick="marker.showBubble(this)"';
            pointsHtml += '></a>';

        }

        for(i=0;i<this.markersDb2.length;i++) {
            p = this.markersDb2[i].split("\|");
            //console.log(p[1] +' '+p[2]);
            //calculate marker positions in pixel
            var pos = maputil.map.fromLatLngToDivPixel(new GLatLng( p[1],  p[2]));
            //extends bounds
            //this.bounds.extend(new GLatLng( p[1], p[2]));

            //set offset params to center marker to position
            var x = parseInt(pos.x) - 8;
            var y = parseInt(pos.y) - 25;

            //create a ne marker achor
            pointsHtml += '<a href="'+p[6]+'" target="_blank" ';

            //set style  and icon
            pointsHtml += 'class="marker" style="';
            pointsHtml += "background:url('" + this.markerIconsPath + '' +p[3]+ ".png') no-repeat;";
            pointsHtml += 'top:' + y + 'px;left:' + x + 'px;" ';
            pointsHtml += 'id="marker_' + p[0] + '" ';

            //hover text
            pointsHtml += "rel='" + p[4] + "' ";

            //add events to markers
            pointsHtml += 'onmouseover="marker.showPointLabel(this)" ';
            pointsHtml += 'onmouseout="marker.hidePointLabel(this)" ';
           // pointsHtml += 'onclick="marker.showBubble(this)"';
            //pointsHtml += 'onclick="marker.infoWindow('+p[1]+','+p[2]+',\''+p[0]+'\')"';
            pointsHtml += '></a>';

        }


        //insert marker html to mappane
        maputil.map.getPane(G_MAP_FLOAT_PANE ).innerHTML = pointsHtml;
        //console.log(pointsHtml);
    }


    MARKERS.prototype.clearMarkers = function(){
        var element = maputil.map.getPane(G_MAP_FLOAT_PANE );
        while (element.firstChild) {

            element.removeChild(element.firstChild);
        }
    }

    MARKERS.prototype.showLabel = function (markerObj){
        //try to get label element if not in the body add it
        try{
            document.getElementById('infoLabel').innerHTML;
            var label = document.getElementById('infoLabel');
        }catch(e){
            var label = document.createElement('div');
            label.setAttribute('id','infoLabel');
            label.onclick = function(){marker.hidePointLabelElement()}
            document.body.appendChild(label);
        }

        //calculate absolute postion of the label
        var m = document.getElementById(markerObj);
        var mapPos = this.findPos(document.getElementById('map'));
        var lY = (maputil.map.getSize().height - (maputil.map.getSize().height/2 + maputil.map.fromLatLngToDivPixel(maputil.map.getCenter()).y - parseInt(m.style.top))) + mapPos[1] ;
        var lX = (maputil.map.getSize().width - (maputil.map.getSize().width/2 + maputil.map.fromLatLngToDivPixel(maputil.map.getCenter()).x - parseInt(m.style.left))) + mapPos[0] ;


        //check if label in map
        if(lY<mapPos[1]+20) return false;
        if(lX<mapPos[0]+20) return false;
        if(lY>(document.getElementById('map').offsetHeight+mapPos[1])) return false;
        if(lX>(document.getElementById('map').offsetWidth+mapPos[0])) return false;


        //show label
        label.style.display='block';

        //set attributes
        //if you need to move the label offset you can change it here
        label.style.top = (lY - 16)  + 'px';
        label.style.left = (lX + 22) + 'px';
        label.innerHTML = '<span class="mapBubbleTxt">' + m.rel + '</span><span class="mapBubbleEnd"></span>';
    }

    MARKERS.prototype.showBubble = function (m){

        var label = document.getElementById('map_bubble');
        //show label
        label.style.display='block';

        //calculate absolute postion of the label
        //var m = document.getElementById(markerObj);
        var mapPos = this.findPos(document.getElementById('map'));
        var lY = (maputil.map.getSize().height - (maputil.map.getSize().height/2 + maputil.map.fromLatLngToDivPixel(maputil.map.getCenter()).y - parseInt(m.style.top))) + mapPos[1] ;
        var lX = (maputil.map.getSize().width - (maputil.map.getSize().width/2 + maputil.map.fromLatLngToDivPixel(maputil.map.getCenter()).x - parseInt(m.style.left))) + mapPos[0] ;


        //set attributes
        //if you need to move the label offset you can change it here
        label.style.top = (lY - 145)  + 'px';
        label.style.left = (lX - 115) + 'px';
        label.innerHTML = document.getElementById("details_" + m.id ).innerHTML;
    }

    MARKERS.prototype.hideBubble = function (){
        try{
            document.getElementById('map_bubble').style.display = 'none';
            marker.currentProperty = 0;
        }catch(e){}
    }

    MARKERS.prototype.findPos = function(obj) {
        if (obj.offsetParent) {
            var curleft = obj.offsetLeft
            var curtop = obj.offsetTop
            while (obj = obj.offsetParent) {
                curleft += obj.offsetLeft
                curtop += obj.offsetTop
            }
            return [curleft,curtop];
        }
    }

    MARKERS.prototype.getZoomLevel = function() {
        return maputil.map.getBoundsZoomLevel(marker.bounds);
    }

    MARKERS.prototype.getMarkerCenter = function() {
        return marker.bounds.getCenter();
    }

    MARKERS.prototype.infoWindow = function(lat,lng,pid){
        //cacluate new geocoordinate by moveing info by 20px
        var markerCenter = new GLatLng(lat,lng);
            markerCenter = maputil.map.fromLatLngToDivPixel(new GLatLng(lat,lng));
            markerCenter = maputil.map.fromDivPixelToLatLng(new GPoint(markerCenter.x,markerCenter.y-25));

        maputil.map.openInfoWindow(markerCenter, '<div id="infoWin">Please wait...</div>');
        marker.ajax('getdetails.php?pid='+pid, marker.showResults);
    }

    MARKERS.prototype.showResults = function(){
        if ((xmlhttp.readyState == 4) && (xmlhttp.status == 200)) {
                document.getElementById('infoWin').innerHTML = xmlhttp.responseText;
        }
    }

    MARKERS.prototype.ajax = function(url,action) {
        try {
    		xmlhttp = window.XMLHttpRequest?new XMLHttpRequest(): new ActiveXObject("Microsoft.XMLHTTP");
    	} catch (e) { }
    	xmlhttp.onreadystatechange = action;
    	xmlhttp.open("GET", url, true);
    	xmlhttp.send(null);
    }

    MARKERS.prototype.markerOn = true;
    MARKERS.prototype.reload = function() {
        marker.clearMarkers();
        marker.hidePointLabelElement();
        marker.hideBubble();
        if(marker.markerOn) marker.processMarkeres();
    }

    MARKERS.prototype.toggle = function() {
        if(marker.markerOn){
            marker.markerOn = false;
        }else{
            marker.markerOn = true;
        }
        marker.reload();
    }

}

MAPTOOLS = function () {
    MAPTOOLS.prototype.added = false;

    //add drop down tool menu and other UI elements
    MAPTOOLS.prototype.add = function(){

        //add container
        var container = document.createElement("div");
        container.style.position = 'absolute';
        container.style.top = '7px';
        container.style.left = '110px';

        //add range finder button
        var bRangeFinderOut = this.createButton("");
        var bRangeFinder = this.createButton("Range Finder");
        bRangeFinderOut.appendChild(bRangeFinder);
        this.toggleButton(bRangeFinder, false);
        container.appendChild(bRangeFinderOut);

        GEvent.addDomListener(bRangeFinder, "click", function() {
            maptools.toggleButton(bRangeFinder, maptools.toggleRangeFinder());
        })



        //add range finder button
        var bDistanceCalcOut = this.createButton("");
        bDistanceCalcOut.style.marginLeft = "6px";
        var bDistanceCalc = this.createButton("Distance Calculator");
        bDistanceCalcOut.appendChild(bDistanceCalc);
        this.toggleButton(bDistanceCalc, false);
        container.appendChild(bDistanceCalcOut);

        GEvent.addDomListener(bDistanceCalc, "click", function() {
            maptools.toggleButton(bDistanceCalc, maptools.toggleDistanceCalc());
        })

         //add fullscreen button
        var bfullScreenOut = this.createButton("");
        bfullScreenOut.style.marginLeft = "6px";
        var bfullScreen = this.createButton("Full Screen");
        bfullScreenOut.appendChild(bfullScreen);
        this.toggleButton(bfullScreen, maptools.fullScreenStatus);
        //console.log(maptools.fullScreenStatus)
        container.appendChild(bfullScreenOut);

        GEvent.addDomListener(bfullScreen, "click", function() {
            maptools.toggleButton(bfullScreen, maptools.toggleFullScreen());
        })

        //add marker toggle button
        var bMarkerOut = this.createButton("");
        bMarkerOut.style.marginLeft = "6px";
        var bMarker = this.createButton("Toggle Marker");
        bMarkerOut.appendChild(bMarker);
        this.toggleButton(bMarker, true);
        container.appendChild(bMarkerOut);

        GEvent.addDomListener(bMarker, "click", function() {
            marker.toggle();
            maptools.toggleButton(bMarker, marker.markerOn);
        })

        container.appendChild(this.rangeFinderForm());
        container.appendChild(this.distanceCalcPanel());

        //add to map
        maputil.map.getContainer().appendChild(container);


    }

    MAPTOOLS.prototype.rangeFinderForm = function(){
       var form = document.createElement("div");
       var htmlSrc = '<br style="clear:both"><div style="border:1px solid #666;padding:5px;background:#fff;display:none;" id="rangeFinderForm">';
       htmlSrc += '<form onsubmit="return maptools.showRange(this.city.value,this.range.value)"><input type="text" name="city" value="Ottawa" size="30"/>';
       htmlSrc += '<input name="range" type="text" value="300" size="5" style="text-align:right" /> nmi &nbsp;'
       htmlSrc += '<input type="submit" value="Show" /><input type="button" onclick="if(maptools.circle != null) maputil.map.removeOverlay(maptools.circle)" value="Clear" /></form> </div>';
       form.innerHTML = htmlSrc;
       return form;
    }

    MAPTOOLS.prototype.distanceCalcPanel = function(){
       var form = document.createElement("div");
       var htmlSrc = '<div style="border:1px solid #666;padding:5px;background:#fff;display:none;" id="distanceCalc">';
       htmlSrc += 'Drag markers to calculate distance.';
       htmlSrc += '';
       htmlSrc += '</div>';
       form.innerHTML = htmlSrc;
       return form;
    }

    MAPTOOLS.prototype.showRange = function(city,range){
        maptools.searchAddress(city,range);
        return false;
    }

    MAPTOOLS.prototype.fullScreenStatus = false;
    MAPTOOLS.prototype.toggleFullScreen = function(){
        if(maptools.fullScreenStatus){
            maptools.fullScreenStatus = false;
            document.getElementById("map").style.position = "relative";
            document.getElementById("map").style.height = "300px";
        }else{
            document.getElementById("map").style.position = "absolute";
            document.getElementById("map").style.top = "0";
            document.getElementById("map").style.left = "0";
            document.getElementById("map").style.width = "100%";
            document.getElementById("map").style.height = "100%";
            document.getElementById("map").style.zIndex = "1";
            //maputil.initMap();
            maputil.map.checkResize() ;
            maptools.fullScreenStatus = true;
        }
        return maptools.fullScreenStatus;
    }

    MAPTOOLS.prototype.rangeFinderStatus = false;
    MAPTOOLS.prototype.toggleRangeFinder = function(){
        if(maptools.rangeFinderStatus){
            maptools.rangeFinderStatus = false;
            document.getElementById("rangeFinderForm").style.display = "none";
            if(maptools.circle != null) maputil.map.removeOverlay(maptools.circle);
        }else{
            document.getElementById("rangeFinderForm").style.display = "block";
            maptools.rangeFinderStatus = true;
        }
        return maptools.rangeFinderStatus;
    }

    MAPTOOLS.prototype.distanceCalcStatus = false;
    MAPTOOLS.prototype.toggleDistanceCalc = function(){
        if(maptools.distanceCalcStatus){
            maptools.distanceCalcStatus = false;
            document.getElementById("distanceCalc").style.display = "none";
            maptools.clearDistanceMarkers();
        }else{
            document.getElementById("distanceCalc").style.display = "block";
            maptools.distanceCalcStatus = true;
            maptools.addDistanceMarkers();
            document.getElementById("distanceCalc").innerHTML = 'Drag markers to calculate distance.';
        }
        return maptools.distanceCalcStatus;
    }

    MAPTOOLS.prototype.setButtonStyle = function(button) {
        button.style.color = "#000000";
        button.style.backgroundColor = "white";
        button.style.font = "small Arial";
        button.style.border = "1px solid black";
        button.style.padding = "0px";
        button.style.margin= "0px";
        button.style.textAlign = "center";
        button.style.fontSize = "12px";
        button.style.cursor = "pointer";
    }

    MAPTOOLS.prototype.toggleButton = function(div, boolCheck) {
        div.style.fontWeight = boolCheck ? "bold" : "";
        div.style.border = "1px solid white";
        var shadows = boolCheck ? ["Top", "Left"] : ["Bottom", "Right"];
        for (var j = 0; j < shadows.length; j++) {
          div.style["border" + shadows[j]] = "1px solid #b0b0b0";
        }
    }

    MAPTOOLS.prototype.createButton = function(text) {
      var buttonDiv = document.createElement("div");
      this.setButtonStyle(buttonDiv);
      buttonDiv.style.cssFloat = "left";
      buttonDiv.style.styleFloat = "left";
      var textDiv = document.createElement("div");
      textDiv.appendChild(document.createTextNode(text));
      textDiv.style.width = "10em";
      buttonDiv.appendChild(textDiv);
      return buttonDiv;
    }

    MAPTOOLS.prototype.circle = null;
    MAPTOOLS.prototype.drawCircle = function(center, radius){
        var color = "#006600";
        var weight = 2;
        var opacity = 0.7;
        var fillColor = "#00FF00";
        var fillOpacity =  0.2;

        var d = radius/3443.917;  //3963.189;
        var circlePoints = Array();
        with (Math) {
            var lat1 = (PI/180)* center.lat(); // radians
        	var lng1 = (PI/180)* center.lng(); // radians

        	for (var a = 0 ; a < 361 ; a++ ) {
        		var tc = (PI/180)*a;
        		var y = asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc));
        		var dlng = atan2(sin(tc)*sin(d)*cos(lat1),cos(d)-sin(lat1)*sin(y));
        		var x = ((lng1-dlng+PI) % (2*PI)) - PI ; // MOD function
        		var point = new GLatLng(parseFloat(y*(180/PI)),parseFloat(x*(180/PI)));
        		circlePoints.push(point);
        	}
            maptools.circle = new GPolygon(circlePoints, color, weight, opacity, fillColor, fillOpacity);

            //circle.tooltip = tooltip;
            maputil.map.addOverlay(maptools.circle);
            maputil.map.setCenter(point);
            marker.reload();
            //addCircleLabels(center, radius, maplabel);
            //circleLabelDb.push(new Array(center, radius,maplabel,tooltip ));
        }
    }

    MAPTOOLS.prototype.searchAddress = function(str,radius){
            geocoder = new GClientGeocoder();
            geocoder.getLocations(str, function(addresses) {
                if(addresses.Status.code != 200) {
                    alert("Geocoder failed to find an address for " + str);
                    //latlng.toUrlValue();
                } else {
                    var result = addresses.Placemark[0];
                    point = new GLatLng(result .Point.coordinates[1], result.Point.coordinates[0]);
                    maptools.drawCircle(point, parseInt(radius));
                }
            });
    }

    MAPTOOLS.prototype.markerStart;
    MAPTOOLS.prototype.markerEnd;
    MAPTOOLS.prototype.distancePoly;
    MAPTOOLS.prototype.addDistanceMarkers = function(){
        var center = maputil.map.getCenter();
        maptools.markerStart = new GMarker(center, {draggable: true});

        GEvent.addListener(maptools.markerStart, "dragend", function() {
            maptools.calculateDistance();
        });

        maputil.map.addOverlay(maptools.markerStart);

        var mapOffset = maputil.map.fromContainerPixelToLatLng(new GPoint((maputil.map.getSize().width/2)-50, maputil.map.getSize().height/2));

        maptools.markerEnd = new GMarker(mapOffset, {draggable: true});
        maputil.map.addOverlay(maptools.markerEnd);

        GEvent.addListener(maptools.markerEnd, "dragend", function() {
            maptools.calculateDistance();
        });
        //GPolyline(latlngs:GLatLng[], color?:String, weight?:Number, opacity?:Number, opts?:GPolylineOptions)
        maptools.distancePoly = new GPolyline([maptools.markerStart.getLatLng(),maptools.markerEnd.getLatLng()],"#000000",1,1,{geodesic:true});
        maputil.map.addOverlay(maptools.distancePoly);
    }

    MAPTOOLS.prototype.calculateDistance = function(){
        maputil.map.removeOverlay(maptools.distancePoly);
        //get distance in meter
        var dist = maptools.markerStart.getLatLng().distanceFrom(maptools.markerEnd.getLatLng());
        dist = (dist/1852).toFixed(0);
        document.getElementById("distanceCalc").innerHTML = "Distance " + dist + " nmi";
        maptools.distancePoly = new GPolyline([maptools.markerStart.getLatLng(),maptools.markerEnd.getLatLng()],"#000000",1,1,{geodesic:true});
        maputil.map.addOverlay(maptools.distancePoly);
    }

    MAPTOOLS.prototype.clearDistanceMarkers = function(){
        maputil.map.removeOverlay(maptools.distancePoly);
        maputil.map.removeOverlay(maptools.markerEnd);
        maputil.map.removeOverlay(maptools.markerStart);
    }

}

//Google local search
GSEARCH  = function () {

    GSEARCH.prototype.getResults = function(query){
        googleSearch.ajax('gmap/glocalsearch.php?q='+encodeURIComponent(query) + '&sspn=' + maputil.map.getBounds().toSpan().toUrlValue() +'&sll='+ maputil.map.getCenter().y+','+ maputil.map.getCenter().x, googleSearch.showResults);
    }

    GSEARCH.prototype.showResults = function(){
        if ((xmlhttp3.readyState == 4) && (xmlhttp3.status == 200)) {
            googleSearch.loading('');

            if(xmlhttp3.responseText.length>0){
                var results = xmlhttp3.responseText.split("\n");
                //if(results.length>1){
                    //if(marker.markersDb.length<1) marker.markersDb = results;
                    //else marker.markersDb.concat(results);
                    marker.markersDb2 = results;
                    marker.processMarkeres();
                    marker.reload();

                /*}else{
                    var cor = xmlhttp.responseText.split(",");
                    maputil.map.setCenter(new GLatLng(cor[1], cor[0]), 12);
                    marker.clearMarkers();
                    marker.getMarkers(1);
                }*/
            }
        }
    }

    GSEARCH.prototype.loading = function(text) {
        if(text.length>0){
            document.getElementById('loading').style.display = 'block';
        }else{
            document.getElementById('loading').style.display = 'none';
        }
    }

    GSEARCH.prototype.ajax = function(url,action) {
        try {
                xmlhttp3 = window.XMLHttpRequest?new XMLHttpRequest(): new ActiveXObject("Microsoft.XMLHTTP");
        } catch (e) { }
        xmlhttp3.onreadystatechange = action;
        xmlhttp3.open("GET", url, true);
        xmlhttp3.send(null);
    }
}


//search
var googleSearch = new GSEARCH;
//create markers class
var marker = new MARKERS;
//create maputil class
var maputil = new MAPUTILS;
var maptools = new MAPTOOLS;


