var gMap = null;
var gMapOverlays = [];

var LMap = function() {
    var _mSvgForced = true; 
    var _mSvgEnabled = true;

    function _getCenterLatLng(box) {
        var latN = box[0];
        var lngE = box[1];
        var latS = box[2];
        var lngW = box[3];

        var latDelta = latN - latS;
        var lat = latN - latDelta/2.0;
        
        var lngDelta = lngE - lngW;
        var lng = lngE - lngDelta/2.0;

        return { 'lat': lat, 'lng': lng };
    }

    function _getAreaPoints(box) {
        var latN = box[0];
        var lngE = box[1];
        var latS = box[2];
        var lngW = box[3];

        return [new GLatLng(latN, lngE), 
                new GLatLng(latN, lngW),
                new GLatLng(latS, lngW),
                new GLatLng(latS, lngE),
                new GLatLng(latN, lngE)];
    }

    return {
        GetCenterLatLng : function(areas, numDecimals) {
            var loc = _getCenterLatLng(areas[0]);
            var multiplier = Math.pow(10, numDecimals);
            loc.lat = Math.round(loc.lat * multiplier) / multiplier;
            loc.lng = Math.round(loc.lng * multiplier) / multiplier;
            return loc;
        },

        SetPrimaryArea : function(areaIndex) {
            for (var i = 0; i < gMapOverlays.length; i++) {
                if (i == areaIndex) { 
                    // set semi-transparent background on primary area
                    gMapOverlays[i].setStrokeStyle( { 'color': "#C00000", 'weight': 3, 'opacity': 1 } );
                    gMapOverlays[i].setFillStyle(   { 'color': "#C00000", 'weight': 2, 'opacity': 0.4 } );
                } else {
                    gMapOverlays[i].setStrokeStyle( { 'color': "#C00000", 'weight': 2, 'opacity': 1 } );
                    gMapOverlays[i].setFillStyle(   { 'color': "#FFFFFF", 'weight': 0, 'opacity': 0 } );
                }
            }

            var area = gAreas[areaIndex];
            var latN = area[0];
            var lngE = area[1];
            var latS = area[2];
            var lngW = area[3];

            // make this area bigger so that it appears correctly scaled on the map
            var latDelta = (latN - latS) / 2.0;
            var lngDelta = (lngE - lngW) / 2.0;
            latN = latN + latDelta;
            latS = latS - latDelta;
            lngE = lngE + lngDelta;
            lngW = lngW - lngDelta;

            var bounds = new GLatLngBounds();
            bounds.extend(new GLatLng(latN, lngE)); 
            bounds.extend(new GLatLng(latS, lngW));
            gMap.setCenter(bounds.getCenter(), gMap.getBoundsZoomLevel(bounds)); 
        },

        Show : function(areas) {
            if (!gMap) {
                gMap = new GMap2(document.getElementById("map_canvas"));
            }
            gMap.addControl(new GSmallMapControl());
            gMap.addControl(new GMapTypeControl());
            gMap.addControl(new GScaleControl());
            //gMap.setUIToDefault();

            var loc = _getCenterLatLng(areas[0]);

            var point = new GLatLng(loc.lat, loc.lng);
            gMap.addOverlay(new GMarker(point));
            gMap.setCenter(point, 5);

            for (var i = 0; i < areas.length; i++) {
                var points = _getAreaPoints(areas[i]);
                gMapOverlays[i] = new GPolygon(points, "#C00000", 2, 0.9, "#FFFFFF", 0);
                gMap.addOverlay(gMapOverlays[i]);
            }
            
            // set bounds of the map based on most precise largest lat/lng box
            this.SetPrimaryArea(0);
        }

    };
} ();

var InteractiveHash = function() {
    function _updateMap(e, action) {
        if (e == undefined) { // for IE
            e = event;
        }
        var element = Util.GetEventTarget(e);
        if (element.tagName == "SPAN") {
            var span = element;
            var prefix = span.id.substr(0, span.id.length-1);
            var index = span.id.substr(span.id.length-1);
            
            // set primary area on the map
            if (e.type == 'mouseover') {
                // select the area represented by the selected hash
                var areaIndex = gAreas.length - 1 - index;
                LMap.SetPrimaryArea(areaIndex);
            } else if (e.type == 'mouseout') {
                // reset to most precise area (represented by full hash)
                LMap.SetPrimaryArea(0); 
            }
            
            // change the style for the interactive hash
            for (var i = index; i >= 0; i--) {
                span = document.getElementById(prefix + i);
                if (e.type == 'mouseover') {
                    span.style.color = '#C00000';
                } else if (e.type == 'mouseout') {
                    span.style.color = '#000000';
                }
            }
        }
    }

    return {
        Init : function(hashDiv) {
            for (var i = 0; i < gHash.length - 1; i++) {
                var span = document.createElement('span');
                span.setAttribute('id', 'hash_char' + i);

                Util.AddEventHandler(span, 'onmouseout', InteractiveHash.OnMouseOut, 'InteractiveHash.OnMouseOut(event);');
                Util.AddEventHandler(span, 'onmouseover', InteractiveHash.OnMouseOver, 'InteractiveHash.OnMouseOver(event);');
                Util.SetInnerText(span, (i == 0) ? gHash.substr(0, 2) : gHash.substr(i+1, 1));
                hashDiv.appendChild(span);
            }
        },

        OnMouseOver : function(e) {
            _updateMap(e);
        },

        OnMouseOut : function(e) {
            _updateMap(e);
        }
    };
} ();

