
// class variables
OtviaLabel.zIndex = 1;
OtviaLabel.count = 0;

OtviaLabel.prototype = new google.maps.OverlayView();

OtviaLabel.prototype.onRemove = function() {
	if (this.container != undefined && this.container != null)
		this.container.parentNode.removeChild(this.container);
	this.container = null;
}

OtviaLabel.prototype.draw = function() {
	this.ourRedraw();
}

OtviaLabel.prototype.onAdd = function() {
    
    this.className = this.opts.className || "markerTooltip";
    if (this.opts.marker /* && typeof opts.marker.getLatLng != "undefined" */) {
        this.marker = this.opts.marker;
        this.anchor = this.marker.getPosition();
        this.isStatic = this.opts.isStatic;
        
        this.markerMouseOver = this.mHover(true);
                    
        google.maps.event.addListener(this.marker, 'mouseover', this.markerMouseOver);
        this.moEvent = google.maps.event.addListener(this.marker, 'mouseout', this.mHover(false));
        google.maps.event.addListener(this.marker, 'click', this.mClick());
        google.maps.event.addListener(this.marker, 'mousemove', this.mMove());
    }
    else if ( this.opts.anchor && typeof this.opts.anchor.lat() != "undefined" ) {
        this.isStatic = this.opts.isStatic;
        this.anchor = this.opts.anchor
    }

    if (!this.anchor) throw "Invalid label configuration: no anchor point";
        
        this.container = document.createElement("div");
        this.container.className = this.className;
        this.container.style.position = "absolute";
        this.container.style.display = "none";
        
        this.mouseOverListener = google.maps.event.addDomListener(this.container, "mouseover", this.mouseOver());
        this.mouseOutListener = google.maps.event.addDomListener(this.container, "mouseout", this.mouseOut());
        // just eat the mousemove over the label
//        google.maps.event.addDomListener(this.container, "mousemove", doNothing);
        
        
        google.maps.event.addDomListener(this.container, "mousemove",  this.stopEvent("mousemove"), true);
        google.maps.event.addDomListener(this.container, "mouseup",  this.stopEvent("mouseup"));
        google.maps.event.addDomListener(this.container, "mousedown",  this.stopEvent("mousedown"));
        google.maps.event.addDomListener(this.container, "click",  this.stopEvent("click"));

		this.setContent(this.content);
        
        this.getPanes().overlayMouseTarget.appendChild(this.container);
        
        this.height = jQuery(this.container).height();
        
        adjustItemLabelOffset(this.opts.item);
        
        if (this.toBeStuck)
        	this.stickIt();
}
 
function OtviaLabel(content, opts) {
    if ( typeof opts != "object" ) throw "Invalid OtviaLabel configuration";
    if (!opts.map) throw "Invalid label configuration: no map";
    
    this.opts = opts;
    
    // this.shelterID = shelterID;
    
    this.content = content;
    
    this.height = 0;
    
    this.toBeStuck = false;
    
    this.objectCount = OtviaLabel.count++;

    this.setMap(opts.map);
}

OtviaLabel.prototype.setContent = function(content) {
    var t = this;
    
    if (content) {
    	t.content = content;
        
    if (t.container) {
	    if (t.mcEvent != undefined && t.mcEvent != null)
	    {
	        google.maps.event.removeListener(t.mcEvent);
	        t.mcEvent = null;
	    }

	    // clear all event handlers first
	    if (t.container.childNodes) {
		    for (var i=0; i<t.container.childNodes.length; i++)
		    	purge(t.container.childNodes[i]);
	    }
	    
        var point = t.container;
        t.content = content;
        jQuery(point).html(content);
        /*
        point.innerHTML = "";
        if ( typeof content == "object" ) {
            point.appendChild(content);
            t.content = point.innerHTML;
        } else {
            t.content = content;
            point.innerHTML = t.content;
        }
        */
        
        // GLog.write("content: "+t.content.substr(0, 80));
        
        var closeIcon;
  		// GLog.write("add closeIcon handler");
        closeIcon = jQuery("div.labelCloseIcon", t.container).get(0); // closeIcon = Element.extend(t.container).select('div.labelCloseIcon')[0];
        // GLog.write("closeIcon: "+ closeIcon.tagName + " " + closeIcon.nodeName);
        t.mcEvent = google.maps.event.addDomListener(closeIcon, "click", t.mClose());
        
        t.height = jQuery(t.container).height();        
    }
    
    setTimeout(executeThisFuncLater(timerUpdatePredictionDelta, t), 10);
    }
}

function doNothing() {
	GLog.write("in doNothing()");
}

OtviaLabel.prototype.mHover = function(s) {
    var _t = this; var _s = s;
    return function() {
		GLog.write("entered OtviaLabel.mHover: "+_s);

		//GLog.write("call setStatic ############## 4");
		
		// do nothing if mouse already over label
		if (!_t.isMouseOver) {
			if (_s) {
		        _t.container.style.zIndex = OtviaLabel.zIndex + "";
		        OtviaLabel.zIndex++;
	        }
			
	    	_t.setStatic(_s);
		}
    }
}

