/* 
 * Class and utility methods for build map configuration from XML document (or
 * eventually multiple sources).
 */

var  _debugFlag = false;

/**
 * Constructor.
 *
 * @param doc the Document object to build the config from.
 */
function MapConfig(doc) {
    if (doc == null) {
        _debug("WARNING: doc is null!");
        return;
    }

    var docRoot = doc.documentElement;

    // now work through child elements; valid elements are:
    //   icon
    //   point
    //   polyline
    for (var i = 0; i < docRoot.childNodes.length; i++) {
        var node = docRoot.childNodes[i];

        if (node.nodeName == "center") {
            // suss out center point
            
            var lat = node.getAttribute("lat");
            var lon = node.getAttribute("lon");
            var address = node.getAttribute("address");

            if ((lat != null) && (lon != null)) {
                this.centerPoint = new GLatLng(parseFloat(lat),parseFloat(lon));
            } else if (address != null) {
                _geocoder.getLatLng(
                    address,
                    function(point) {
                        this.centerPoint = point;
                    }
                );
            }

            var zoom = node.getAttribute("zoom");
            if (zoom != null) {
                this.zoomLevel = parseInt(zoom);
            }
        } else if (node.nodeName == "icon") {
            this.icons[node.getAttributeNode("name").value] = this._buildIcon(node);
        } else if (node.nodeName == "point") {
            var _point = new _MapPoint(node);

            // add to array
            this.pointList.push(_point);
            
            // add to hash
            if (_point.name != null) {
                this.points[_point.name] = _point;
            }
        } else if (node.nodeName == "polyline") {
            this.polyList.push(this._buildPolyline(node));
        }
    }
}

// new MapConfig(null); /* discard for JavaScript 1.1 */

// GPoint to center the map on; reasonable defaults?
MapConfig.prototype.centerPoint = new GLatLng(0,0);
MapConfig.prototype.zoomLevel = 13;

// "Hash" of icons
MapConfig.prototype.icons = {};

MapConfig.prototype.points = {};
MapConfig.prototype.pointList = new Array();
MapConfig.prototype.polyList = new Array();

MapConfig.prototype._buildIcon = function(node) {
    /*
    <icon name="tiny">
        <img src="http://labs.google.com/ridefinder/images/mm_20_red.png" width="12" height="20"/>
        <shadow src="http://labs.google.com/ridefinder/images/mm_20_shadow.png" width="22" height="20" />
        <anchor x="6" y="20" />
        <infoWindowAnchor x="5" y="1" />
    </icon>
    */

    var _icon = new GIcon();
    
    // get first child named img
    var childNode = node.getElementsByTagName("img")[0];
    
    _icon.image = childNode.getAttribute("src");
    _icon.iconSize =
        new GSize(
            parseInt(childNode.getAttribute("width")),
            parseInt(childNode.getAttribute("height"))
        );

    // get first child named shadow
    childNode = node.getElementsByTagName("shadow")[0];

    _icon.shadow = childNode.getAttribute("src");
    _icon.shadowSize =
        new GSize(
            parseInt(childNode.getAttribute("width")),
            parseInt(childNode.getAttribute("height"))
        );

    // get first child named anchor
    childNode = node.getElementsByTagName("anchor")[0];

    _icon.iconAnchor = 
        new GPoint(
            parseInt(childNode.getAttribute("x")),
            parseInt(childNode.getAttribute("y"))
        );
    
    // get first child named infoWindowAnchor
    childNode = node.getElementsByTagName("infoWindowAnchor")[0];

    _icon.infoWindowAnchor = 
        new GPoint(
            parseInt(childNode.getAttribute("x")),
            parseInt(childNode.getAttribute("y"))
        );
    
    return _icon;
}

MapConfig.prototype._buildPolyline = function(node) { /* no-op */ }

/**
 * _MapPoint constructor
 *
 * @param node node instance to build from
 */
function _MapPoint(pointNode) {
    if (pointNode == null) {
        _debug("MapPoint: node is null")
        return;
    }
    
    var nameAttr = pointNode.getAttribute("name");
    if (nameAttr != null) {
        this.name = nameAttr;
    }

    var iconAttr = pointNode.getAttribute("icon");
    if (iconAttr != null) {
        this.iconName = iconAttr;
    }

    var lat = pointNode.getAttribute("lat");
    var lon = pointNode.getAttribute("lon");
    var address = pointNode.getAttribute("address");
    
    if ((lat != null) && (lon != null)) {
        this.gpoint = new GLatLng(parseFloat(lat), parseFloat(lon));
    } else if (address != null) {
        this.address = address;
        _resolveAddressForMapPoint(this, this.address);
    }
    
    // now walk child nodes
    for (var i = 0; i < pointNode.childNodes.length; i++) {
        var child = pointNode.childNodes[i];
        child.normalize();
        
        if (child.nodeName == "label") {
            this.label = child.firstChild.data;
        } else if (child.nodeName == "url") {
            this.url = child.firstChild.data;
        } else if (child.nodeName == "blurb") {
            this.blurb = child.firstChild.data;
        } else {
            // unknown child
        }
    }
}

// new _MapPoint(null); /* discard */

_MapPoint.prototype.name = null;
_MapPoint.prototype.address = null;
_MapPoint.prototype.gpoint = null;
_MapPoint.prototype.label = null;
_MapPoint.prototype.url = null;
_MapPoint.prototype.blurb = null;
_MapPoint.prototype.iconName = null;

// UTILITY FUNCTIONS AND VARIABLES ===========================================
// Geocoder
var _geocoder = new GClientGeocoder();

// address resolver
function _resolveAddressForMapPoint(mapPoint, addr) {
    _debug("resolving address: " + addr);
    _geocoder.getLatLng(
        addr,
        function(gpoint) {
            _debug("addr result: " + gpoint);
            if (gpoint != null) {
                mapPoint.gpoint = gpoint;
            } else {
                _debug("could not resolve: " + addr);
            }
        }
    );
    
}

function _debug(msg) {
    if (_debugFlag) {
        GLog.write(msg);
    }
}
