/*
 * api_key - Google Maps API key
 * ui_ids - hash with ids to contain map and directions
 *      { map: 'map', directions: 'directions' }
 */

function GMapWrapper(api_key, ui_ids) {

    var map;
    var gdir;
    var geocoder = null;
    var addressMarker;

    var ui = {
            map: null,
            dir: null
        };

    var cfg = {
            zoomCtrl: true
        };

    var callbacks = {};

    this.init = function(skipSetCenter) {
        var w = this;
        window.makeMap = function() { window.gmap = true; if(GBrowserIsCompatible()) w.initMap(skipSetCenter); }

        var script = document.createElement("script");
        script.type = "text/javascript";
        script.src = "http://maps.google.com/maps?file=api&v=2.x&key=" + api_key + "&async=2&callback=makeMap";
        document.body.appendChild(script);
    }


    this.initMap = function(skipSetCenter) {
        if( window.makeMap ) window.makeMap = null;

        ui.map = document.getElementById(ui_ids.map);
        ui.map.innerHTML = '';

        map = new GMap2(ui.map);
        if(!skipSetCenter) {
            map.setCenter(new GLatLng(-30.145127183376115, 143.61328125), 3);
        }

        if(cfg.zoomCtrl) map.addControl(new GLargeMapControl());

        GEvent.addListener(map, "zoomend", this.updateMarkers);

        GEvent.addListener(map, "zoomend", function() {
            if (!window['Cookies']) return;
            if ('hidden' == Cookies.get("gmap_help")) return;
            if (!$("gmap_help_popup")) return;
            if (3 < this.getZoom()) {
                $hide("gmap_help_popup");                
            }
            else {
                $show("gmap_help_popup");
            }
        });

        if(this.onMapMove) GEvent.addListener(map, "moveend", this.onMapMove);
        if(this.onMapZoom) GEvent.addListener(map, "zoomend", this.onMapZoom);

        ui.dir = document.getElementById(ui_ids["directions"]);

        gdir = new GDirections(map, ui.dir);
        GEvent.addListener(gdir, "load", onGDirectionsLoad);
        GEvent.addListener(gdir, "error", handleErrors);

        geocoder = new GClientGeocoder();

        if(this.onReady) this.onReady();
    }

    this.setData = function(data) {
        if (!data) return;

        if (data.groups) {
            for (var i in data.groups) {
                if (data.groups.hasOwnProperty(i)) {
                    var group = data.groups[i];
                    this.addGroupMarker(group);
                }
            }
        }

        if (data.motels) {
            for (var i in data.motels) {
                if (data.motels.hasOwnProperty(i)) {
                    var motel = data.motels[i];
                    this.addMarker(motel);
                }
            }
        }

        this.updateMarkers();
    }

    this.setCallback = function(target, cb) {
        callbacks[target] = cb;
    }

    this.getMapCenter = function() {
        return map.getCenter();
    }

    this.setMapCenter = function(point, zoom) {
        map.checkResize();
        map.setCenter(point, parseInt(zoom));
    }

    this.getCurrentZoom = function() {
        return map.getZoom();
    }

    this.navigateToCoordinate = function(point, zoom) {
        this.setMapCenter(point, zoom);
//        map.setCenter(point, zoom);
    }

    this.navigateToAU = function() {
        this.setMapCenter(new GLatLng(-30.145127183376115, 143.61328125), 3);
    }

    this.setDirections = function(fromAddress, toAddress, locale) {
        gdir.load("from: " + fromAddress + " to: " + toAddress, { "locale": locale });
        return false;
    }

    this.clearDirections = function() {
        ui.dir.innerHTML = '';
        ui.dir.style.display = 'none';
        gdir.clear();
        map.setCenter(new GLatLng(-30.145127183376115, 143.61328125), 3);
        return false;
    }

    this.makeAddress = function(c, s, cty) {
        var city = cty ? cty + "," : "";
        switch(c) {
            case 'au': 
                var state = s ? "," + s : "";
                return city + "Australia" + state;
                break;
            case 'nz': 
//                return city + "New Zealand, " + (s == "ni" ? "North Island" : "South Island");
                return city + "New Zealand";
                break;
        }
        return [cty, s, c].join(', ');                                                                                              
    } 

    this.findAddress = function(address) {
        geocoder.getLatLng(
                  address,
                  function(point) {
                    if (!point) {
//                      alert(address + " not found");
                    } else {
                      map.setCenter(point, 13);
                      var marker = new GMarker(point);
                      map.addOverlay(marker);
                      marker.openInfoWindowHtml(address);
                    }
                  }
                );
        return false;
    }

    var tabAccuracy = new Array(2,4,6,10,12,13,16,16,17);

    this.navigateTo = function(address, zoom) {
        geocoder.getLocations(
                  address,
                    function(response) {
                      if(response.Status.code!=200){
//                        alert('"' + address + '" not found');
                      } else {
                        var place = response.Placemark[0];
                        var accuracy = place.AddressDetails.Accuracy;
                        map.setCenter(new GLatLng(place.Point.coordinates[1],
                             place.Point.coordinates[0]), zoom ? zoom : tabAccuracy[accuracy]);
                      }
                    }
                );
        return false;
    }

    function handleErrors() {
        var html = "";
        switch(gdir.getStatus().code) {
            case G_GEO_UNKNOWN_ADDRESS:
                html = "No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.";
                break;
            case G_GEO_UNKNOWN_ADDRESS:
                html = "No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.";
                break;
            case G_GEO_SERVER_ERROR:
                html = "A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.";
                break;       
            case G_GEO_MISSING_QUERY:
                html = "The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.";
                break;
            case G_GEO_BAD_KEY:
                html = "The given key is either invalid or does not match the domain for which it was given.";
                break;
            case G_GEO_BAD_REQUEST:
                html = "A directions request could not be successfully parsed.";
                break;        
            default:
                html = "An unknown error occurred.";
        }
        $("directions").innerHTML = "<div class='message_error' style='margin-left: 10px;'>" + html + "</div>";
    }



    function onGDirectionsLoad(){ 
        $("directions").innerHTML = "";
        ui.dir.style.display = 'block';
      // Use this function to access information about the latest load()
      // results.

      // e.g.
      // document.getElementById("getStatus").innerHTML = gdir.getStatus().code;
      // and yada yada yada...
    }

    // Markers

    this.marker_data = [];

    this.markers = [];
    this.groups = [];

    this.addMarker = function() {
        var mk = arguments[0];
//        var cb = arguments[1];
        var cb = callbacks['motel'] ? callbacks['motel'] : null;

        if(mk == undefined) return;

        var baseIcon = new GIcon();
//        baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
        baseIcon.iconSize = new GSize(16, 16);
        baseIcon.shadowSize = new GSize(16, 16);
        baseIcon.iconAnchor = new GPoint(16, 16);
        baseIcon.infoWindowAnchor = new GPoint(16, 2);
        baseIcon.infoShadowAnchor = new GPoint(18, 25);

        var icon = new GIcon(baseIcon);

        //icon.image = "/static/images."+mk.host+"/motel_icon.png";
        icon.image = "/static/themes/" + mk.host + "/motel_icon.png"

        if (chain == 3 || chain == 0){
            var marker = new GMarker(new GLatLng(mk.lat, mk.lon), {icon: icon, title: mk.title});
        }else{
            var marker = new GMarker(new GLatLng(mk.lat, mk.lon), {icon: icon, title: mk.title, zIndexProcess:this.orderOfCreation});
        }
        marker.motel_id = mk.motel_id;
        marker.title = mk.title;
        marker.loaded = false;
        marker.chain_id = mk.chain_id;
        
        var html = '<div id="marker_' + this.motel_id + '">loading</div>';
        this.marker_data[mk.motel_id] = { html: html };

        marker.html = html;
        var g = this;
        GEvent.addListener(marker, 'click', cb ? cb : function() {
                //var html = g.marker_data[this.motel_id].html;
                marker.openInfoWindowHtml(this.html, {maxWidth: 300});
                if( !marker.loaded ) g.loadHTMLfor('motel', this.motel_id, marker);
            });

        map.addOverlay(marker);

        if (6 > map.getZoom()) marker.hide();

        this.markers[String(marker.motel_id)] = marker;
    }

    this.orderOfCreation = function(marker,b){
        return (marker.chain_id == chain) ? 1 : -1;
    }
    
    this.addGroupMarker = function() {
        var group = arguments[0];
        var cb = callbacks['group'] ? callbacks['group'] : null;

        var baseIcon = new GIcon();
        baseIcon.iconSize = new GSize(32, 16);
        baseIcon.shadowSize = new GSize(32, 16);
        baseIcon.iconAnchor = new GPoint(16, 8);
        baseIcon.infoWindowAnchor = new GPoint(32, 0);
        baseIcon.infoShadowAnchor = new GPoint(32, 0);

        var icon = new GIcon(baseIcon);

        var motels = group.motels.split('|');

//        icon.image = "/static/images/bmc-group" + motels.length + ".png";
        icon.image = "/static/images/"+group.host+"-group" + motels.length + ".png";
        
        var mParams = {
            icon: icon,
            title: 'Group of motels',
            draggable: true
        };
        var marker = new GMarker(new GLatLng(group.latitude, group.longitude), mParams);

        marker.disableDragging();

        marker.loaded = false;
        marker.html = '<div>loading</div>';
        
        var g = this;
        GEvent.addListener(marker, 'click', cb ? cb :function() {
                marker.openInfoWindowHtml(this.html, {maxWidth: 300});
                //if( !marker.loaded ) g.loadHTMLfor('motel_group', this.groupData.id, marker);
                if( !marker.loaded ) g.loadData('motel_group', this.groupData.id, marker);
        });

        map.addOverlay(marker);

        if (6 > map.getZoom()) marker.hide();

        marker.groupData = { 
            id: group.id,
            zoomStart: Number(group.zoom_start),
            zoomEnd: Number(group.zoom_end),
            lat: Number(group.latitude),
            lng: Number(group.longitude),
            motels: motels
        }

        this.groups[group.id] = marker;
    }


    this.removeGroup = function(id) {
        var m = this.groups[id];
        if (m) {
            map.removeOverlay(m);
            this.groups[id] = null;
        }

        this.updateMarkers();
    }

    this.updateMarkers = function() {
        gm.showMotels();
        gm.showGroups();
    }

    this.showGroups = function() {
        var z = map.getZoom();
        for (var i=0; i<this.groups.length; i++) {
            var m = this.groups[i];
            if (m) {
                if (m.groupData.zoomStart <= z && z <= m.groupData.zoomEnd) {
                    m.show();
                    for (var j=0; j < m.groupData.motels.length; j++) {
                        var m_id = m.groupData.motels[j];
                        var marker = this.markers[String(m_id)];
                        if (marker) marker.hide();
                    }
                }
                else
                    m.hide();
            }
        }
    }

    this.showMotels = function() {
        for (var i=0; i<this.markers.length; i++) {
            var m = this.markers[i];
            if (m) m.show();
        }
    }

    this.clearClickListeners = function() {
        for(var i in this.markers) { if (this.markers.hasOwnProperty(i)) {
            GEvent.clearListeners(this.markers[i], 'click');
        }}
    }

    this.loadHTMLfor = function(target, id, marker) {
        var g = this;
        new AJAX_Request(
                { url: "/index.php", 
                  params: { dialog: 'controller', action: 'get_' + target, id: id }, 
                  callback: function(request) {
                            //g.marker_data[marker.motel_id].html = request;
                            marker.html = request;
                            marker.loaded = true;
                            marker.openInfoWindowHtml(request);
//                            marker.bindInfoWindowHtml(request);
//                            marker.openInfoWindowHtml(request, {maxWidth: 300});
                        },
                  type: RTYPE_TEXT }
        );
    }

    this.loadData = function(target, id, marker) {
        var g = this;
        new AJAX_Request(
                { url: "/index.php",
                  params: { dialog: 'controller', action: 'get_' + target, id: id },
                  callback: function(r) {
                        marker.data = r;
                        marker.loaded = true;
                        g.sortGroup(id, 'motel');
                  }
                }
        );
    }

    this.sortGroup = function(id, field) {
        var m = this.groups[id];
        m.closeInfoWindow();
        m.bindInfoWindowHtml(null);
        var s_word = field == 'motel' ? 'city' : 'motel';

        if ('motel' == field) {
            m.data.sort(compareMotel);
        }
        else {
            m.data.sort(compareCity);
        }

        var html = "<strong>Motels at this location</strong>";
        html += '<br/><a href="#" onclick="javascript: gm.sortGroup(' + id + ', \'' + s_word + '\'); return false;">Sort by ' + s_word + '</a>';
        html += '<div style="margin-top: 20px;width: 320px; max-height: 220px; _height: expression( this.scrollHeight > 220 ? 220px : \'auto\');overflow-y: auto;overflow-x: hidden">';

        for (var i=0; i<m.data.length; i++) {
            var item = m.data[i];
            if (!item) continue;
            var i_html = '<div style="width: 320px;">';
            i_html += '<div style="width: 320px; zoom: 1; overflow: hidden; margin-bottom: 6px;">';
            if (item.img_src) {
                i_html += '<div style="width: 100px; height: 100px; text-align:center; margin: 0 8px 4px 0px; float: left;">';
                i_html += '<img style="border: 0; width: 100px;" src="' + item.img_src + '"/></div>';
            }
            i_html += '<div style="width: 210px; float: left;">';
            i_html += '<b>' + item.name + '</b><br/><br/>';
            i_html += item.street + '<br/>';
            i_html += item.city;
            i_html += item.state ? ', ' + item.state : '';
            i_html += item.post_code ? ', ' + item.post_code : '';
            i_html += '<br/><a href="' + item.member_url + '">Member site</a>';
            i_html += '</div>';
            i_html += '</div></div>';
            html += i_html;
        }

        html += '</div>';

        m.html = "<div class='gmap_motel_popup'>" + html + "</div>";

        m.openInfoWindowHtml(m.html);
//        m.bindInfoWindowHtml(m.html);
    }

    function compareMotel(a, b) {
        if (a.name < b.name)
            return -1;
        if (a.name > b.name)
            return 1;
        return 0;
    }

    function compareCity(a, b) {
        if (a.city < b.city)
            return -1;
        if (a.city > b.city)
            return 1;
        return 0;
    }
    this.onHTML = function() {
    }

    this.hideAllMarkers = function() {
        activeIDs = [];
        for (var i in this.markers) {
            if (this.markers.hasOwnProperty(i)) {
                var m = this.markers[i];
                m.hide();
            }
        }
    }

    this.hideAllGroups = function() {
        for (var i in this.groups) {
            if (this.groups.hasOwnProperty(i)) {
                var g = this.groups[i];
                if (g) g.hide();
            }
        };
    }

    this.showMarkerById = function(id) {
        var m = this.markers[id];
        if( m ) m.show();
    }


    this.calcZoom = function(c, st, cty) {
        if(cty) return null;
        if(c == 'nz') return 5;
        if(st) {
            if(st == 'act') return 9;
            if(st == 'tas') return 7;
            return 5;
        }
        return null;
    }


    this.getMapObject = function() {
        return map;
    }

};
