/*----------------------------------------
$Id: VGMap.js,v 1.4 2005/10/10 03:09:26 mfrumin Exp $

This file is part of VGMap: http://vgmap.eyebeamresearch.org

Distributed under the Gnu Public License, see LICENSE

Copyright Copyright 2005 Michael Frumin
mfrumin@eyebeam.org, http://eyebeam.org
----------------------------------------*/

var VGM_Instances = new Array();

function VGMap(map, mapNodeId, overlayNodeId, vgmPath, debugNodeId) {
    this.map = map;
    this.lcId = "VGM_" +  new Date().getTime();
    this.vgmPath = vgmPath;
    this.flashProxy = new FlashProxy(this.lcId, vgmPath + "flash/JavaScriptFlashGateway.swf");

    this.mapNode = document.getElementById(mapNodeId);
    this.overlayNode = document.getElementById(overlayNodeId);
    this.debugNode = document.getElementById(debugNodeId);
    this.debugNodeId = debugNodeId;

    VGM_storeOverlay(this.lcId, this);
}


VGMap.prototype.go = function(offset, flashFile, flashVars) {

    mapOff = getNodeOffset(this.mapNode);
    mapSize = getNodeSize(this.mapNode);

    var width = mapSize.w - 2* offset;
    var height = mapSize.h - 2* offset;

    this.overlayNode.style.position = "absolute";

    this.overlayNode.style.left = (mapOff.x + offset) + "px";
    this.overlayNode.style.top = (mapOff.y + offset) + "px";

    this.overlayNode.style.height = height + "px";
    this.overlayNode.style.width = width + "px";

    // why create the flash_proxy node?  because we need the node to position the node
    // always on screen because it does not work in FF if the flash widget
    // is out of the viewing panel

    this.fpNodeId = "_flash_proxy_" + this.lcId;
    fpNode = document.getElementById(this.fpNodeId);

    if(!fpNode) {
        document.write('<div id="' + this.fpNodeId + '"></div>');
    }

    fpNode = document.getElementById(this.fpNodeId);
    if(fpNode) {
        fpNode.style.position = "absolute";
        fpNode.style.left = (mapOff.x + mapSize.w / 2.0) + "px";
        fpNode.style.top = (mapOff.y + mapSize.h / 2.0) + "px";
    }

    var flash = new FlashTag(this.vgmPath + "flash/VGMap.swf", width, height, "7,0,14,0");

    var fv = "lcId=" + this.lcId + "&VGMInBrowser=1";
    fv += "&VGMWidth=" + width + "&VGMHeight=" + height;
    fv += "&VGMOffset=" + offset;
    fv += "&VGMFlashFile=" + escape(flashFile);
    fv += "&VGMFlashVars=" + escape(flashVars);


    flash.setFlashvars(fv);

    this.overlayNode.innerHTML = flash.toString();

    this.initGMapListeners();
}



function VGM_lookupOverlay(lcId) {

    // is this safe?
    if(VGM_Instances[lcId]) {
        var vgm = VGM_Instances[lcId];
        return vgm;
    }
    return null;
}

function VGM_storeOverlay(lcId, overlay) {
    VGM_Instances[lcId] = overlay;
}


function VGM_onOverlayLoaded(lcId) {

    var vgm;
    if(vgm = VGM_lookupOverlay(lcId)) {
        vgm.onOverlayLoaded();
    }
}

VGMap.prototype.onOverlayLoaded = function() {
    // should we define a new method?
    this.sendCurrentMap();
}


function VGM_debugMsg(lcId, msg, clear) {

    var vgm;
    if(vgm = VGM_lookupOverlay(lcId)) {
        vgm.debugMsg(msg, clear);
    }
}

VGMap.prototype.debugMsg = function(msg, clear) {

    if(!this.debugNode && this.debugNodeId) {
        this.debugNode = document.getElementById(this.debugNodeId);
    }
    if(this.debugNode) {
        if(clear) {
            this.debugNode.innerHTML = '';
        }
        this.debugNode.innerHTML += msg + " \n";
    }
}

VGMap.prototype.sendCurrentMap = function() {
    this.flashProxy.call("VGM_setCurrentMap", this.getGMapParams(this.map));    
}


// needs to have a setup for which listeners it wants...

