// Triodos Bank JavaScript for Google Maps implementations
// Utility and MGGG common library
// Version: 1.0 (2010-08-12)
// Author: Wouter van der Graaf, Dynora, NL

if (typeof triodos === 'undefined') {
    var triodos = {};
}

triodos.STATIC_URL = '/static/';

triodos.utils = {
    urlencode: function () {
        var re = /\+/g;
        return function (s) {
            return escape(s).replace(re, '%2B');
        };
    }(),
    
    geocoderTypeToAccuracy: {
        country: 1,
        administrative_area_level_1: 2,
        administrative_area_level_2: 3,
        administrative_area_level_3: 3,
        locality: 4,
        sublocality: 4,
        neighborhood: 5,
        postal_code: 5,
        route: 6,
        intersection: 7,
        street_address: 8,
        premise: 9,
        subpremise: 9
    },

    initMapReadyCalling: function (map) {
        if (typeof map.triodos === 'undefined') {
            map.triodos = {};
        }
        map.triodos.ready = false;
        map.triodos.readyCallables = [];
        var listener = google.maps.event.addListener(map, 'tilesloaded', function () {
            google.maps.event.removeListener(listener);
            map.triodos.ready = true;
            $j.each(map.triodos.readyCallables, function (i, fn) {
                fn();
            });
            map.triodos.readyCallables = [];
        });
    },
    
    callWhenMapReady: function (map, fn) {
        if (typeof map.triodos === 'undefined' || typeof map.triodos.ready === 'undefined') {
            throw new Error('MapReady calling must first be initialized with triodos.utils.initMapReadyCalling function.');
        }
        if (map.triodos.ready) {
            fn();
        }
        else {
            map.triodos.readyCallables.push(fn);
        }
    },
    
    initMap: function (options) {
        // options: el, lat, lng, zoom
        if (!options.el) {
            return null;
        }
        // set initial viewport to branch meta data
        var initCenter;
        var initZoom;
        if (options.lat && options.lng && options.zoom) {
            initCenter = new google.maps.LatLng(options.lat, options.lng);
            initZoom = parseInt(options.zoom, 10);
        }

        // init map
        var map = new google.maps.Map(options.el, {
            center: initCenter,
            zoom: initZoom,
            mapTypeId: options.mapTypeId,
            streetViewControl: true
        });

       
        if (options.bounds) {
            map.fitBounds(options.bounds);
        }
        
        triodos.utils.initMapReadyCalling(map);
        var manager = new MarkerManager(map, {
            borderPadding: 20
        });
        return [map, manager];
    },
    
    markerDistribution: {
        zoomMultipliers: [
            [0, .25],
            [3, .5],
            [4, .75],
            [5, 1.25],
            [6, 2.5],
            [7, 5],
            [8, 10],
            [9, 20]
        ],
        generateKey: function (i, lat, lng) {
            var mult = triodos.utils.markerDistribution.zoomMultipliers[i][1];
            return (parseInt(lat * mult, 10) / mult) + ',' + (parseInt(lng * mult, 10) / mult);
        }
    },
    
    placeMarkers: function (options) {
        // options: map, manager, markerFactory, data (objects must have lat and lng properties)
        var markers = [];
        var map = options.map;
        
        // check for first time placement
        if (typeof map.triodos === 'undefined') {
            map.triodos = {};
        }
        if (!map.triodos.distributionPockets) {
            var pockets = map.triodos.distributionPockets = [];
            var distMarkers = map.triodos.distributedMarkers = [];
            $j.each(triodos.utils.markerDistribution.zoomMultipliers, function () {
                pockets.push({});
                distMarkers.push([]);
            });
            // container for remaining markers
            distMarkers.push([]);
        }
        else {
            var pockets = map.triodos.distributionPockets
            var distMarkers = map.triodos.distributedMarkers;
        }
        // optionally make highlighted items determine map viewport
        if (!map.triodos.highlightedBounds) {
            map.triodos.highlightedBounds = new google.maps.LatLngBounds();
        }
        var bounds = map.triodos.highlightedBounds;
        var fitBounds = false;
        $j.each(options.data, function (i, item) {
            item.lat = parseFloat(item.lat);
            item.lng = parseFloat(item.lng);
            if (item.lat && item.lng) {
                markers.push(options.markerFactory(map, item));
                if (item.highlighted) {
                    fitBounds = true;
                    bounds.extend(new google.maps.LatLng(item.lat, item.lng));
                }
            }
        });
        if (fitBounds) {
            map.fitBounds(bounds);
        }
        
        $j.each(markers, function (i, m) {
            var assigned = false;
            var idx = 0;
            while (!assigned) {
                var key = triodos.utils.markerDistribution.generateKey(idx, m.getPosition().lat(), m.getPosition().lng());
                if (!pockets[idx][key]) {
                    pockets[idx][key] = true;
                    distMarkers[idx].push(m);
                    assigned = true;
                }
                else if (idx === pockets.length - 1) {
                    distMarkers[pockets.length].push(m);
                    assigned = true;
                }
                else {
                    idx++;
                }
            }
        });
        var zoomMp = triodos.utils.markerDistribution.zoomMultipliers;
        var allMarkers = [];
        var minZoomLevel = 10000;
        $j.each(distMarkers, function (i, markerList) {
            (function (idx, listMarkers) {
                /*setTimeout(function () {*/
                var minZoom = zoomMp[zoomMp.length - 1][0] + 1;
                if (idx < zoomMp.length) {
                    minZoom = zoomMp[idx][0];
                    if(minZoom < minZoomLevel){
                        minZoomLevel = minZoom;
                    }
                }
                $j.each(listMarkers, function (i, m) {
                    //options.manager.addMarker(m, minZoom);
                    allMarkers.push(m);
                });
                /*}, 250 * idx);*/
            })(i, markerList);
        });
        options.manager.addMarkers(allMarkers, minZoomLevel);
        options.manager.refresh();
    },

    getBounds : function(data){
        var bounds = new google.maps.LatLngBounds();
        $j.each(data, function (i, item) {
            item.lat = parseFloat(item.lat);
            item.lng = parseFloat(item.lng);
            if (item.lat && item.lng) {
                if (item.highlighted) {
                    bounds.extend(new google.maps.LatLng(item.lat, item.lng));
                }
            }
        });
        return bounds;
    }
    
};

