/*
 * jGMap jQuery Plug-in
 * http://fazchanj.com/jGMap
 * jQuery Google Maps Wrapper
 *
 * Copyright (c) 2010 Samuel Rouse
 * Dual licensed under the MIT and GPL licenses.
 * http://docs.jquery.com/License
 * Requires jQuery 1.4+, tested with 1.4.2
 *
 * Date: 2010-12-29
 * Revision: 0
 * Date: 2011-08-17
 * Revision: 1 - Added pin color support
 *
 * Options: 
	optURL - Location for AJAX call to get additional options (JSON object). GET is assumed.
	optURLData - Any data you may need to pass to get the appropriate option list (JSON object).
	pointURL - Location for AJAX call to get map points (JSON object). GET is assumed.
 	pointURLData - Data you may need to pass to get the appropriate set of map points (JSON object).
	map - CSS Selector of the Map (will use first result if selector returns multiple).
	mapOpt - Data to create the map (JSON object).
	mapOptURL - Location for AJAX call to get map data (JSON object). GET is assumed.
	mapOptData - Data you may need to pass to get map data (JSON Object).
  		
 * MapData:
	ptDrop - Whether points should drop onto the map. Defaults to true. 
	ptDropDelay - Delay between each point dropping onto the map. Defaults to 200ms.
	
	ptGetIcon - passed directly to Google Maps API. Can return a string (url) or google.maps.MarkerImage class.
  	-- Override with a function to handle multiple colors or designs.
	-- Defaults to generic pushpin graphic.
	ptGetIcon - passed directly to Google Maps API. Can return a string (url) or google.maps.MarkerImage class.
  	-- Override with a function to handle multiple colors or designs.
  	-- Defaults to MarkerImage class for pushpin.
  	
  	ptDragAll - Set all points to draggable.
  	
  	ptClick - Whether there is a click handler. Defaults to false.
  	ptDblClick - Whether there is a double-click handler. Defaults to false.
 
 */
 