// ==============================================================
// STATIC CLASS: Hint
// ==============================================================
var Hint = function() {
    var _id = 'hint';

    return {
        Init : function() {
            var div = document.createElement('div');
            div.setAttribute('id', _id);
            document.body.appendChild(div);
        },

        Show : function(target, htmlContent, width) {
            var div = document.getElementById(_id);
            div.style.display = 'block';

            div.innerHTML = htmlContent;

            var offsets = Util.GetOffsets(target);
            div.style.top = offsets.top + target.clientHeight;
            div.style.left = offsets.left + target.clientWidth;
            if (width) {
                div.style.width = width + 'px';
            }

            Util.AddEventHandler(target, 'onmouseout', Hint.Hide, 'Hint.Hide();');
            Util.AddEventHandler(target, 'onfocus', Hint.Hide, 'Hint.Hide();');
            Util.AddEventHandler(target, 'onblur', Hint.Hide, 'Hint.Hide();');
        },
    
        Hide : function() {
            var div = document.getElementById(_id);
            div.style.display = 'none';
        }
    };
} ();

// ==============================================================
// STATIC CLASS: Util
// ==============================================================
var Util = function() {

    return {
        Trim : function(str) {
            return str.replace(/^\s*/, "").replace(/\s*$/, "");
        },

        AddEventHandler : function(element, eventName, functionPtr, functionText) {
            if (/MSIE \d+\.\d+;/.test(navigator.userAgent)) {
                // IE, always the special one
                switch (eventName) {
                    case 'onmouseover':
                        element.onmouseover = functionPtr;
                        return;    
                    case 'onmouseout':
                        element.onmouseout = functionPtr;
                        return;    
                    case 'onfocus':
                        element.onfocus = functionPtr;
                        return;    
                    case 'onblur':
                        element.onblur = functionPtr;
                        return;    
                    case 'onclick':
                        element.onclick = functionPtr;
                        return;    
                }
            } else {
                element.setAttribute(eventName, functionText);
            }
        },
        
        GetInnerText : function(element) {
            if(typeof(element.textContent) != "undefined") {
                return element.textContent; // Firefox
            } else if(typeof(element.innerText) != "undefined") {
                return element.innerText; // IE and Chrome
            }
        },
        
        SetInnerText : function(element, text) {
            if(typeof(element.textContent) != "undefined") {
                element.textContent = text; // Firefox
            } else if(typeof(element.innerText) != "undefined") {
                element.innerText = text; // IE and Chrome
            }
        },
        
        AddOptionToSelect : function(select, option) {
            try {
                select.add(option, null); // Firefox and Chrome
            } catch(e) {
                select.add(option); // IE
            }
        },
        
        GetEventTarget : function(e) {
            // TODO: do we need this line??
            if(e == null) { // IE only
                e = event;
            }
            
            if(typeof(e.target) != "undefined") { // Firefox and Chrome
                return e.target;
            } else if(typeof(e.srcElement) != "undefined") { // IE
                return e.srcElement;
            } else {
                return null;
            }
        },
        
        SetInputValue : function(inputElement, value) {
            if(inputElement.tagName != "INPUT") {
                return;
            }
        
            if(typeof(inputElement.value) != "undefined") {
                inputElement.value = value;
            } else if(typeof(inputElement.textContent) != "undefined") { 
                inputElement.textContent = value;
            }
        },
        
        GetInputValue : function(inputElement) {
            if(inputElement.tagName != "INPUT") {
                return null;
            }
            
            if(typeof(inputElement.value) != "undefined") {
                return inputElement.value;
            } else if(typeof(inputElement.textContent) != "undefined") { 
                return inputElement.textContent;
            }
        },

        GetOffsets : function(element) {
            var offsetLeft = element.offsetLeft;
            var offsetTop = element.offsetTop;
            var parent = element.offsetParent;
            while (parent != null) {
                offsetLeft += parent.offsetLeft;
                offsetTop += parent.offsetTop;
                parent = parent.offsetParent;
            }
            return { 'left': offsetLeft, 'top': offsetTop };
        }

    };
} ();

// ==============================================================
// STATIC CLASS: WindowEventManager
// ==============================================================
var WindowEventManager = function() {
	var eventFunctions = new Object();
	
	return {
	    EvalFunctionCalls : function(event) {
	        if(eventFunctions[event.type]) {
                var funcs = eventFunctions[event.type];
                for(var i = 0; i < funcs.length; i++) {
                    eval(funcs[i]);
	            }
	        }
	    },
	
		Attach : function() {
            for(var eventName in eventFunctions) {
                if(window.addEventListener) {
                    addEventListener(eventName, WindowEventManager.EvalFunctionCalls, false);
                } else if(window.attachEvent) {
                    attachEvent('on' + eventName, WindowEventManager.EvalFunctionCalls);
                }
            }
		},
		
		AddFunctionCall : function(eventName, functionCall) {
            if(eventFunctions[eventName]) {
                var funcs = eventFunctions[eventName];
                funcs[funcs.length] = functionCall;
            } else {
                var funcs = new Array();
                funcs[0] = functionCall;
                eventFunctions[eventName] = funcs;
            }
		}
	};
} ();

