/**
 * SQS Group
 *
 * @author:     Freie Formation - Rafael Hiss, Mehmet Erdem
 * @email:      rafael.hiss@freieformation.de
 * @website:    http://www.freieformation.de
 * 
 */
var SQS_MAP = ( function() {
    var my = {};
    var SQS_MAP_WRAPPER_SELECTOR    = '#sqs-map-wrapper';
    var SQS_MAP_CONTAINER_ID        = 'sqs-map-container';
    var TOOLTIP_CONTENT_LOADING     = '<div id="sqs-tooltip-content-loading">Loading...</div>';
    var TOOLTIP_HTML                = '<div id="sqs-map-marker">'+
    '<h3><%= location.name %></h3>'+
    '<p><%= location.address %></p>'+
    '<a href="<%= map.directionsUrl %><%= location.directionsParams %>" target="_blank">'+
    '<div id="sqs-map-button-iehack"></div>'+
    '<div class="sqs-map-button"></div>'+
    '</a>'+
    '</div>';
    
    var TOOLTIP_CONTAINER_HTML      = '<div id="sqs-tooltip-container">'+
    '<div id="sqs-tooltip-bg">'+
    '</div>'+
    '<div id="sqs-tooltip">'+
    '</div></div>';
    
    var TOOL_TIP_SELECTOR           = '#sqs-tooltip';
    var MAP_WRAPPER_HTML            =   '<div class="sqs-topleft"></div>'+
    '<div class="sqs-topright"></div>'+
    '<div id="sqs-map-container"></div> '+
    '<div class="sqs-bottomleft"></div>'+
    '<div class="sqs-bottomright"></div>';
    
    var TOOLTIP_HIDDEN              = 'HIDDEN';
    var TOOLTIP_START_SHOW          = 'START_SHOW';
    var TOOLTIP_SHOWN               = 'SHOWN';
    var TOOLTIP_START_HIDE          = 'START_HIDE';
    var MAP_STYLES = [{
        featureType: "all",
        elementType: "all",
        stylers: [{
            saturation: -100
        },{
            hue: '#cccccc'
        },{
            lightness: 27
        },{
            visibility: "on"
        }
        ]
    }
    ];
    var config                      = null;
    var $mapContainer               = null;
    var map                         = null;
    var manager                     = null;
    var $tooltipContainer           = null;
    var $tooltip                    = null;
    var tooltipContentCache         = {};
    var currentTooltip = {
        id: null,
        x: null,
        y: null,
        timerId: null,
        state: TOOLTIP_HIDDEN
    };
    var getProjection               = null;
    var cache                       = {};
    /*
     *   -----------------------------------------------------------------------------------------------
     */
    function init(configUrl) {
        log("INIT");
        loadConfig(configUrl);
    }
    function loadConfig(configUrl) {
        log("LOADCONFIG");
        var url = configUrl;
        $.ajax({
            url: url,
            error: function() {
                // todo: add error css
            },
            success: function(data) {
                config = data;
                loadMapApi();
            },
            dataType: 'json'
        });
    }
    function loadMapApi() {
        $.getScript('http://maps.google.com/maps/api/js?v=3&async=2&callback=SQS_MAP.mapApiLoaded&sensor=false&key=' + config.map.apiKey);
    }
    function mapApiLoaded() {
        log("mapApiLoaded");
        initTooltip();
        createMap(config.map);
        initGetProjection();
        createMarkers(config.locations);        
    }
    function createMap(mapConfig) {        
        $(SQS_MAP_WRAPPER_SELECTOR).html(MAP_WRAPPER_HTML);
        mapContainerEl = document.getElementById(SQS_MAP_CONTAINER_ID);
        $mapContainer = $(mapContainerEl);
        var center = new google.maps.LatLng(mapConfig.centerLatitude, mapConfig.centerLongitude);
        var mapOptions = {
            zoom: mapConfig.zoom,
            center: center,
            mapTypeControl: false,
            mapTypeControlOptions: {
                mapTypeIds: [google.maps.MapTypeId.ROADMAP],
                style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
            },
            navigationControlOptions: {
                style: google.maps.NavigationControlStyle.ZOOM_PAN
            }
        };
        map = new google.maps.Map(mapContainerEl,mapOptions);        
        var styledMapType = new google.maps.StyledMapType(MAP_STYLES, {});
        map.mapTypes.set('styledMap', styledMapType);
        map.setMapTypeId('styledMap');
    }
    function initGetProjection() {
        var overlayViewHelper = new google.maps.OverlayView();
        overlayViewHelper.setMap(map);
        overlayViewHelper.draw = function () {
            if (!this.ready) {
                this.ready = true;
                google.maps.event.trigger(this, 'ready');
            }
        };
        getProjection = function() {
            return overlayViewHelper.getProjection();
        };
    }
    function createMarkers(locations) {
        var i;
        for (i = 0; i < locations.length; i++) {
            var location = locations[i];
            createMarker(location, i);
        }        
    }
    function createMarker(location, index) {
        var markerPosition = new google.maps.LatLng(location.latitude, location.longitude);
        var marker = new google.maps.Marker({
            position: new google.maps.LatLng(location.latitude, location.longitude),
            map: map,
            icon: config.marker.icon
        });
        google.maps.event.addListener(marker, 'mouseover', createMarkerMouseOverHandler(markerPosition,location, index));
        google.maps.event.addListener(marker, 'mouseout', deactivateTooltip);
    }
    function createMarkerMouseOverHandler(markerPosition,location, index) {
        return function() {
            var markerPixelPosition = calcMarkerPixelPosition (markerPosition);
            activateTooltip(index, markerPixelPosition.x, markerPixelPosition.y, function(callback) {
                $html = $(tmpl(TOOLTIP_HTML, {
                    "location":location,
                    "map":config.map
                }));
                callback($html);
            });
        };
    }
    function calcMarkerPixelPosition (markerPosition) {
        var markerPixelOffset = getProjection().fromLatLngToContainerPixel(markerPosition);
        var mapPixelOffset = $mapContainer.offset();
        var markerPixelPosition = {
            x: mapPixelOffset.left + markerPixelOffset.x,
            y: mapPixelOffset.top + markerPixelOffset.y
        };
        return markerPixelPosition;
    }
    function initTooltip() {
        $tooltipContainer = $(TOOLTIP_CONTAINER_HTML).appendTo('body');
        $tooltip = $tooltipContainer.find(TOOL_TIP_SELECTOR).hover( function() {
            startShowTooltip(currentTooltip.id);
        }, function() {
            deactivateTooltip();
        });
        $tooltipContainer.hide();
    }
    function setTooltipContent(id, content) {
        log(id, content);
        tooltipContentCache[id] = content;
        if (currentTooltip.id == id) {
            $tooltip.html(content);
        }
    }
    function showTooltip() {
        $tooltip.html(tooltipContentCache[currentTooltip.id]);
        $tooltipContainer.css('left', currentTooltip.x);
        $tooltipContainer.css('top', currentTooltip.y);
        $tooltipContainer.removeClass();
        if (currentTooltip.cssClass) {
            $tooltipContainer.addClass(currentTooltip.cssClass);
        }
        $tooltipContainer.show();
        currentTooltip.state = TOOLTIP_SHOWN;
        google.maps.event.addListenerOnce(map, 'click', function () {
            hideTooltip();
        });
    }
    function hideTooltip() {
        $tooltipContainer.hide();
        currentTooltip.state = TOOLTIP_HIDDEN;
        currentTooltip.id = null;
    }
    function startShowTooltip(id) {
        switch (currentTooltip.state) {
            case TOOLTIP_HIDDEN:
                currentTooltip.id = id;
                currentTooltip.state = TOOLTIP_START_SHOW;
                currentTooltip.timerId = setTimeout( function() {
                    showTooltip();
                }, config.tooltip.showDelay);
                break;
            case TOOLTIP_START_HIDE:
                clearTimeout(currentTooltip.timerId);
                currentTooltip.timerId = null;
                if (currentTooltip.id == id) {
                    currentTooltip.state = TOOLTIP_SHOWN;
                    break;
                } else {
                    hideTooltip();
                    currentTooltip.id = id;
                    currentTooltip.state = TOOLTIP_START_SHOW;
                    currentTooltip.timerId = setTimeout( function() {
                        showTooltip();
                    }, config.tooltip.showDelay);
                }
                break;
            default:
                log("UNHANDLED CASE" + currentTooltip.state);
        }
    }
    function activateTooltip(id, x, y, contentProvider, cssClass) {
        currentTooltip.x = x;
        currentTooltip.y = y;
        tooltipContentCache[id] = TOOLTIP_CONTENT_LOADING;
        contentProvider( function(content) {
            setTooltipContent(id, content);
        });
        startShowTooltip(id);
    }
    function deactivateTooltip() {
        switch (currentTooltip.state) {
            case TOOLTIP_SHOWN:
                currentTooltip.timerId = setTimeout( function() {
                    hideTooltip();
                }, config.tooltip.hideDelay);
                currentTooltip.state = TOOLTIP_START_HIDE;
                break;
            case TOOLTIP_START_SHOW:
                clearTimeout(currentTooltip.timerId);
                currentTooltip.timerId = null;
                currentTooltip.state = TOOLTIP_HIDDEN;
                break;
            default:
                log("UNHANDLED CASE!" + currentTooltip.state);
        }
    }
    
    function log () {
        try {
            console.log("SQS_MAP :: ", arguments);
        } catch(err) {
            var i = 0;
            while (i < arguments[0].length) {
                if (!output) {
                    var output = arguments[0][i] + "\n";
                } else {
                    output += arguments[0][i] + "\n";
                }
                i++;
            }
            // alert( output);
        }
    }
    
    // Simple JavaScript Templating
    // John Resig - http://ejohn.org/ - MIT Licensed
    function tmpl(str, data) {
        // Figure out if we're getting a template, or if we need to
        // load the template - and be sure to cache the result.
        var fn = !/\W/.test(str) ? cache[str] = cache[str] ||
        tmpl(document.getElementById(str).innerHTML) :        // Generate a reusable function that will serve as a template
        // generator (and which will be cached).
        new Function("obj", "var p=[],print=function(){p.push.apply(p,arguments);};" +
        // Introduce the data as local variables using with(){}
        "with(obj){p.push('" +
        // Convert the template into pure JavaScript
        str.replace(/[\r\t\n]/g, " ").
        split("<%").
        join("\t").
        replace(/((^|%>)[^\t]*)'/g, "$1\r").
        replace(/\t=(.*?)%>/g, "',$1,'").
        split("\t").join("');").
        split("%>").
        join("p.push('").
        split("\r").join("\\'") +
        "');}return p.join('');");
        // Provide some basic currying to the user
        return data ? fn(data) : fn;
    }

    my.init = init;
    my.activateTooltip = activateTooltip;
    my.deactivateTooltip = deactivateTooltip;
    my.mapApiLoaded = mapApiLoaded;
    return my;
}());
