/*
 GxMarker version 2.0
 
 SYNOPSIS
    This version is compatible only with Google Maps API Version 2
 
    GxMarker is merely an extended marker that allows styled tooltip events.
 
    To setup a tooltip, pass in a third parameter (after the icon) to the
    GxMarker class:
        var marker = new GxMarker(new google.maps.Point(lat,lng),icon,"My Tooltip",?opts?);
        map.addOverlay(marker);
    Or:
        var marker = new GxMarker( new google.maps.Point(lat,lng) );
        marker.setTooltip("My Tooltip", ?opts?);
        map.addOverlay(marker);
 
    The opts should be a hash (var opts = { "field1": "value" }) that contains
    the configuration for the marker.  This allows a user to specify the
    offset, a "isStatic" boolean flag, and an alternative className to use
    intead of the default "markerTooltip"
 
    (This is a complete, 100% rewrite of GxMarker Version 1)
 
    TESTED PLATFORMS:
        Google Maps API V2 with:
        Linux: Firefox
        Windows: Firefox, IE6
        Mac OS X (Panther): Safari
 
    There is no warranty of functionality of this code, if you wish to use it
    and it does not work for you, I recommend you submit a patch.  This software
    is licensed under the GNU Lesser General Public License (LGPL):
    the full text at: http://opensource.org/licenses/lgpl-license.php

    Updated to use the Google AJAX Map API

 */

var __singleLabel;
var __singleLabelRefCount = 0;

var isClicked;
var moEvent;
var mcEvent;

var zIndex = 1;

function GxLabel( content, opts ) {
    if ( typeof opts != "object" ) throw "Invalid GxLabel configuration";
    
    this.content = content;
    //this.callbackParent = null;
    //this.isClicked = false;
    
    this.height = 0;
    
    if ( opts.offset && typeof opts.offset.width != "undefined" ) 
        this.offset = opts.offset
    else
        this.offset = new google.maps.Size(0,0);
    
    this.className = opts.className || "markerTooltip";
    if ( opts.marker && typeof opts.marker.getPoint != "undefined" ) {
        this.marker = opts.marker;
        this.anchor = opts.marker.getPoint();
        if ( opts.isStatic ) {
            this.isStatic = true;
        } else {
            
            //
            // Removing singleLabel
            //
            // __singleLabelRefCount++;
            
            /*
            google.maps.Event.addListener(this.marker, "mouseover",
            this.createSingletonClosure(this.show, this.anchor, this.offset, this.content, true));
            google.maps.Event.addListener(this.marker, "mouseout",
            this.createSingletonClosure(this.hide, this.anchor, this.offset, this.content, false));
             */
            
            google.maps.Event.addListener(this.marker, 'mouseover', this.mHover(true));
            this.moEvent = google.maps.Event.addListener(this.marker, 'mouseout', this.mHover(false));
            google.maps.Event.addListener(this.marker, 'click', this.mClick());        
            
            //this.moveHandle = true;
            
            //
            // Removing singleLabel
            //
            /*
            if ( !__singleLabel )
                __singleLabel = this;
            return __singleLabel;
             */
        }
        if ( opts.deleteHandle ) {
            this.deleteHandle = true;
        }
    }
    else if ( opts.anchor && typeof opts.anchor.lat != "undefined" ) {
        if ( opts.isStatic ) {
            this.isStatic = true;
        }
        if ( opts.moveHandle ) {
            this.moveHandle = true;
        }
        if ( opts.deleteHandle ) {
            this.deleteHandle = true;
        }
        this.anchor = opts.anchor
    }
    
    if ( opts.pane ) this.pane = opts.pane;
    if ( !this.anchor ) throw "Invalid label configuration: no anchor point";
    
}

GxLabel.prototype = new google.maps.Overlay();

