var glatlng;
var gmarker;
var manager;
var tooltip;
var zoom    = 8;
var gmap    = null;
var loader  = null;
var polygon = null;

/* Collection of POIs */
var points = [];

/* Initialize */
function initialize (container, options) {

    var container = container ? container : 'listings-map';

    var defaults  = {
        'map_type' : G_NORMAL_MAP,
        'loader'   : false,
        'tooltip'  : true,
        'polygon'  : false,
        'control_types' : true,
        'bounds_center' : true,
        'bounds_zoom'   : true
    };

    var options   = options   ? options : defaults;

    if (gmap != null) return;

    /* Create Map */
    gmap = new GMap2(document.getElementById(container));

    /* Set Map Type */
    options.map_type = (typeof(options.map_type) != 'undefined') ? options.map_type : defaults.map_type;
    if (options.map_type) {
        gmap.setMapType(options.map_type);
    }

    /* Center Map */
    gmap.setCenter(glatlng, zoom);

    /* Add 3D Map Control */
    gmap.addControl(new GLargeMapControl3D());

    /* Add Map Type Controls */
    options.control_types = (typeof(options.control_types) != 'undefined') ? options.control_types : defaults.control_types;
    if (options.control_types) {
        gmap.addMapType(G_PHYSICAL_MAP);
        var hControl = new GHierarchicalMapTypeControl();
        hControl.addRelationship(G_SATELLITE_MAP, G_HYBRID_MAP, "Labels", true);
        gmap.addControl(hControl);
    }

    /* Enable Scroll Wheel Zoom */
    gmap.enableScrollWheelZoom();

    /* POI Manager */
    manager = new MapMarkerManager (gmap, points, {
        'bounds_center' : (typeof(options.bounds_center) != 'undefined') ? options.bounds_center : defaults.bounds_center,
        'bounds_zoom'   : (typeof(options.bounds_zoom)   != 'undefined') ? options.bounds_zoom   : defaults.bounds_zoom
    });
    manager.plot();

    /* Map Loader Overlay */
    options.loader = (typeof(options.loader) != 'undefined') ? options.loader : defaults.loader;
    if (options.loader) {
        loader = new MapLoader ();
    }

    /* Map Tooltip */
    options.tooltip = (typeof(options.bounds_center) != 'undefined') ? options.tooltip : defaults.tooltip;
    if (options.tooltip) {
        tooltip = new MapTooltip('map-label');
    }

    /* Create Polygon Tools */
    options.polygon = (typeof(options.bounds_center) != 'undefined') ? options.polygon : defaults.polygon;
    if (options.polygon) {
        polygon = new Polygon();
        polygon.toolbar();
    }

}

function MapMarker (title, latitude, longitude, html, options) {

    /* Marker Instance */
    var $marker = this;

    /* Marker Options */
    $marker.options = options ? options : {};

    /* Marker Parameters */
    $marker.title      = title;
    $marker.latitude   = latitude;
    $marker.longitude  = longitude;
    $marker.html       = html;
    $marker.icon       = $marker.options.icon ? $marker.options.icon : '/img/map/ico-map-listing.png';
    //$marker.icon       = $marker.options.icon ? $marker.options.icon : '/img/icons/ico-home.gif';
    $marker.icon            = new GIcon(G_DEFAULT_ICON, $marker.icon);
    $marker.icon.shadow     = "/img/map/ico-map-shadow.png";
    $marker.icon.iconSize   = new GSize(14, 17);
    $marker.icon.shadowSize = new GSize(17, 17);
    $marker.icon.iconAnchor = new GPoint(0, 0);

    /* Marker Point */
    $marker.point = new GLatLng ($marker.latitude, $marker.longitude);

    /* Google Marker */
    $marker.marker = new GMarker($marker.point, {
        icon: $marker.icon,
        title: $marker.title
    });

    /* Select Marker */
    $marker.select = function () {
        /* Trigger Marker Click */
        GEvent.trigger($marker.marker, 'click');
    };

}