OtviaLabel.prototype.mMove = function() {

    var _t = this;

    return function() {


    //GLog.write("entered OtviaLabel.mMove()");

    if (!_t.isStatic) {
    	// if label is not showing then show label...probably moving from label to marker
    	// and we do not want to hide label
    	_t.markerMouseOver();
    }
	}
}

OtviaLabel.prototype.mClick = function() {

    var _t = this;

    return function() {


    //GLog.write("entered OtviaLabel.mClick()");

        if (_t.isStatic) {
        	if (_t.isClicked) {
        		// if already clicked and stuck then close the label
        		_t.mClose()();
        		// GLog.write("close in mClick");
        	} else {
                if (_t.moEvent) {
                	//GLog.write("moEvent removed");
                    google.maps.event.removeListener(_t.moEvent);
                    _t.moEvent = null;
                }
                _t.isClicked = true;
                //GLog.write("regular mClick");
        	}
        }
	}
}

OtviaLabel.prototype.mouseOver = function() {
    var _t = this;
    
    return function(evt) {

  	var relTarget = evt.relatedTarget;
  	
  	GLog.write("entered OtviaLabel.mouseOver()");
  	
  	if (evt.fromElement)
  		relTarget = evt.fromElement;
  		
  	if (!isAChildOf(_t.container, relTarget) && _t.container != relTarget) {

		GLog.write("OtviaLabel.mouseOver() exec");
	
		//GLog.write("call OtviaLabel.mouseOver() setStatic ##############");
        _t.container.style.zIndex = OtviaLabel.zIndex + "";
        OtviaLabel.zIndex++;
	    _t.setStatic(true);
	    
	    _t.isMouseOver = true;	    
    }

    }
}

OtviaLabel.prototype.mouseOut = function() {
    var _t = this;
    
    return function(evt) {

  	var relTarget = evt.relatedTarget;

	GLog.write("entered OtviaLabel.mouseOut()");
  	
  	if (evt.toElement)
  		relTarget = evt.toElement;
  		
  	if (!isAChildOf(_t.container, relTarget) && _t.container != relTarget) {
	    if (!_t.isClicked && _t.isStatic == true)
	    {
	        GLog.write("OtviaLabel.mouseOut() exec");

			//GLog.write("call OtviaLabel.mouseOut() setStatic ###########");
	        _t.setStatic(false);	           
	    }
	    
	    _t.isMouseOver = false;
    }
    }
}

OtviaLabel.prototype.mClose = function() {

    var _t = this;
    return function() {

    //GLog.write("entered OtviaLabel.mClose()");

        if (_t.isStatic) {
        	//GLog.write("isStatic: true mClose()");
            if (_t.isClicked) {
                _t.moEvent = google.maps.event.addListener(_t.marker, 'mouseout', _t.mHover(false));
                //GLog.write("mouseout Added mClose()");
            }
        }
        _t.isClicked = false;
        //GLog.write("call setStatic ############## 7");
        _t.setStatic(false);
        
        if (_t.opts.item && _t.opts.item.labelClosed)
        	_t.opts.item.labelClosed();

        //if (_t.shelterID) {
        	//jsShelterLabelController(_t.shelterID, false, true);
        	//GLog.write("jsShelterLabelController invoked mClose()");
        //}
    }
}

OtviaLabel.prototype.setAnchor = function(anchor) {
    try {
        if (anchor && anchor.lat() && anchor.lng()) {
        	//GLog.write("************************* setAnchor() "+anchor);
            this.anchor = anchor;
            this.ourRedraw();
        }
    } catch(E) {}
}

OtviaLabel.prototype.getAnchor = function() {
	if (this.anchor)
		return this.anchor;
	
	return null;
}


OtviaLabel.prototype.setOffset = function(offset) {
    try {
    	if (offset) {
    		// if (this.opts.item.shelterName)
    			// GLog.write("***** OtviaLabel.setOffset() for " + this.opts.item.shelterName + " to "+offset);
	        this.offset = offset;
	        this.ourRedraw();
        }
    } catch(E) {}
}

OtviaLabel.prototype.setStatic = function(s, doRedraw)
{	
    var _t = this;
    
    if (!_t.container)
    	return;
    
    var _s = s;
    
    // GLog.write("setStatic before: "+ _t.isStatic);
    
    if((_s != _t.isStatic) && _s == true) {
        _t.container.style.zIndex = OtviaLabel.zIndex + "";
        OtviaLabel.zIndex++;
    }
    
    // set timer to update predictionDelta
    if (_s) {    	
    	_t.updatePredictionDelta();
    	otviaLabelDeltaMinutesUpdates[_t.objectCount] = executeThisFuncLater(timerUpdatePredictionDelta, _t);
    } else {
    	otviaLabelDeltaMinutesUpdates[_t.objectCount] = null;    	
    }

    _t.isStatic = _s;
    
    if ((doRedraw == undefined) || doRedraw)
    	_t.ourRedraw(); // default action is to redraw
    	
    //GLog.write("setStatic after: "+ _t.isStatic);
   
}