GxLabel.prototype.initialize = function(map) {
    var t = this;
    
    //
    // Removing singleLabel
    //
    /*
    if ( __singleLabel && !this.isStatic )
        t = __singleLabel;
     */
    
    t.map = map;
    t.pane = map.getPane(t.pane || G_MAP_MARKER_PANE) ||
        map.getPane(G_MAP_MARKER_PANE);
    
    if ( !t.container ) {
        t.container = document.createElement("div");
        t.container.className = t.className;
        t.container.style.position = "absolute";
        
        //
        // XXX : thomasp - Updates for IE/FireFox event differences.
        //
        if (navigator.appVersion.indexOf("MSIE") != -1)
        {
            t.mouseOverListener = google.maps.Event.bindDom(t.container, "mouseenter", this, this.mouseOver);
            t.mouseOutListener = google.maps.Event.bindDom(t.container, "mouseleave", this, this.mouseOut);
        }
        else
        {
            t.mouseOverListener = google.maps.Event.bindDom(t.container, "mouseover", this, this.mouseOver);
            t.mouseOutListener = google.maps.Event.bindDom(t.container, "mouseout", this, this.mouseOut);
        }
        
        if ( t.moveHandle && !t.moveHandleNode ) {
            t.moveHandlePanel = t.pane;
            t.contentNode    = document.createElement("div");
            t.moveHandleNode = document.createElement("div");
            with( t.moveHandleNode.style ) {
                background = "#ccc";
                width      = "8px";
                height     = "100%";
                cssFloat   = "left";
                fontWeight = "bold";
                textAlign  = "center";
                borderRight = "1px solid #555";
            }
            t.contentNode.style.marginLeft = "10px";
            t.moveHandleNode.innerHTML = ":";
            
            t.container.appendChild(t.moveHandleNode);
            t.container.appendChild(t.contentNode);
            
            t.insertPoint     = t.contentNode;
            
        } else {
            t.insertPoint = t.container;
        }
        
        t.setContent(t.content);
        
        t.pane.appendChild(t.container);
        
        t.height = jQuery(t.container).height();
        
        var b = t.container;
        
        google.maps.Event.addDomListener(b, "click",
            function(e) {
                stopEvent(e); google.maps.Event.trigger(t, "click", e);
            });
            
        //
        // thomasp - Added new stop_propagation method for IE users.
        //
        google.maps.Event.addDomListener(b, "mouseup",
            function(e) {
                stop_propagation(e); google.maps.Event.trigger(t, "mouseup", e);
            });
        google.maps.Event.addDomListener(b, "mousedown",
            function(e) {
                stop_propagation(e); google.maps.Event.trigger(t, "mousedown", e);
            });
            
        //
        // XXX : thomasp - Updates for IE/FireFox event differences.
        //
        if (navigator.appVersion.indexOf("MSIE") != -1)
        {        
            google.maps.Event.addDomListener(b, "mouseenter",
            function(e) {
                stopEvent(e); google.maps.Event.trigger(t, "mouseenter", e);
            });
            google.maps.Event.addDomListener(b, "mouseleave",
            function(e) {
                stopEvent(e); google.maps.Event.trigger(t, "mouseleave", e);
            });
        }
        else
        {
            google.maps.Event.addDomListener(b, "mouseover",
            function(e) {
                stopEvent(e); google.maps.Event.trigger(t, "mouseover", e);
            });
            google.maps.Event.addDomListener(b, "mouseout",
            function(e) {
                stopEvent(e); google.maps.Event.trigger(t, "mouseout", e);
            });
        }
    }
}

GxLabel.prototype.setContent = function(content) {
    var t = this;
    
    //
    // Removing singleLabel
    //
    /*
    if ( __singleLabel && !this.isStatic )
        t = __singleLabel;
     */
    
    //
    // Always clean up events.
    //
    if (t.mcEvent != undefined && t.mcEvent != null)
    {
        google.maps.Event.removeListener(t.mcEvent);
        t.mcEvent = null;
    }
    
    if ( content ) {
        var point = t.insertPoint || t.container;
        point.innerHTML = "";
        if ( typeof content == "object" ) {
            point.appendChild(content);
            t.content = point.innerHTML;
        } else {
            t.content = content;
            point.innerHTML = t.content;
        }
        
        //
        // thomasp - Here we put the new 'Close' image
        //           to use.
        //
        var closeIcon;
        if ( t.deleteHandle ) {
              closeIcon = Element.extend(t.container).select('div.labelCloseIcon')[0];
              t.mcEvent = google.maps.Event.bindDom(closeIcon, "click", this, this.mClose());
        }
        else {
            closeIcon = Element.extend(t.container).select('div.labelCloseIcon')[0];
            if (t.mcEvent != undefined) {
                google.maps.Event.removeListener(t.mcEvent);
            }
            closeIcon.remove();
        }
        closeIcon = null;
    }
    
    this.height = jQuery(this.container).height();
        
}