function MapMarkerManager (map, points, options) {

    /* Manager Instance */
    var $manager = this;

    /* Manager Parameters */
    $manager.map     = map;
    $manager.options = options || {};
    $manager.points  = [];

    /* Manager Bounds */
    $manager.bounds = new GLatLngBounds();

    /* Add New MapMarker */
    $manager.addMarker = function (marker) {

        /* Marker Index */
        var index = $manager.points.length;

        /* Add to Collection */
        $manager.points[index] = marker;

        /* Extend Bounds */
        $manager.bounds.extend(marker.point);

    };

    /* Loop through Results */
    var i = 0, len = points.length;
    while (i < len) {
        $manager.addMarker(points[i]);
        i++;
    }

    /* Remove Existing Marker */
    $manager.removeMarker = function (title) {

        /* Find Marker */
        var marker = $manager.getMarker(title);
        if (marker) {



        }

    };

    /* Select Existing Marker */
    $manager.selectMarker = function (title) {

        /* Find Marker */
        var marker = $manager.getMarker(title);
        if (marker) {

            /* Select Marker */
            marker.select();

        }

    };

    /* Get Marker by Title */
    $manager.getMarker = function (title) {

        var marker = null;

        /* Loop through Markers */
        $.each($manager.points, function (index) {

            /* Match Against Title */
            if (title == this.title) {
                marker = $manager.points[index];
                return;
            }

        });

        /* Return Marker */
        return marker;

    };

    /* Plot Manager Points */
    $manager.plot = function (points) {

        /* Show Loader */
        if (loader) loader.show();

        /* Points to Plot */
        if (typeof(points) != 'undefined') {
            var i = 0, len = points.length;
            while (i < len) {
                $manager.addMarker(points[i]);
                i++;
            }
        }

        /* Loop through Marker Collection */
        $.each($manager.points, function () {

            /* Set Scope */
            var marker = this.marker;
            var html   = this.html;

            /* Add to Map */
            gmap.addOverlay(marker);

            /* Attach Onclick Event */
            GEvent.addListener(marker, 'click', function() {
                /* Open Tooltip */
                if (tooltip) {
                    /* Show Tooltip */
					if ($('#map-label:hidden')) {
					    if (html != '') {
                            tooltip.show(marker, html, true);
                        }
					}
                }
            });

            /* Attach Mouse Over Event */
            GEvent.addListener(marker, 'mouseover', function() {
                /* Show Tooltip */
            	if (tooltip) {
                    if ($('body').hasClass('mapHasSticky')) return;
                    if (html != '') tooltip.show(marker, html);
                }
            });

            /* Attach Mouse Out Event */
            GEvent.addListener(marker, 'mouseout', function() {
                /* Hide Tooltip */
                if (tooltip) tooltip.hide();
            });

            i++;

        });

        /* Fit All Markers within Map */
        if (manager.bounds.getCenter().lat() != 0) {
            if ($manager.options.bounds_center) {
                gmap.setCenter(manager.bounds.getCenter());
            }
            if ($manager.options.bounds_zoom) {
                gmap.setZoom(gmap.getBoundsZoomLevel(manager.bounds));
            }
        }

        /* Hide Loader */
        if (loader) loader.hide();

    };

    /* Reset Marker Manager */
    $manager.reset = function () {

        /* Hide Tooltip */
		if (tooltip) tooltip.hide(true);

//		/* Loop through Marker Collection */
//        var i = 0, len = $manager.points.length;
//        while (i < len) {
//
//            /* Remove Listeners */
//            GEvent.clearInstanceListeners($manager.points[i].marker);
//
//            /* Remove Overlay */
//            gmap.removeOverlay($manager.points[i].marker);
//
//            /* Increment */
//            i++;
//
//        }

        /* Remove OVerlays */
        map.clearOverlays();

        /* Reset Points */
        $manager.points = [];

        /* Reset Bounds */
        $manager.bounds = new GLatLngBounds();

    };

}


function MapTooltip (elem, options) {

    /* Tooltip Instance */
    var $tooltip = this;

    /* Over */
    $tooltip.over = false;

    /* Sticky */
    $tooltip.sticky = false;

    /* Tooltip Options */
    $tooltip.options = options ? options : {};

    /* Tooltip Timout Delay */
    $tooltip.delay = $tooltip.options.delay ? $tooltip.options.delay : 500;

    /* Create Container */
    $('body').append('<div id="' + elem + '" style="position: absolute; z-index: 300; display: none;"></div>');

    /* Tooltip Container */
    var $contain = $('#' + elem);

    /* Container Mouseover */
    $contain.bind('mouseover', function () {
        $tooltip.over = true;
    });

    /* Container Mouseout */
    $contain.bind('mouseout', function () {
        $tooltip.hide();
    });

    /* Show MapTooltip */
    $tooltip.show = function (marker, html, sticky) {
   		$tooltip.over   = true;
		$tooltip.sticky = (typeof(sticky) != 'undefined') ? sticky : false;
		var offset = gmap.fromLatLngToContainerPixel(marker.getLatLng());
		$contain.show().css({
			position: 'absolute',
			top:  $('#' + gmap.getContainer().id).offset().top  + offset.y + 10 + 'px',
			left: $('#' + gmap.getContainer().id).offset().left + offset.x + 10 + 'px'
		}).html(html);
		if ($tooltip.sticky) {
			$close = ('<a href="javascript:void(0);" class="action-close">hide</a>');
			$('body').addClass('mapHasSticky');
			$('.title', $contain). append($close);
			$('.action-close', $contain).click(function(){
				$tooltip.hide(true);
			});
		} else {
			$contain.removeClass('sticky');
		}
    };

    /* Hide MapTooltip */
    $tooltip.hide = function (force) {
        if (force == true) {
            $('body').removeClass('mapHasSticky');
            $tooltip.sticky = false;
            $tooltip.over = false;
            $contain.hide();
            return;
        }
        if ($tooltip.sticky) return;
        $tooltip.over = false;
        clearTimeout($tooltip.timeout);
        $tooltip.timeout = setTimeout(function () {
            if ($tooltip.over == false) {
                $contain.hide();
            }
        }, $tooltip.delay);
    };

}