(function ($) {
    $.fn.jGMap = function (options) {
        // Set the options.
        $.fn.jGMap.options = $.extend({}, $.fn.jGMap.defaults, options);

        // Go through the matched elements and return the jQuery object.
        return this.each(function (idx) {
            // Only create a map for the first match.
            if (idx == 0) {
                $.fn.jGMap.obj = $(this);
                $.fn.jGMap.init();
            }
        });
    };


    // Public Values
    $.fn.jGMap.loadState = 0;
    $.fn.jGMap.defaults = {
        ptDrop: true,
        ptDropDelay: 200,
        debug: false,
        geoCodeWarn: true
    };
    $.fn.jGMap.obj = "";
    $.fn.jGMap.options = "";
    $.fn.jGMap.points = "";
    $.fn.jGMap.curPoint = 0;
    $.fn.jGMap.pins = "";
    $.fn.jGMap.mapData = {
        lat: 37.64,
        long: -65.06,
        zoom: 4,
        ptDrop: true,
        ptDropDelay: 200,
        ptGetIcon: new google.maps.MarkerImage('/PHDModules/maps/images/pushpin.png',(new google.maps.Size(32,32)),new google.maps.Point(0,0),new google.maps.Point(9,32)),
        ptGetShadow: new google.maps.MarkerImage("/PHDModules/maps/images/pushpin_shadow.png", (new google.maps.Size(59, 32)), (new google.maps.Point(0, 0)), (new google.maps.Point(8, 32)), (new google.maps.Size(59, 32))),
        ptDragAll: false,
        ptClick: false,
        ptDblClick: false
    };
    $.fn.jGMap.settings = "";

    // Google Maps "map" object
    $.fn.jGMap.gMap = "";

    // Public Functions	
    $.fn.jGMap.init = function () {
        var options = $.fn.jGMap.options;

        // Cycle through actions to make sure they load inrementally.
        // Each case will cascade if there is no action to take.
        switch ($.fn.jGMap.loadState) {
            case 0: 	// Load AJAX options
                if (options.optURL != null) {
                    $.getJSON(options.optURL, (options.optURLData != null ? options.optURLData : {}), function (data, stat) {
                        if (options.debug == true) { alert("Returned AJAX Options."); }

                        if (typeof (data) == 'object') {
                            $.fn.jGMap.options = options = $.extend({}, options, data);
                        }
                        $.fn.jGMap.loadState += 1;
                        $.fn.jGMap.init();
                    });
                    break;
                } else {
                    $.fn.jGMap.loadState += 1;
                }

            case 1: 	// Load AJAX map data
                if (options.mapOptURL != null) {
                    $.getJSON(options.mapOptURL, (options.mapOptURLData != null ? options.mapOptURLData : {}), function (data, stat) {
                        if (options.debug == true) { alert("Returned AJAX Map Data."); }

                        if (typeof (data) == 'object') {
                            $.fn.jGMap.mapData = $.extend({}, $.fn.jGMap.mapData, options.mapData, data.rows[0]);
                        }
                        $.fn.jGMap.loadState += 1;
                        $.fn.jGMap.init();
                    });
                    break;
                } else {
                    $.fn.jGMap.loadState += 1;
                }

            case 2:     // Load AJAX map pins
                if (options.pinURL != null) {
                    $.getJSON(options.pinURL, (options.pinURLData != null ? options.pinURLData : {}), function (data, stat) {
                        if (options.debug == true) { alert("Returned AJAX Map Pins."); }

                        if (typeof (data) == 'object') {
                            $.fn.jGMap.pins = $.extend({}, $.fn.jGMap.pins, data.pins);
                        }
                        $.fn.jGMap.loadState += 1;
                        $.fn.jGMap.init();
                    });
                    break;
                } else {
                    $.fn.jGMap.loadState += 1;
                }

            case 3: 	// Load AJAX map points
                if (options.pointURL != null) {
                    $.getJSON(options.pointURL, (options.pointURLData != null ? options.pointURLData : {}), function (data, stat) {
                        if (options.debug == true) { alert("Returned AJAX Map Points."); }

                        if (typeof (data) == 'object') {
                            $.fn.jGMap.points = $.extend({}, $.fn.jGMap.points, data.rows);
                        }
                        $.fn.jGMap.loadState += 1;
                        $.fn.jGMap.init();
                    });
                    break;
                } else {
                    $.fn.jGMap.loadState += 1;
                }

            case 4: 	// Init Proper
                if ($.fn.jGMap.loadState == 4) {
                    if ($.fn.jGMap.options.debug == true) {
                        alert('Started!');
                        $.fn.jGMap.obj.ajaxError(function (e, xhr, opt, err) {
                            if (opt.url.indexOf("/Manage/map/") != -1) {
                                // Only run for Map requests in Manage
                                alert(xhr.responseText);
                            }
                        });
                    }

                    var tmpMapOptions = {
                        center: new google.maps.LatLng($.fn.jGMap.mapData.lat, $.fn.jGMap.mapData.long),
                        mapTypeId: google.maps.MapTypeId.ROADMAP,
                        zoom: $.fn.jGMap.mapData.zoom
                    };

                    // Generate the Map
                    $.fn.jGMap.gMap = new google.maps.Map($.fn.jGMap.obj[0], tmpMapOptions);

                    // Listener to load points after the map is loaded.
                    google.maps.event.addListenerOnce($.fn.jGMap.gMap, "tilesloaded", function () {

                        // Cycle through the points JSON object
                        $.each($.fn.jGMap.points, function (idx, item) {
                            $.fn.jGMap.obj.delay($.fn.jGMap.mapData.ptDropDelay);
                            $.fn.jGMap.obj.queue(function (next) {
                                addPoint($(this), next, idx, item);
                            });
                        });
                    });

                }
        }
    };

    $.fn.jGMap.newPoint = function (latlng) {
        // Externally accessible point addition
        // Returns the marker object

        var mapData = $.fn.jGMap.mapData;

        // Add a blank point.
        var curPt = new google.maps.Marker({
            position: latlng,
            map: $.fn.jGMap.gMap,
            icon: typeof (mapData.ptGetIcon) == "function" ? mapData.ptGetIcon() : mapData.ptGetIcon,
            shadow: typeof (mapData.ptGetShadow) == "function" ? mapData.ptGetShadow() : mapData.ptGetShadow,
            title: "New Point"
        });

        // Check for DROP animation
        if (mapData.ptDrop == true) {
            curPt.setAnimation(google.maps.Animation.DROP);
        }

        return curPt;
    };

    $.fn.jGMap.newPointEvents = function (curPt, idx) {
        // Makes sure the new point has all the event handlers it should.

        var mapData = $.fn.jGMap.mapData;

        if (mapData.ptDblClickOnce != null && mapData.ptDblClickOnce == true) {
            google.maps.event.addListenerOnce(curPt, 'dblclick', function () {
                ptDblClick($.fn.jGMap.gMap, curPt, idx);
            });
        }

        if (mapData.ptDblClick != null && mapData.ptDblClick == true) {
            google.maps.event.addListener(curPt, 'dblclick', function () {
                ptDblClick($.fn.jGMap.gMap, curPt, idx);
            });
        }

        if (mapData.ptClick != null && mapData.ptClick == true) {
            google.maps.event.addListener(curPt, 'click', function () {
                ptClick($.fn.jGMap.gMap, curPt, idx);
            });
        }

        if (mapData.ptClickOnce != null && mapData.ptClickOnce == true) {
            google.maps.event.addListenerOnce(curPt, 'click', function () {
                ptClick($.fn.jGMap.gMap, curPt, idx);
            });
        }
    };

    // Add each point
    addPoint = function (queue, next, idx, item) {
        // Track the current point.
        $.fn.jGMap.curPoint = idx;

        var mapData = $.fn.jGMap.mapData;

        // Add the details to the map.
        var curPt = new google.maps.Marker({
            position: new google.maps.LatLng(item.lat, item.long),
            map: $.fn.jGMap.gMap,
            icon: typeof (mapData.ptGetIcon) == "function" ? mapData.ptGetIcon() : mapData.ptGetIcon,
            shadow: typeof (mapData.ptGetShadow) == "function" ? mapData.ptGetShadow() : mapData.ptGetShadow,
            title: item.chrname
        });

        // Check for DROP animation
        if (mapData.ptDrop == true) {
            curPt.setAnimation(google.maps.Animation.DROP);
        }

        if (mapData.ptDblClickOnce != null && mapData.ptDblClickOnce == true) {
            google.maps.event.addListenerOnce(curPt, 'dblclick', function () {
                ptDblClick($.fn.jGMap.gMap, curPt, idx);
            });
        }

        if (mapData.ptDblClick != null && mapData.ptDblClick == true) {
            google.maps.event.addListener(curPt, 'dblclick', function () {
                ptDblClick($.fn.jGMap.gMap, curPt, idx);
            });
        }

        if (mapData.ptClick != null && mapData.ptClick == true) {
            google.maps.event.addListener(curPt, 'click', function () {
                ptClick($.fn.jGMap.gMap, curPt, idx);
            });
        }

        if (mapData.ptClickOnce != null && mapData.ptClickOnce == true) {
            google.maps.event.addListenerOnce(curPt, 'click', function () {
                ptClick($.fn.jGMap.gMap, curPt, idx);
            });
        }

        // Handle the queue
        queue.dequeue();
        next;
    };

})(jQuery);