GxLabel.prototype.setAnchor = function(anchor) {
    try {
        if ( anchor.lat() && anchor.lng() ) {
            this.anchor = anchor;
            this.redraw();
        }
    } catch(E) {}
}
    
GxLabel.prototype.setOffset = function(offset) {
    try {
        this.offset = offset;
        this.redraw();
    } catch(E) {}
}

GxLabel.prototype.remove = function() {
    if ( this.isStatic || --__singleLabelRefCount <= 0 ) {
        //
        // Added support to clean up the close event for the label
        // if this option is activated.
        //
        if (this.deleteHandle && this.mcEvent != undefined) {
            google.maps.Event.removeListener(this.mcEvent);
        }
        if (this.moEvent != undefined && this.moEvent != null) {
            google.maps.Event.removeListener(this.moEvent);
        }
        this.mcEvent = null;
        this.moEvent = null;
        
        this.container.parentNode.removeChild(this.container);
        google.maps.Event.trigger(this, "remove");
    }
}

GxLabel.prototype.copy = function() {
}

GxLabel.prototype.redraw = function(force) {
    if ( this.isStatic ) {
        this.show();
    } else {
        /* Show dynamic tooltips only on events, not on redraws */
        this.hide();
    }
}

GxLabel.prototype.createSingletonClosure = function(fn, p, o, c) {
    var _t = this; var obj = fn;
    var _p = p; var _o = o; var _c = c;
    p = null; fn = null; o = null; c = null;
    return function() {
        _t.setContent(_c);        
        obj.apply(_t, [ _p, _o ] );
    };
}

GxLabel.prototype.setStatic = function(s)
{
    var _t = this; 
    var _s = s;
    if(((_s != _t.isStatic) || _t.isClicked == true) && _s == true)
    {
        _t.container.style.zIndex = zIndex + "";
        zIndex++;
        //_t.map.removeOverlay(_t);
        //_t.map.addOverlay(_t);
    }
    else
    {
        //_t.container.style.zIndex = zIndex + "";
    }
    _t.isStatic = _s;
    _t.redraw();
   
}

GxLabel.prototype.mHover = function(s) {
    var _t = this; var _s = s;
    return function() {
        /*
        if(_s == true)
        {
            _t.container.style.zIndex = zIndex + "";
            zIndex++;
            //_t.map.removeOverlay(_t);
            //_t.map.addOverlay(_t);
        }
        else
        {
            //_t.container.style.zIndex = zIndex + "";
        }
        _t.isStatic = _s;
        _t.redraw();*/
        _t.setStatic(_s);
    }
}

GxLabel.prototype.mClick = function() {
    var _t = this;
    return function() {
        if (_t.isStatic) {
//            if (_t.isClicked) {
//                _t.moEvent = google.maps.Event.addListener(_t.marker, 'mouseout', _t.mHover(false));
//                _t.isClicked = false;
//                _t.isStatic = false;
//                _t.redraw();
//            }
//            else {
//                if(_t.moEvent != undefined)
//                {
//                    google.maps.Event.removeListener(_t.moEvent);
//                }
//                _t.isClicked = true;
//            }

            //
            // NOTE: This now simply eats the mouseout event if it exists
            //       on the object.
            //
            if (_t.moEvent != undefined)
            {
                google.maps.Event.removeListener(_t.moEvent);
            }
            _t.isClicked = true;
        }
    }
}

GxLabel.prototype.mClose = function() {
    var _t = this;
    return function() {
        if (_t.isStatic) {
            if (_t.isClicked && _t.isClicked != undefined) {
                _t.moEvent = google.maps.Event.addListener(_t.marker, 'mouseout', _t.mHover(false));
            }
        }
        _t.isClicked = false;
        _t.isStatic  = false;
        _t.redraw();
    }
}

GxLabel.prototype.show = function(point, offset) {
    try {
        var t = this;
        
        //
        // Removing singleLabel
        //
        /*
        if ( __singleLabel && !this.isStatic )
            t = __singleLabel;
         */
        
        var p = point  || t.anchor;
        var o = offset || t.offset || new google.maps.Size(0,0);
        if ( p && p.lat ) {
            t.anchor = p; t.offset = o;
            var pix = t.map.fromLatLngToDivPixel(p);
            t.container.style.left = ( pix.x + o.width ) + "px";
            t.container.style.top  = ( pix.y + o.height ) + "px";
            t.container.style.display = "";
            
        }
    } catch(e) { }
}