/* Map Loader Overlay Object */
function MapLoader (options) {

    /* Loader Instance */
    var $loader = this;

    /* Loader Options */
    $loader.options = options ? options : {};

    /* Loading Overlay */
    $loader.overlays = [];
    $loader.overlays[$loader.overlays.length] = new GPolygon([new GLatLng(-85,0),new GLatLng(85,0),new GLatLng(85,90),new GLatLng(-85,90)],null,0,0,"#000",0.4);
    $loader.overlays[$loader.overlays.length] = new GPolygon([new GLatLng(-85,90),new GLatLng(85,90),new GLatLng(85,180),new GLatLng(-85,180)],null,0,0,"#000",0.4);
    $loader.overlays[$loader.overlays.length] = new GPolygon([new GLatLng(-85,180.000001),new GLatLng(85,180.000001),new GLatLng(85,270),new GLatLng(-85,270)],null,0,0,"#000",0.4);
    $loader.overlays[$loader.overlays.length] = new GPolygon([new GLatLng(-85,270),new GLatLng(85,270),new GLatLng(85,360),new GLatLng(-85,360)],null,0,0,"#000",0.4);

    /* Add Loading Overlays */
    $loader.show = function () {
        var i = 0, len = $loader.overlays.length;
        while (i < len) {
            gmap.addOverlay($loader.overlays[i]);
            i++;
        }
    }

    /* Remove Loading Overlays */
    $loader.hide = function () {
        var i = 0, len = $loader.overlays.length;
        while (i < len) {
            gmap.removeOverlay($loader.overlays[i]);
            i++;
        }
    }

}

/* Polygon Object */
function Polygon () {

    /* Polygon */
    this.polygon = null;

    /* Points */
    this.points = [];
    //this.points[this.points.length] = gmap.getCenter();

    /* Mode */
    this.mode      = 0;
    this.MODE_DRAW = 1;
    this.MODE_EDIT = 2;
    this.MODE_IDLE = 3;

    /* WKT */
    this.wkt = null;

    /* Control Toolbar */
    this.control = new PolygonControl();

    /* Add Control Toolbar */
    gmap.addControl(this.control);

}

/* Polygon.findPoint */
Polygon.prototype.findPoint = function (latitude, longitude) {

    /* Return Empty */
    if (this.polygon) {

        var i;
        var j = this.polygon.getVertexCount() - 1;
        var inPoly = false;

        /* Loop through vertex points */
        for (i = 0; i < this.polygon.getVertexCount(); i++) {

            var iPoint = this.polygon.getVertex(i);
            var jPoint = this.polygon.getVertex(j);

            if ((iPoint.lng() < longitude && jPoint.lng() >= longitude) ||
                (jPoint.lng() < longitude && iPoint.lng() >= longitude))  {

                if (iPoint.lat() + (longitude - iPoint.lng()) / (jPoint.lng() - iPoint.lng()) * (jPoint.lat() - iPoint.lat()) < latitude)  {

                    inPoly = !inPoly;

                }

            }

            j = i;

        }

        return inPoly;

    }

}

/* Polygon.serialize */
Polygon.prototype.serialize = function () {

    /* Return Empty */
    if (!this.polygon) return '';

    /* WKT MultiPolygon */
    this.wkt = "MULTIPOLYGON(((";

    /* Loop through vertex points */
    for (i = 0; i < this.polygon.getVertexCount(); i++) {

        /* Select point */
        var point = this.polygon.getVertex(i);

        /* WKT */
        this.wkt += point.lat() + " " + point.lng() + ",";

    }

    this.wkt = this.wkt.replace(/,$/,"");
    this.wkt += ")))";

    return this.wkt;

}