triodos.mggg = {

    markerOptions: {
        local: {
            currentBranch: new google.maps.MarkerImage(
            'http://chart.apis.google.com/chart?cht=mm&chs=20x32&chco=FF4200FF,FF4200FF,000000FF&ext=.png',
            new google.maps.Size(20, 32),
            new google.maps.Point(0, 0),
            new google.maps.Point(10, 32)
        ),
            otherBranch: new google.maps.MarkerImage(
            'http://chart.apis.google.com/chart?cht=mm&chs=20x32&chco=D8D8D8FF,D8D8D8FF,000000FF&ext=.png',
            new google.maps.Size(20, 32),
            new google.maps.Point(0, 0),
            new google.maps.Point(10, 32)
        )
        },
        remote: {
            currentBranch: new google.maps.MarkerImage(
            'http://chart.apis.google.com/chart?cht=mm&chs=14x24&chco=FF4200FF,FF4200FF,000000FF&ext=.png',
            new google.maps.Size(14, 24),
            new google.maps.Point(0, 0),
            new google.maps.Point(7, 24)
        ),
            otherBranch: new google.maps.MarkerImage(
            'http://chart.apis.google.com/chart?cht=mm&chs=14x24&chco=D8D8D8FF,D8D8D8FF,000000FF&ext=.png',
            new google.maps.Size(14, 24),
            new google.maps.Point(0, 0),
            new google.maps.Point(7, 24)
        )
        }
    },
    
    markerFactory: function (map, item) {
        var options = {
            position: new google.maps.LatLng(item.lat, item.lng),
            shape: []
        };
        var key = 'remote';
        if (item.highlighted) {
            key = 'local';
        }
        var markerOpts = triodos.mggg.markerOptions[key];        
        if (item.bch === triodos.mggg.currentBranch) {
            options.icon = markerOpts.currentBranch;
        }
        else {
            options.icon = markerOpts.otherBranch;
        }
        //options.shadow = markerOpts.shadow;
        var marker = new google.maps.Marker(options);
        google.maps.event.addListener(marker, 'click', function () {
            if (map.triodos.activeInfoWindow) {
                map.triodos.activeInfoWindow.close();
            }
            if (typeof marker.infoWindow === 'undefined') {
                var infoWindowOptions = {
                    content: triodos.mggg.createInfoWindowContent(map, item)
                };
                marker.infoWindow = new google.maps.InfoWindow(infoWindowOptions);
            }
            setTimeout(function () {
                marker.infoWindow.open(map, marker);
                map.setZoom(map.getZoom()); // fixes weird disappearance bug in all browsers
            }, 0); // zero timeout to fix rendering bug in Firefox
            map.triodos.activeInfoWindow = marker.infoWindow;

            $j(".infowindow .moreInfo").live("click.marker", function () {
                _gaq.push(['_trackEvent', 'Mggg Map', 'Click more info', item.nam]);
            });
            $j(".infowindow .zoomIn").live("click.marker", function () {
                _gaq.push(['_trackEvent', 'Mggg Map', 'Click zoom in', item.nam]);
            });

        });
        google.maps.event.addListener(map, 'click', function () {
            if (map.triodos.activeInfoWindow) {
                map.triodos.activeInfoWindow.close();
            }
        });
        return marker;
    },
    
    zoomerText: translate('mgggbundle', 'balloon.zoomInOnMap.label') || 'Zoom',
    infoText: translate('mgggbundle', 'balloon.moreInfo.label') || 'Info',
    
    createInfoWindowContent: function (map, item) {
        var header = [
            item.vis && item.vis.length > 0 ? '<img src="' + item.vis + '" class="ethumb" width="80" height="60">' : '',
            '<div class="sector">', item.sec, '</div><strong class="title">',
            (item.hpg ? '<a href="' + item.url + '">' : ''),
            item.nam,
            (item.hpg ? '</a>' : ''),
            '</strong>'
        ].join('');

        item.hno = !item.hno ? '' : item.hno;
            
        if (triodos.mggg.country === 'GB') {
            var content = [
                header,
                    !item.hid || item.hid === item.nam ? '' : '<div class="house_identifier">' + item.hid + '</div>',
                    !item.adr ? '' : '<div class="street_address">' + item.adr + ' ' + item.hno + '</div>',
                    !item.sub || item.sub === item.nam ? '' : '<div class="subbuilding">' + item.sub + '</div>',
                    !item.slo ? '' : '<div class="sublocality">' + item.slo + '</div>',
                    !item.dis ? '' : '<div class="district">' + item.dis + '</div>',
                    !item.loc ? '' : '<div class="locality_name">' + item.loc + '</div>',
                    !item.pro ? '' : '<div class="state_or_province_name">' + item.pro + '</div>',
                    !item.cou ? '' : '<div class="country_name">' + item.cou + '</div>'
            ];
        }
        else {
            var content = [
                header,
                    !item.sub || item.sub === item.nam ? '' : '<div class="subbuilding">' + item.sub + '</div>',
                    !item.hid || item.hid === item.nam ? '' : '<div class="house_identifier">' + item.hid + '</div>',
                    !item.adr ? '' : '<div class="street_address">' + item.adr + ' ' + item.hno + '</div>',
                    !item.slo ? '' : '<div class="sublocality">' + item.slo + '</div>',
                    !item.dis ? '' : '<div class="district">' + item.dis + '</div>',
                    !item.loc ? '' : '<div class="locality_name">' + item.loc + '</div>',
                    !item.pro ? '' : '<div class="state_or_province_name">' + item.pro + '</div>',
                    !item.cou ? '' : '<div class="country_name">' + item.cou + '</div>'
            ];
        }
        if (item.vis & item.vis.length > 0) {
            className = 'infowindow_novisual';
        }
        else {
            className = 'infowindow';
        }
        var el = $j('<div class="' + className + '"></div>');
        el.html(content.join(''));

        var zoomer = $j('<a class="zoomIn" href="javascript:;">' + triodos.mggg.zoomerText + '</a>');
        el.append(zoomer);
        zoomer.click(function () {
            map.setCenter(new google.maps.LatLng(item.lat, item.lng));
            map.setZoom(15);
        });
        
        if (item.hpg) {
            el.append('<a class="moreInfo" href="' + item.url + '">' + triodos.mggg.infoText + '</a>');
        }
        
        return el[0];
    },

    displayMapView: function(map, view) {
        var lat = $j('meta[name=' + view + 'Lat]').attr('content');
        var lng = $j('meta[name=' + view + 'Lng]').attr('content');
        var zoom = $j('meta[name=' + view + 'ZoomLevel]').attr('content');
        if (lat && lng && zoom) {
            map.setCenter(new google.maps.LatLng(lat, lng));
            map.setZoom(parseInt(zoom, 10));
        }
    },

    trackZoom: function(map) {
        var prevZoomLevel = map.getZoom();
        google.maps.event.addListener(map, 'zoom_changed', function() {
            if(map.getZoom() > prevZoomLevel){
                _gaq.push(['_trackEvent', 'Mggg Map', 'Change zoom', 'Zoom in']);
            }
            else {
                _gaq.push(['_trackEvent', 'Mggg Map', 'Change zoom', 'Zoom out']);
            }
            prevZoomLevel = map.getZoom();
        });
    }
};