GxLabel.prototype.closeLabel = function() {
}

/* Pointless Params! */
GxLabel.prototype.hide = function(point, offset) {
    try {
        var t = this;
        
        //
        // Removing singleLabel
        //
        /*
        if ( __singleLabel && !this.isStatic )
            t = __singleLabel;
         */
        
        var p = point  || t.anchor;
        var o = offset || t.offset || new google.maps.Size(0,0);
        if ( p && p.lat ) {
            t.anchor = p; t.offset = o;
            var pix = t.map.fromLatLngToDivPixel(p);
            t.container.style.left = ( pix.x + o.width ) + "px";
            t.container.style.top  = ( pix.y + o.height ) + "px";
            t.container.style.display = "none";
            t.container.style.zIndex = "0";
        }
    } catch(e) { }
}

GxLabel.prototype.mouseOver = function(e) {    
    var _t = this;
       
    //return function() {
    if(_t.isStatic == false)
    {
        //           if(this.mouseOverListener)
        //           {
        //               google.maps.Event.removeListener(this.mouseOverListener);
        //           }
   
        //_t.isStatic = true;
        //_t.redraw();
        _t.setStatic(true);
            
        //            if(!this.mouseOutListener)
        //            {
        //                this.mouseOutListener = google.maps.Event.bindDom(_t.container, "mouseout", this, this.mouseOut);
        //            }
    }
    //}
}

GxLabel.prototype.mouseOut = function(e) {
    var _t = this;
     
    //return function() {
    if((_t.isClicked == undefined || _t.isClicked == false) && _t.isStatic == true)
    {
        //           if(this.mouseOutListener)
        //           {
        //               google.maps.Event.removeListener(this.mouseOutListener);
        //           }
        //_t.isStatic = false;
        //_t.redraw();
        _t.setStatic(false);
           
        //           if(!this.mouseOverListener)
        //           {
        //                this.mouseOverListener = google.maps.Event.bindDom(_t.container, "mouseover", this, this.mouseOver);
        //           }
    }
    //}
}

GxLabel.prototype.mouseUp = function(e) {
    if ( this.mouseUpListener )
        google.maps.Event.removeListener(this.mouseUpListener);
    /*
    if ( this.mouseMoveListener )
        google.maps.Event.removeListener(this.mouseMoveListener);
    if ( this.startDrag ) {
        
    }
    google.maps.Event.trigger(this, "moveend", this.anchor);
    this.startDrag = false;
    */
}

GxLabel.prototype.mouseMove = function(e) {
    if ( !this.startDrag ) {
        if ( this.mouseUpListener )
            google.maps.Event.removeListener(this.mouseUpListener);
        if ( this.mouseMoveListener )
            google.maps.Event.removeListener(this.mouseMoveListener);
        return false;
    }
    
    var point = new google.maps.Point(
    e.clientX - this.topLeftPoint.x, e.clientY - this.topLeftPoint.y);
    var anchor = this.map.fromDivPixelToLatLng(point);
    this.anchor = anchor;
    this.redraw();
}

GxLabel.prototype.mouseDown = function(e) {
    stopEvent(e);
    this.startDrag = true;
    /*
    var mapBounds = this.map.getBounds();
    var topleft = new google.maps.LatLng(
        mapBounds.getSouthWest().lat(),
        mapBounds.getNorthEast().lng());
    this.topLeftPoint = this.map.getCurrentMapType().getProjection().fromLatLngToPixel(topleft, this.map.getZoom());    
    this.topLeftPoint = this.map.fromLatLngToDivPixel(topleft);
     */

    this.topLeftPoint = new google.maps.Point(
    dojo.html.getAbsoluteX(document.getElementById("map")),
    dojo.html.getAbsoluteY(document.getElementById("map")));
    if ( !this.mouseUpListener ) {
        //google.maps.Event.bindDom(document.getElementById("map"), "mouseover", this, this.mouseOver);
        
        this.mouseUpListener = google.maps.Event.bindDom(document.getElementById("map"),
        "mouseup", this, this.mouseUp);
    }
    if ( !this.mouseMoveListener ) {
        this.mouseUpListener = google.maps.Event.bindDom(document.getElementById("map"),
        "mousemove", this, this.mouseMove);
    }
}