/* Polygon.draw */
Polygon.prototype.draw = function () {

    /* Remove Overlay */
    this.remove();

    /* Create Polygon */
    this.polygon = new GPolygon(this.points);

    /* Add Polygon to Map */
    gmap.addOverlay(this.polygon);

    /* Enable Drawing */
    this.polygon.enableDrawing();

    /* Set Mode */
    this.mode = this.MODE_DRAW;

    /* Polygon Event Listener - lineupdated */
    GEvent.addListener(this.polygon, 'lineupdated', function () {

        /* Redraw Toolbar */
        polygon.toolbar();

    });

    /* Polygon Event Listener - endline */
    GEvent.addListener(this.polygon, 'endline', function () {

        /* Set Mode */
        polygon.mode = polygon.MODE_IDLE;

        /* Redraw Toolbar */
        polygon.toolbar();

    });

}

/* Polygon.remove */
Polygon.prototype.remove = function () {

    /* Remove Overlay */
    if (this.polygon) {

        /* Disable Edit Mode */
        polygon.polygon.disableEditing();

        /* Remove Listeners */
        GEvent.clearInstanceListeners(this.polygon);

        /* Remove Polygon */
        this.polygon.remove();

        /* Reset Points */
        this.points = [];

        /* Clear Polygon */
        this.polygon = null;

        /* Set Mode */
        this.mode = this.MODE_IDLE;

    }

}

/* Polygon.toolbar */
Polygon.prototype.toolbar = function () {

    /* Redraw Polygon Toolbar */
    this.control.draw(this);

}

/* Polygon Toolbar */
function PolygonControl() {};

/* Polygon Control */
PolygonControl.prototype = new GControl();

/* Polygon Toolbar */
PolygonControl.prototype.initialize = function () {

    this.css_toolbar = {
        'font-family' : 'Arial,sans-serif',
    	'text-align' : 'center',
        'font-size-adjust' : 'none',
        'font-style' : 'normal',
        'font-variant' : 'normal',
        'font-weight' : 'normal'
    };

    this.css_button = {
    	'background-color' : '#fff',
    	'color' : '#000',
    	'padding' : '2px 3px 2px 3px',
    	'text-decoration' : 'none',
    	'border' : '1px solid #000',
    	'cursor' : 'pointer',
    	'font-size' : '12px'
    };

    this.contain = 'toolbar';

    /* Create Toolbar Container */
    $('body').append('<div id="' + this.contain + '" class="gmnoprint"></div>');

    this.toolbar = $("#" + this.contain).get(0);

    $("#toolbar").css(this.css_toolbar);

    gmap.getContainer().appendChild(this.toolbar);

    return this.toolbar;
}

/* Position Toolbar */
PolygonControl.prototype.getDefaultPosition = function() {
    return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(7, 30));
}

/* Draw Toolbar */
PolygonControl.prototype.draw = function(polygon) {

    $('#toolbar').html('');

    if (polygon.polygon) {

        if (polygon.mode == polygon.MODE_DRAW) {
            $('<a href="javascript:void(0);">Cancel Polygon</a>').css(this.css_button).appendTo('#toolbar').bind('click', function () {

                /* Remove Polygon */
                polygon.remove();

                /* Redraw Toolbar */
                polygon.toolbar();

            });
        }

        if (polygon.mode == polygon.MODE_IDLE) {
            $('<a href="javascript:void(0);">Draw New Polygon</a>').css(this.css_button).appendTo('#toolbar').bind('click', function () {

                /* Draw Polygon */
                polygon.draw();

                /* Redraw Toolbar */
                polygon.toolbar();

            });
        }

    } else {

        $('<a href="javascript:void(0);">Draw Polygon</a>').css(this.css_button).appendTo('#toolbar').bind('click', function () {

            /* Draw Polygon */
            polygon.draw();

            /* Redraw Toolbar */
            polygon.toolbar();

        });
    }

    if (polygon.polygon && polygon.polygon.getVertexCount()) {

        if (polygon.mode == polygon.MODE_IDLE) {
            $('<a href="javascript:void(0);">Edit Polygon</a>').css(this.css_button).appendTo('#toolbar').bind('click', function () {

                /* Enable Edit Mode */
                polygon.polygon.enableEditing();

                /* Set Mode */
                polygon.mode = polygon.MODE_EDIT;

                /* Redraw Toolbar */
                polygon.toolbar();

            });
        }

        if (polygon.mode == polygon.MODE_EDIT) {
            $('<a href="javascript:void(0);">Done Edit</a>').css(this.css_button).appendTo('#toolbar').bind('click', function () {

                /* Disable Edit Mode */
                polygon.polygon.disableEditing();

                /* Set Mode */
                polygon.mode = polygon.MODE_IDLE;

                /* Redraw Toolbar */
                polygon.toolbar();

            });
        }

        if (polygon.mode == polygon.MODE_IDLE) {
            $('<a href="javascript:void(0);">Remove Polygon</a>').css(this.css_button).appendTo('#toolbar').bind('click', function () {

                /* Remove Polygon */
                polygon.remove();

                /* Redraw Toolbar */
                polygon.toolbar();

            });
        }

    }

}