function timerUpdatePredictionDelta(label) {
	if (label)
		label.updatePredictionDelta();
}

OtviaLabel.prototype.show = function(point, offset) {
    try {
        var t = this;
        
        if (!t.container)
        	return;
        
        // GLog.write("^^^^^^^^^^^^^^^^^^^^^^OtviaLabel.show(): height = " +t.height+ " t.offset "+t.offset.width+" , "+t.offset.height+" offset "+offset);

        var p = point  || t.anchor;
        var o = offset || t.offset || new google.maps.Size(0,0);
        if ( p && p.lat() ) {
        
        	GLog.write("call setStatic ############## 8");
        	t.setStatic(true, false);
        	
        	// if not clicked and no mouseout handler add it
        	if (!t.isClicked && t.moEvent == null)
        		t.moEvent = google.maps.event.addListener(t.marker, 'mouseout', t.mHover(false));        		

            t.anchor = p; t.offset = o;
            var pix = t.getProjection().fromLatLngToDivPixel(p);
            t.container.style.left = ( pix.x + o.width ) + "px";
            t.container.style.top  = ( pix.y + o.height ) + "px";
            t.container.style.display = "";
            
            // check if this is a group with an active shelter
            if (t.opts.item.isShelterLabelActive && t.opts.item.activeShelterDOMId) {
            	var scrollPos=0, div = jQuery("#"+t.opts.item.activeShelterDOMId);
            	
            	if (div) {
	            	div.prevAll().each(function () {
	            		// GLog.write("previous content "+jQuery(this).text());
	            		scrollPos += jQuery(this).height();
	            	});
	            	div.parent().scrollTop(scrollPos);            	
	            } else {
	            	GLog.write("ACTIVE SHELTER NOT FOUND");
	            }
            }

            GLog.write("------------------------------OtviaLabel.show(): offset "+o.width+" , "+o.height);
        }
    } catch(e) { }
}

OtviaLabel.prototype.updatePredictionDelta = function() {
    var t = this;
    if (!t.container)
    	return;

	// update dM in prediction label
    if (currentServerTime && t.opts.item.predictionTimes) {
    	for (var domId in t.opts.item.predictionTimes) {
    		var predTime = t.opts.item.predictionTimes[domId];
    		var dM = ((predTime - currentServerTime.millis)/(60*1000))|0;
    		if (dM > 0 && dM < 100) {
    			// try and update label
    			jQuery("#"+domId, t.container).text("("+dM+" min.)");
    		} else if (dM == 0) {
    			jQuery("#"+domId, t.container).text("(NOW)");    			
    		} else {
    			jQuery("#"+domId, t.container).text("");
    		}
    	}            	
    }	
}

OtviaLabel.prototype.hide = function() {
    try {
        var t = this;
        if (!t.container)
        	return;

		//GLog.write("call setStatic ############## 9");
		t.setStatic(false, false);
        t.isClicked = false;
        t.container.style.display = "none";
        t.container.style.zIndex = "0";
        
        // GLog.write("OtviaLabel.hide() exec");
    } catch(e) { }
}

OtviaLabel.prototype.ourRedraw = function() {
	
    if (!this.container)
    	return;
	
    if ( this.isStatic ) {
        this.show();
    } else {
        /* Show dynamic tooltips only on events, not on redraws */
        this.hide();
    }
}

OtviaLabel.prototype.stickIt = function() {
	var t = this;
	
	//GLog.write("entered stickIt");
	
    if (!t.container) {
    	t.toBeStuck = true; // so it can be stuck when label is added to the DOM
    	return;
    }
	
	//GLog.write("call setStatic ############## stickIt");
	t.setStatic(true, false);	
	t.mClick()();
	t.show();
	t.toBeStuck = false; // it has been stuck....clear flag
}

OtviaLabel.prototype.stopEvent = function(eventName) {
	var t = this;

	return function(eventObject) {
	    //if (!t.container)
	    	//return;
	
    if (eventObject && eventObject.stopPropagation) {
        eventObject.stopPropagation();
    }
//    if (eventObject.cancelBubble ) {
        eventObject.cancelBubble = true;
//    }
    
    if (eventObject && eventObject.preventDefault) {
        eventObject.preventDefault();
    }
//    if (eventObject) {
        eventObject.returnValue = false;
//    }
    
	// GEvent.trigger(t.container, eventName, eventObject);    
    
    }
}

OtviaLabel.prototype.destroy = function() {
	this.setMap(null);
} 

function isAChildOf(_parent, _child)
{
   if (_parent === _child) { return false; }
      while (_child && _child !== _parent)
   { _child = _child.parentNode; }

   return _child === _parent;
}    

