createPackage('nl.grip.cms.maps', 'maps');

maps.Map = function(selector, width, height, options)
{
    this.selector = selector;
    this.width = width || 500;
    this.height = height || 300;
    this.options = options || {};
    this.autoLoad = options['autoload'] || true;

    this.bounds = [];
    this.center = [];
    this.locations = {};
    this.points = [];
    this.icons = [];
    this.markers = {};

    this.map = null;
    this.routeForm = null;

    this.getObject = function()
    {
        return $(this.selector);
    }

    this.addLocation = function(name, lat, lng, opts)
    {
        this.locations[name] = [lat, lng, opts];
    }

    this.createMarker = function(name, lat, lng, opts)
    {
        var title = opts.title || '';
        var body = opts.body || '';
        var address = opts.address || '';
        var href = opts.href || '';
        var external = opts.external || '';
        var icon = opts.icon || '';

        var point = new google.maps.LatLng(lat, lng);
        this.points.push(point);

        var marker = new google.maps.Marker(point, { icon:this.icons[icon] });
        marker.address = address;

        if (href != '') {
            if (external == 'external') {
                title = '<a href="' + href + '" target="_blank">' + title + '</a>';
            } else {
                title = '<a href="' + href + '">' + title + '</a>';
            }
        }

        var text = '<h2 class="markerheader">' + title + '<\/h2>' + '<div class="markerbody">' + body + '<\/div>';

        // add route form when address is specified
        if (address) {
            this.routeForm = new cms.maps.RouteForm(this);

            var form = '<form class="route" onsubmit="map.routeForm.submitRouteForm(); return false;"><label>' + cms.Lang.getText('RouteDepartureLocation') + '</label><br/><input type="text" name="departure" id="departure"><input class="submit" type="submit" value="' + cms.Lang.getText('RouteExecute') + '"><\/form>';

            text = text + form + '<br/>';
        }

        google.maps.Event.addListener(marker, 'click', function() { marker.openInfoWindowHtml(text); });
        google.maps.Event.addListener(marker, 'infowindowopen', function() { this.opened = true; });

        this.points.push(point);
        this.markers[name] = marker;

        return marker;
    }

    this.setIcon = function(name)
    {
        this.icons[name] = new google.maps.Icon(G_DEFAULT_ICON);
    }

    this.setIconProperty = function(name, property, value)
    {
        this.icons[name].property = value;
    }

    this.setBounds = function(bottomLeftLat, bottomLeftLng, topRightLat, topRightLng)
    {
        this.bounds = [bottomLeftLat, bottomLeftLng, topRightLat, topRightLng];
    }

    this.setCenter = function(lat, lng)
    {
        this.center = [lat, lng];
    }

    /**
     * Apply view on a map
     * @param Object view The view must hold: (x,y,z) for setting center and zoom level and/or (m) for map type
     * @param GMap2 map The map to apply view on
     * @return void
     */
    this.applyMapView = function(view)
    {
        if (view.m) {
            mapTypes = this.map.getMapTypes();
            this.map.setMapType(mapTypes[view.m]);
        }

        if (view.x && view.y) {
            this.map.setCenter(new google.maps.LatLng(view.x, view.y));
        }

        if (view.z) {
            this.map.setZoom(parseInt(view.z));
        }

        if (view.sm) {

            // apply selected marker
            if (this.markers[view.sm]) {
                google.maps.Event.trigger(this.markers[view.sm], 'click');
            }
        }

        this.map.savePosition();

    }

    this.updateMapLink = function()
    {
        var url = window.location.toString();
        var currentFragment = window.location.hash;

        // strip hash from the url: we create it ourself
        if (currentFragment.length > 0) {
            url = url.substring(0, url.length - currentFragment.length);
        }

        url = url + '#';

        // determine selected map type
        var m = -1;
        var mapTypes = this.map.getMapTypes();
        var mapType = this.map.getCurrentMapType();
        if (mapTypes && mapType) {
            for (var i = 0; i < mapTypes.length; i++) {
                if (mapTypes[i] == mapType) m = i;
            }
        }
        if (m > -1) {
            url = url + (url.substr(url.length - 1, 1) != '#' ? ';' : '') + 'm=' + m.toString();
        }

        // get selected center
        var center = this.map.getCenter();
        if (center) {
            url = url + (url.substr(url.length - 1, 1) != '#' ? ';' : '') + 'x=' + center.lat() + ';y=' + center.lng();
        }

        // determine selected zoom level
        var z = this.map.getZoom();
        if (z) {
            url = url + (url.substr(url.length - 1, 1) != '#' ? ';' : '') + 'z=' + z.toString();
        }

        // determine selected marker
        var el = this.getSelectedMarkerName();
        if (el) {
            url = url + (url.substr(url.length - 1, 1) != '#' ? ';' : '') + 'sm=' + el;
        }

        if (url.substr(url.length - 1, 1) == '#') url = url.substr(0, url.length - 1);

        $('#maplink').attr('href', url);
    }

    /**
     * Initializes 'link to this page' on the <a> node with the map
     * @param DOMNode node The <a> node
     * @param GMap2 map The map to get state from
     * @param string label The text to show in the link
     */
    this.createMapLink = function()
    {
        var link = $('<a id="maplink" class="permalink" href="' + window.location.toString() + '">' + cms.Lang.getText('LinkToCurrentPage') + '</a>');
        this.getObject().after(link);

        link.mouseover(EventUtils.Delegate.create(this, 'mouseover', this.updateMapLink));
    }

    /**
     * Returns selected marker name (if any selected)
     * @return String
     */
    this.getSelectedMarkerName = function()
    {
        if (this.markers) {
            for (el in this.markers) {
                if (this.markers[el].opened == true) {
                    return el;
                    break;
                }
            }
        }
        return null;
    }

    /**
     * Returns selected marker (if any selected)
     * @return GMarker
     */
    this.getSelectedMarker = function()
    {
        var el = this.getSelectedMarkerName();
        if (el && this.markers[el]) {
            return this.markers[el];
        }
        return null;
    }


    this.load = function()
    {
        if (google.maps.BrowserIsCompatible()) {

            // adjust dimensions
            this.getObject().css({'width' : this.width, 'height' : this.height});

            this.map = new google.maps.Map2(this.getObject().get(0), this.options);

            var bottomLeft = new google.maps.LatLng(this.bounds[0], this.bounds[1]);
            var topRight = new google.maps.LatLng(this.bounds[2], this.bounds[3]);
            var bounds = new google.maps.LatLngBounds(bottomLeft, topRight);

            var zoomlevel = this.map.getBoundsZoomLevel(bounds);

            if (zoomlevel == 19) {
                zoomlevel = zoomlevel - 6;
            }
            
            if (zoomlevel > 16){ zoomlevel = 14; }
            

            this.map.addControl(new google.maps.MapTypeControl());
            this.map.addControl(new google.maps.LargeMapControl3D());
            this.map.setCenter(new google.maps.LatLng(this.center[0], this.center[1]), zoomlevel);

            // add markers
            for (var a in this.locations) {

                var marker = this.createMarker(a, this.locations[a][0], this.locations[a][1], this.locations[a][2]);
                this.map.addOverlay(marker);
            }

            // set fragment params
            var customView = cms.getFragmentParams();
            if (customView) {
                this.setCustomView(customView);
            }

            // add link to current map position
//            this.createMapLink();

            // add unload event to plug memory leaks when leaving the page
            EventUtils.addUnloadEvent(google.maps.Unload);
        }
    }

    if (this.autoLoad) {
        $(EventUtils.Delegate.create(this, 'load', this.load));
    }
}

maps.RouteForm = function(map)
{
    this.map = map;

    /**
     * Process route form
     * @return boolean false (to prevent form actually being submitted)
     */
    this.submitRouteForm = function ()
    {
        var sm = this.map.getSelectedMarker();
        var departure = document.getElementById("departure").value;

        if (sm) {

            var dir = new google.maps.Directions(this.map.map, document.getElementById('route'));

            google.maps.Event.addListener(dir, "load", this.processRouteLoad);
            google.maps.Event.addListener(dir, "addoverlay", this.processRouteResult);

            dir.loadFromWaypoints([departure, sm.address], {locale : "nl_NL"});

        }

        return false;
    }

    /**
     * Event handler for route request
     * @return void
     */
    this.processRouteLoad = function()
    {
        // this method gets called when a user submits a route request
    }

    /**
     * Event handler for route response
     * @return void
     */
    this.processRouteResult = function()
    {
        // TODO test if any route was found

        //var sm = this.map.getSelectedMarker();
        //if (sm) {
        //    sm.closeInfoWindow();
        //}
        // TODO adjust margins for route
        // TODO add 'clear route' link
    }
}