/* 
 * Kills an event's propagation and default action.  Not sure who the original
 * author of this function is, but I love it.
 */
function stopEvent(eventObject) {
    if (eventObject && eventObject.stopPropagation) {
        eventObject.stopPropagation();
    }
    if (window.event && window.event.cancelBubble ) {
        window.event.cancelBubble = true;
    }
    
    if (eventObject && eventObject.preventDefault) {
        eventObject.preventDefault();
    }
    if (window.event) {
        window.event.returnValue = false;
    }
}

/*
 * GxMarker
 */

function GxMarker(point, icon, tooltip, opts) {
    if ( tooltip ) {
        var oldInit  = this.initialize;
        var _t = this;
        var offset   = ( typeof opts == "object" ) ?
            (opts.offset || new google.maps.Point(22,0)) : new google.maps.Point(22,0);
        var isStatic = ( typeof opts == "object" ) ?
            (opts.isStatic || false ) : false;
        this.initialize = function(map) {
            var l = new GxLabel(tooltip, {
                "marker":   _t,
                "offset":   offset,
                "isStatic": isStatic
            });
            map.addOverlay(l);
            oldInit.apply(_t, [ map ]);
        }
    }
    google.maps.Marker.apply(this, [ point, icon ]);
}

GxMarker.prototype = new google.maps.Marker(new google.maps.LatLng(1,1));

function debug(msg) {
    var d = document.getElementById("debug") ?
        document.getElementById("debug") : document.body;
    d.appendChild(document.createTextNode("[" + new Date() + "] "));
    d.appendChild(document.createTextNode(msg));
    d.appendChild(document.createElement("br"));
}

// cross-browser function to stop event propogation.
// assign this as your event function.
// 
// thomasp - pulled from Google Group.
// 
// URL: http://groups.google.com/group/Google-Maps-API/msg/38dbc8efd6646363
//
// NOTE: in production code you will want to remove the
// GLog.write()s and probably also the window.alert()
// which checks the correctness of your code.
//
// Examples of how to use.
//
// // traditional "on" properties
// b.onclick = stop_propagation;
//
// // IE-specific attachEvent()
// // NOTE: the extra "on" before the event name
// b.attachEvent("onclick", stop_propagation);
//
// // DOM2 (Netscape, Firefox, NOT IE) addEventListener()
// // IMPORTANT: pass false, not true, for capture argument.
// b.addEventListener("click", stop_propagation, false);
//
// // Google GEvent addDomListener, which does one
// // of the above depending on the browser platform
// GEvent.addDomListener(b, "click", stop_propagation);
//
function stop_propagation(event)
{
    // var type = event ? event.type : window.event.type;
    // var phase = event ? event.eventPhase : "unknown";
    // google.maps.Log.write(this.id + ' ' + type + ' ' + event + ' ' + phase);

    // IE: it's important to test window.event, not event.
    // IE sends a non-null event for attachEvent() but that
    // event has no eventPhase or stopPropagation() properties.
    if (window.event) // IE
    {
        // google.maps.Log.write("used window.event.cancelBubble");
        window.event.cancelBubble = true; // for IE
    }
    else // non-IE
    {
        // NOTE: we cannot even mention event.cancelBubble here, not
        // even read it, because if we do, a hideous FireFox 1.5.0.4
        // (and probably also Netscape) IE compatiblity hack will kick
        // into action and change the value of event.eventPhase to 0,
        // which is bad if eventPhase happens to have been
        // CAPTURING_PHASE (1) (see below). don't believe me?  try it:
        // GLog.write("phase=" + event.eventPhase);
        // GLog.write("cancel=" + event.cancelBubble);
        // GLog.write("now phase=" + event.eventPhase);

        if (event.eventPhase == 1)
        {
            // don't call stopPropogation() in CAPTURING_PHASE (1) --
            // we want events to be able to propogate down, but not up.
            // this is really user error; almost certainly the user
            // called
            //   b.addEventListener(e, f, false)
            // instead of
            //   b.addEventListener(e, f, true).
            // in which case they WON'T call us at the right time!
            // google.maps.Log.write("avoided stopPropogation--wrong phase");
        }
        else
        {
            // google.maps.Log.write("used stopPropogation");
            event.stopPropagation();
        }
    }
} 