VGMap.prototype.initGMapListeners = function() {
    GEvent.bind(this.map, "click", this, this.onGMapClick)
    GEvent.bind(this.map, "movestart", this, this.onGMapMoveStart)
    GEvent.bind(this.map, "move", this, this.onGMapMove)
    GEvent.bind(this.map, "moveend", this, this.onGMapMoveEnd);
    GEvent.bind(this.map, "zoom", this, this.onGMapZoom)

    /* NOT IMPLEMENTED IN THE FLASH PART YET
    GEvent.bind(this.map, "maptypechanged", this, this.onGMapMapTypeChanged)
    GEvent.bind(this.map, "infowindowopen", this, this.onGMapInfoWindowOpen)
    GEvent.bind(this.map, "infowindowclose", this, this.onGMapInfoWindowClose)
    GEvent.bind(this.map, "addoverlay", this, this.onGMapAddOverlay)
    GEvent.bind(this.map, "removeoverlay", this, this.onGMapRemoveOverlay)
    GEvent.bind(this.map, "clearoverlays", this, this.onGMapClearOverlays)
    */
}
VGMap.prototype.getGMapParams = function(map) {

    var res = new Object;

    res.zoomLevel = map.getZoomLevel();

    res.centerLatLng_x = map.getCenterLatLng().x;
    res.centerLatLng_y = map.getCenterLatLng().y;

    res.boundsLatLng_minX = map.getBoundsLatLng().minX;
    res.boundsLatLng_minY = map.getBoundsLatLng().minY;
    res.boundsLatLng_maxX = map.getBoundsLatLng().maxX;
    res.boundsLatLng_maxY = map.getBoundsLatLng().maxY;

    res.spanLatLng_width = map.getSpanLatLng().width;
    res.spanLatLng_height = map.getSpanLatLng().height;

   
    /* We are using long single-level hashnames because the JS -> AS calls
     * get all F-ed up on nested objects

    res.centerLatLng = map.getCenterLatLng();
    res.boundsLatLng = map.getBoundsLatLng();
    res.spanLatLng = map.getSpanLatLng();
    */

    /* Skipping for now
    res.currentMapType = map.getCurrentMapType();
    res.mapTypes = map.getMapTypes();
    */

    return res;
}


/*
 onGMap* -- Boring methods that bounce the GMap events through to the flash proxy
*/

VGMap.prototype.onGMapClick = function(overlay, point) {
    this.flashProxy.call("VGM_click", this.getGMapParams(this.map), overlay, point);    
}

VGMap.prototype.onGMapMoveStart = function() {
    this.flashProxy.call("VGM_movestart", this.getGMapParams(this.map));    
}

VGMap.prototype.onGMapMove = function() {
    this.flashProxy.call("VGM_move", this.getGMapParams(this.map));    
}

VGMap.prototype.onGMapMoveEnd = function() {
    this.flashProxy.call("VGM_moveend", this.getGMapParams(this.map));    
}

VGMap.prototype.onGMapZoom = function(oldzoomlevel, newzoomlevel) {
    this.flashProxy.call("VGM_zoom", this.getGMapParams(this.map), oldzoomlevel, newzoomlevel);
}

VGMap.prototype.onGMapMapTypeChanged = function() {
    this.flashProxy.call("VGM_maptypechanged", this.getGMapParams(this.map));    
}

VGMap.prototype.onGMapInfoWindowOpen = function() {
    this.flashProxy.call("VGM_infowindowopen", this.getGMapParams(this.map));
}

VGMap.prototype.onGMapInfoWindowClose = function() {
    this.flashProxy.call("VGM_infowindowclose", this.getGMapParams(this.map));    
}

VGMap.prototype.onGMapAddOverlay = function(overlay) {
    this.flashProxy.call("VGM_addoverlay", this.getGMapParams(this.map), overlay);
}

VGMap.prototype.onGMapRemoveOverlay = function(overlay) {
    this.flashProxy.call("VGM_removeoverlay", this.getGMapParams(this.map), overlay); 
}

VGMap.prototype.onGMapClearOverlays = function() {
    this.flashProxy.call("VGM_clearoverlays", this.getGMapParams(this.map));    
}



// some browser-independent functions for getting the 
// location/size of HTML DOM nodes.

function getNodeOffset(node)
{
    /*
    if(this.node_x != null && this.node_y != null) {
        return new Refeed.Coord(this.node_x, this.node_y);
    }
    */
    
    var x = 0;
    var y = 0;
    
    if(node.nodeName == 'TR') {
        // in Safari, table rows have no offsetWidth/Height/Left/Right defined, 
        // so we will have to base these values on the contained table cells.
        for(var startingNode = node.firstChild; startingNode.nodeName != 'TD'; startingNode = startingNode.nextSibling) { continue; }
        
        for(var n = startingNode; n; n = n.offsetParent) {
            x += n.offsetLeft;
            y += n.offsetTop;
        }
    } else {
        for(var n = node; n; n = n.offsetParent) {
            x += n.offsetLeft;
            y += n.offsetTop;
        }
    }
    
    
    return {x : x, y: y};
}


function getNodeSize(node)
{
    var height = 0;
    var width = 0;

    if(node.nodeName == 'TR') {
        // in Safari, table rows have no offsetWidth/Height/Left/Right defined, 
        // so we will have to base these values on the contained table cells.
        for(var startingNode = node.firstChild; startingNode.nodeName != 'TD'; startingNode = startingNode.nextSibling) { continue; }

        for(var TD = startingNode; TD; TD = TD.nextSibling) {
            if(TD.nodeName == 'TD') {
                height = Math.max(height, TD.offsetHeight);
                width += TD.offsetWidth;
            }
        }
    } else {
        height = node.offsetHeight;
        width = node.offsetWidth;
    }
    
    return { h: height, w: width};
}
