// VEE AJAX functionality for searching
// (c) 2009 Loco (Loohuis Consulting), http://www.loohuis-consulting.nl/
// This work is licensed under a
// Creative Commons Attribution-Share Alike 3.0 Netherlands License
// see http://www.loohuis-consulting.nl/development/cc-by-sa.php


document.observe('dom:loaded', function() {new VEESearch();});

var VEESearch = Class.create({
    // script url
    url: window.location.protocol + '//' + window.location.host + window.location.pathname,
    // search application interface
    searchAppURL: 'http://www.vaneigenerf.nl/search/app.php',
    // google map
    map: null,
    // global marker storage
    markers: new Array(),
    // lookup table, use indexOf to find marker
    markerLookup: new Array(),
    mgr: null,
    // zoom level at which markers appear
    markerThreshold: 7,
    // active location
    active: null,
    // default layout of map
    defaultCenter: new GLatLng(52, 5),
    defaultZoom: 10,
    locateZoom: 11,
    // route directions
    directions: null,
    // suggestions
    // minimum length to show suggestions for
    minSuggestLength: 3,
    // timeout before fetching suggestions in milliseconds
    suggestTimeout: 700,
    suggestTimer: null,
    // location to show at display
    showLocation: null,

    initialize: function(el)
    {
        // create the icons
        this.veeIcon = new GIcon();
        this.veeIcon.image = "/skin/vee-point.png";
        this.veeIcon.iconSize = new GSize(22, 22);
        this.veeIcon.iconAnchor = new GPoint(1, 21);
        this.veeIcon.infoWindowAnchor = new GPoint(1, 21);
        this.noveeIcon = new GIcon();
        this.noveeIcon.image = "/skin/no_vee-point.png";
        this.noveeIcon.iconSize = new GSize(22, 22);
        this.noveeIcon.iconAnchor = new GPoint(1, 21);
        this.noveeIcon.infoWindowAnchor = new GPoint(1, 21);
        this.afhaalIcon = new GIcon();
        this.afhaalIcon.image = "/skin/afhaal-point.png";
        this.afhaalIcon.iconSize = new GSize(22, 22);
        this.afhaalIcon.iconAnchor = new GPoint(1, 21);
        this.afhaalIcon.infoWindowAnchor = new GPoint(1, 21);
        // load the search interface
        if ($('searchapp')) {
            this.searchType = $('searchapp').getAttribute('searchtype');
            this.searchGroup = $('searchapp').getAttribute('searchgroup');
            this.search = window.location.search.toQueryParams();
            if (this.search.locatie)
                this.showLocation = this.search.locatie;
            new Ajax.Updater('searchapp', this.searchAppURL, {
                method: 'get',
                parameters: {
                    'newstyle': 1,
                    'vind': this.search.vind,
                    'locatie': this.search.locatie,
                    'searchtype': this.searchType,
                    'productgroep': this.searchGroup
                },
                onCreate: function() {$('throbber').show()},
                onComplete: function ()
                {
                    Event.observe(window, 'unload', GUnload, false);
                    this.loadMap();
                    $('searchform').observe('submit', this.setLocation.bindAsEventListener(this));
                    $('location').observe('keyup', this.getSuggestions.bindAsEventListener(this));
                    $('location').observe('focus', function(e) {Event.element(e).clear()});
                    $('searchtype').observe('change', this.reloadInterface.bindAsEventListener(this));
                    $('productgroep').observe('change', this.reloadInterface.bindAsEventListener(this));
                    if (this.search.locatie)
                        $('location').value = this.search.locatie.replace(/\+/g, ' ');
                    this.initMap();
                }.bind(this)
            });
        }
    },

    // reload interface with new mode
    reloadInterface: function(e)
    {
        this.directions.clear();
        var elm = Event.element(e);
        var newType = $F('searchtype');
        var newGroup = $F('productgroep');
        var searchType = $('searchapp').getAttribute('searchtype');
        var searchGroup = $('searchapp').getAttribute('searchgroup');
        if (newType != searchType || newGroup != searchGroup) {
            $('searchapp').setAttribute('searchtype', newType);
            $('searchapp').setAttribute('searchgroup', newGroup);
            this.search = window.location.search.toQueryParams();
            new Ajax.Updater('searchapp', this.searchAppURL, {
                method: 'get',
                parameters: {
                    'searchtype': newType,
                    'productgroep': newGroup,
                    'newstyle': 1
                },
                onCreate: function() {$('throbber').show()},
                onComplete: function ()
                {
                    $('searchform').observe('submit', this.setLocation.bindAsEventListener(this));
                    $('location').observe('keyup', this.getSuggestions.bindAsEventListener(this));
                    $('location').observe('focus', function(e) {Event.element(e).clear()});
                    $('searchtype').observe('change', this.reloadInterface.bindAsEventListener(this));
                    $('productgroep').observe('change', this.reloadInterface.bindAsEventListener(this));
                    if (this.search.locatie)
                        $('location').value = this.search.locatie.replace(/\+/g, ' ');
                    this.initMap();
                }.bind(this)
            });
        }
        Event.stop(e);
    },

    // load Google map
    loadMap: function()
    {
        this.map = new GMap2($("searchmap"));
        this.map.addControl(new GLargeMapControl3D());
        this.map.addControl(new GHierarchicalMapTypeControl()); // GMapTypeControl
        this.map.removeMapType(G_SATELLITE_MAP);
        this.map.removeMapType(G_HYBRID_MAP);
        this.map.addMapType(G_PHYSICAL_MAP);
        G_PHYSICAL_MAP.getMinimumResolution = function () { return 8 };
        G_NORMAL_MAP.getMinimumResolution = function () { return 8 };
        this.map.addControl(new GScaleControl());
        // adjust the map to its previous state
        var oldZoom = parseInt($F('oldzoom'));
        var oldLon = $F('oldlon');
        var oldLat = $F('oldlat');
        this.map.setCenter(new GLatLng(oldLat, oldLon), oldZoom);
        this.map.enableScrollWheelZoom();
        this.map.setMapType(G_PHYSICAL_MAP);
        GEvent.addListener(this.map, 'moveend', this.refreshSearch.bindAsEventListener(this));
        this.mgr = new MarkerManager(this.map);

        this.directions = new GDirections(this.map, $('directions'));
    },

    // initialize the map markers etc.
    initMap: function()
    {
        this.map.clearOverlays();
        this.mgr.clearMarkers();
        this.markers.clear();
        this.markerLookup.clear();
        // get point data
        var json = eval($('locationdata').points.value);
        var points = $A(json.points);
        points.each(function(p)
        {
            if (p && p.lat > 0 && p.lon > 0) {
                if (p.veelid > 0)
                    var m = new GMarker(new GLatLng(p.lat, p.lon), this.veeIcon);
                else if (p.afhaalpunt > 0)
                    var m = new GMarker(new GLatLng(p.lat, p.lon), this.afhaalIcon);
                else
                    var m = new GMarker(new GLatLng(p.lat, p.lon), this.noveeIcon);
                m.lid = p.lid;
                GEvent.addListener(m, 'click', function() {this.showInfo(m)}.bind(this));
                // store markers in array, and keep id index
                this.markers.push(m);
                this.markerLookup.push(p.lid);
            }
        }, this);
        // use marker manager
        this.mgr.addMarkers(this.markers, this.markerThreshold);
        this.mgr.refresh();
        // add KML areas if required
        if ($F('searchtype') == 'afhaalpunt') {
            kml1 = new GGeoXml("http://www.vaneigenerf.nl/data/gezondgemak.kml?" + (new Date()).valueOf());
            kml2 = new GGeoXml("http://www.vaneigenerf.nl/data/haiboerhai.kml?" + (new Date()).valueOf());
            kml3 = new GGeoXml("http://www.vaneigenerf.nl/data/biowebfryslan.kml?" + (new Date()).valueOf());
            kml4 = new GGeoXml("http://www.vaneigenerf.nl/data/biologischgoed.kml?" + (new Date()).valueOf());
            kml5 = new GGeoXml("http://www.vaneigenerf.nl/data/hetgroenespoor.kml?" + (new Date()).valueOf());
            kml6 = new GGeoXml("http://www.vaneigenerf.nl/data/degroteverleiding.kml?" + (new Date()).valueOf());
            kml7 = new GGeoXml("http://www.vaneigenerf.nl/data/hww.kml?" + (new Date()).valueOf());
            this.map.addOverlay(kml1);
            this.map.addOverlay(kml2);
            this.map.addOverlay(kml3);
            this.map.addOverlay(kml4);
            this.map.addOverlay(kml5);
            this.map.addOverlay(kml6);
            this.map.addOverlay(kml7);
        }
        // update search results
        this.refreshSearch();
    },

    // refresh search results on map events dragend, moveend, and zoomend
    // note: drag and zoom events also trigger move event
    refreshSearch: function()
    {
        var zoom = this.map.getZoom();
        var center = this.map.getCenter();
        var bounds = this.map.getBounds();
        var searchType = $F('searchtype');
        var searchGroup = $F('productgroep');
        new Ajax.Updater('searchresults', searchAppURL, {
            parameters: {
                'search': '1',
                'searchtype': searchType,
                'productgroep': searchGroup,
                'zoom': zoom,
                'lon': center.lng(),
                'lat': center.lat(),
                'north': bounds.getNorthEast().lat(),
                'east': bounds.getNorthEast().lng(),
                'south': bounds.getSouthWest().lat(),
                'west': bounds.getSouthWest().lng()
            },
            onCreate: function() {$('searchresults').update(); $('throbber').show();}, // clear results area
            onComplete: function() {
                // show appropriate results header
                $$('p.label').each(function(p) {
                    var st = p.getAttribute('searchtype');
                    if (st == searchType)
                        p.show();
                    else
                        p.hide();
                });
                // add triggers
                $$('.blowup').each(function(l)
                {
                    // show info window for marker
                    var lid = l.getAttribute('name');
                    var m = this.markers[this.markerLookup.indexOf(lid)];
                    l.observe('click', function() {this.showInfo(m)}.bind(this));
                }, this);
                $$('.infolayer').each(function(l) {l.observe('click', this.showOverlay.bindAsEventListener(this));}, this);
                $$('.routeplanner').each(function(l) {l.observe('click', this.showRouteForm.bindAsEventListener(this));}, this);
                if (this.active) {
                    var links = $$('.blowup').each(function(l) { l.up('div').removeClassName('active')});
                    $('lid_' + this.active).addClassName('active');
                    this.active = null;
                }
                $('throbber').hide();
            }.bind(this)
        });
    },

    // show info window over marker, fetch HTML dynamically
    showInfo: function(m)
    {
        this.directions.clear();
        new Ajax.Request(this.searchAppURL,
        {
            parameters: {'infowindow': m.lid},
            onComplete: function(t)
            {
                // FIXME: add event handlers on links here!
                var links = $$('.blowup').each(function(l) { l.up('div').removeClassName('active')});
                $('lid_' + m.lid).addClassName('active');
                m.openInfoWindowHtml(t.responseText);
                $$('.infolayer').each(function(l) {l.observe('click', this.showOverlay.bindAsEventListener(this));}, this);
                $$('.routeplanner').each(function(l) {l.observe('click', this.showRouteForm.bindAsEventListener(this));}, this);
                if (this.active) {
                    var links = $$('.blowup').each(function(l) { l.up('div').removeClassName('active')});
                    $('lid_' + this.active).addClassName('active');
                    this.active = null;
                }
                this.active = m.lid;
            }.bind(this)
        });
    },

    // show info overlay
    showOverlay: function(e)
    {
        this.directions.clear();
        elm = Event.element(e);
        var lid = elm.getAttribute('name');
        new Ajax.Request(this.searchAppURL, {
            parameters: {
                'overlay': 1,
                'profile': lid
            },
            onSuccess: function(r) {
                $('inner').update(r.responseText);
                $('overlay').show();
                $('inner').show();
                $('closelink').observe('click', this.closeOverlay);
            }.bind(this)
        });
        Event.stop(e);
    },

    // close info overlay
    closeOverlay: function(e)
    {
        $('inner').update();
        $('inner').hide();
        $('overlay').hide();
    },

    // show route planer input form
    showRouteForm: function(e)
    {
        elm = Event.element(e);
        var to = elm.getAttribute('name');
        var routeForm = $('routeform').cloneNode(true);
        routeForm.routeto.value = to;
        routeForm.observe('submit', this.getRoute.bindAsEventListener(this));
        if (elm.up('p'))
            elm.up('p').replace(routeForm);
    },

    // get directions
    getRoute: function(e)
    {
        elm = Event.element(e);
        this.map.closeInfoWindow();
        this.directions.load('from: ' + elm.routefrom.value + ' to: ' + elm.routeto.value, {locale: 'nl_NL'});
        Event.stop(e);
    },

    // adjust map location based on search
    setLocation: function(e)
    {
        this.directions.clear();
        clearTimeout(this.suggestTimer);
        $('suggestions').hide();
        $('location').blur();
        elm = Event.element(e);
        new Ajax.Request(this.searchAppURL, {
            parameters: {
                'location': $F('location').replace('vul hier je woonplaats in', ''),
                'searchtype': $F('searchtype'),
                'productgroep': $F('productgroep')
            },
            onComplete: function(r) {
                if (r.responseJSON.adjust.error) {
                    this.map.setCenter(defaultCenter, defaultZoom);
                }
                else if (r.responseJSON.adjust.lat > 0 && r.responseJSON.adjust.lon > 0) {
                    if (r.responseJSON.adjust.zoom)
                        this.map.setCenter(new GLatLng(parseFloat(r.responseJSON.adjust.lat), parseFloat(r.responseJSON.adjust.lon)), parseInt(r.responseJSON.adjust.zoom));
                    else
                        this.map.setCenter(new GLatLng(parseFloat(r.responseJSON.adjust.lat), parseFloat(r.responseJSON.adjust.lon)), this.locateZoom);
                }
            }.bind(this)
        });
        Event.stop(e);
    },

    // get suggestions for location
    getSuggestions: function(e)
    {
        clearTimeout(this.suggestTimer);
        $('suggestions').hide();
        this.suggestBase = $F('location');
        // only retrieve suggestions if minimum length
        // and doesn't start with digit (exclude pcodes)
        if ((this.suggestBase.length >= this.minSuggestLength) && (!this.suggestBase.match(/^\s*\d/))) {
            this.suggestTimer = setTimeout(this.getDelayedSuggestions.bind(this), this.suggestTimeout);
        }
    },

    // delayed suggestion fetch
    getDelayedSuggestions: function()
    {
        new Ajax.Request(searchAppURL, {
            parameters: {
                'suggest': this.suggestBase
            },
            onSuccess: function(r) {
                if (r.responseJSON.length) {
                    // empty suggestions and add new options
                    $('suggestions').update();
                    r.responseJSON.each(function(l) {
                        // add links
                        $('suggestions').insert({bottom: '<li><a href="#" name="' + l + '">' + l + '</a></li>'});
                    });
                    // add handler to all options
                    $$('#suggestions a').each(function(a) {
                        a.observe('click', this.setCity.bindAsEventListener(this));
                    }, this);
                    $('suggestions').show();
                }
            }.bind(this)
        });
    },

    // set a city as the location and refresh the search
    setCity: function(e)
    {
        elm = Event.element(e);
        $('location').value = elm.name;
        $('suggestions').hide();
        this.setLocation(e);
    }

});
