// $Id: MapContext.Format.js,v 1.1.2.9 2008/12/15 19:25:41 openwereld Exp $

/**
 * @requires OpenLayers/Format/WMC.js
 */

OpenLayers.Format.WMC.vMapContext_Parser = OpenLayers.Class(
    OpenLayers.Format.WMC.v1_1_0, {
    
    read_wmc_Layer: function(context, node) {
        OpenLayers.Format.WMC.v1_1_0.prototype.read_wmc_Layer.apply(this, arguments);
        
        // set queryable attribute
        context.layers[context.layers.length - 1].queryable = (node.getAttribute("queryable") == "1");
    },
    
    getLayerFromInfo: function(layerInfo) {
        var layer = OpenLayers.Format.WMC.v1_1_0.prototype.getLayerFromInfo.apply(this, arguments);
        
        // extend a layer with legend properties if available
        if (layerInfo.styles[0].legend) {
            layer.legend = layerInfo.styles[0].legend;
        }
        return layer;
    },
    
    read_ol_baselayers: function(context, node) {
        //alert('read_ol_baselayers');
        context.baselayers = this.getChildValue(node);
    },
    
    write_ol_MapExtension: function(context) {
        var node = OpenLayers.Format.WMC.v1_1_0.prototype.write_ol_MapExtension.apply(this, arguments);
        
        var layers = context.layers;
        var baselayers = [];
        for (var i = 0; i < layers.length; i++) {
          if (layers[i].isBaseLayer) {
            var t = layers[i].CLASS_NAME.split('.');
            if (t[0] == 'OpenLayers' && t[1] == 'Layer') {
              if (t.length >= 3) {
                var layer_type = t[2].toLowerCase();
                switch(layer_type) {
                case 'google':
                  // todo: types of google maps
                  // e.g. layers[i].options.type.eF == 'Hybrid'
                  // todo: layer options like opacity, MIN_ZOOM_LEVEL
                  if (typeof layers[i].options.type.eF != 'undefined') {
                    layer_type += '-' + layers[i].options.type.eF.toLowerCase();
                  }
                  baselayers[baselayers.length] = layer_type;
                  break;
                case 'virtualearth':
                  baselayers[baselayers.length] = 've';
                  break;
                case 'tms':
                  baselayers[baselayers.length] = 'osm';
                  break;
                case 'yahoo':
                  baselayers[baselayers.length] = 'yahoo';
                  // todo: add baselayer options
                  break;
                default:
                  // ignore
                  break;
                }
              }
              else {
                baselayers[baselayers.length] = 'none';
              }
            }
          }
        }
        if (baselayers.length > 0) {
          var baselayersNode = this.createElementNS(this.namespaces.ol, 'ol:baselayers');
          baselayersNode.appendChild(this.createTextNode(baselayers.join(',')));
          node.appendChild(baselayersNode);
        }
        
        return node;
    },
    
    write_wmc_StyleList: function(layer) {
        var node = OpenLayers.Format.WMC.v1_1_0.prototype.write_wmc_StyleList.apply(this, arguments);
        if (layer.legend && !(layer.params['SLD'] || layer.params['SLD_BODY'])) {
            //
            var legend = this.createElementDefaultNS("LegendURL");
            legend.setAttribute('format', 'image/png'); // todo: from href
            legend.appendChild(this.write_wmc_OnlineResource(layer.legend.href));
            
            // find style child node
            var styles = node.getElementsByTagName("Style");
            if (styles.length > 0) {
                styles[0].appendChild(legend);
            }
        }
        return node;
    },
    
    CLASS_NAME: 'OpenLayers.Format.WMC.vMapContext_Parser'
});

/**
 * Class: OpenLayers.Format.MapContext
 * Read and write Web Map Context documents.
 *
 * Inherits from:
 *  - <OpenLayers.Format.WMC>
 */
OpenLayers.Format.MapContext = OpenLayers.Class(
    OpenLayers.Format.WMC, {
    
    /**
     * Constructor: OpenLayers.Format.WMC
     * Create a new parser for WMC docs.
     *
     * Parameters:
     * options - {Object} An optional object whose properties will be set on
     *     this instance.
     */
    initialize: function(options) {
        OpenLayers.Format.WMC.prototype.initialize.apply(
            this, [options]
        );
    },
    
    read: function(data, options) {
        this.version = 'MapContext.Parser';
        return OpenLayers.Format.WMC.prototype.read.apply(this, arguments);
    },
    
    write: function(data, options) {
        this.version = 'MapContext.Parser';
        return OpenLayers.Format.WMC.prototype.write.apply(this, arguments);
    },
    
    /**
     * Method: contextToMap
     * Create a map given a context object.
     *
     * Parameters:
     * context - {Object} The context object.
     * id - {String | Element} The dom element or element id that will contain
     *     the map.
     *
     * Returns:
     * {<OpenLayers.Map>} A map based on the context object.
     */
    contextToMap: function(context, id) {
        var map = new OpenLayers.Map(id, {
            maxExtent: context.maxExtent ? context.maxExtent : context.bounds,
            projection: context.projection
        });
        this.mergeContextToMap(context, map);
        map.setCenter(
            context.bounds.getCenterLonLat(),
            map.getZoomForExtent(context.bounds, true)
        );
        return map;
    },
    
    /**
     * Method: mergeContextToMap
     * Add layers from a context object to a map.
     *
     * Parameters:
     * context - {Object} The context object.
     * map - {<OpenLayers.Map>} The map.
     *
     * Returns:
     * {<OpenLayers.Map>} The same map with layers added.
     */
    mergeContextToMap: function(context, map) {
        if (context.baselayers) {
            var baselayers = context.baselayers.split(',');
            var layers = [];
            var common_options = {'isBaseLayer': true};
            if (map.projection.projCode == 'EPSG:900913') {
              common_options.sphericalMercator = true;
            }
            
            for (var i = 0; i < baselayers.length; i++) {
                var layer = { 'options': {} };
                var baselayer_def = baselayers[i].split('|');
                var baselayer = baselayer_def[0].split('-');
                
                // todo: get options from baselayer_def array
                for (var j = 1; j < baselayer_def.length; j++) {
                  var kv = baselayer_def[j].split('=');
                  if (kv.length == 2) {
                    key = kv[0];
                    value = kv[1];
                    // check for true/false and for a number
                    layer.options[key] = (value == 'true' ? true : (value == 'false' ? false : (isNaN(new Number(value)) ? value : parseFloat(value))));
                  }
                }
                
                switch (baselayer[0]) {
                case 'none':
                    layer.vendor = 'none';
                    break;
                case 'google':
                    if (typeof G_HYBRID_MAP == 'undefined') {
                      continue;
                    }
                    layer.vendor = 'google';
                    var type = G_HYBRID_MAP;
                    var variant = 'default';
                    if (baselayer.length > 1) {
                        switch (variant = baselayer[1]) {
                        case 'hybrid':
                            break;
                        case 'streets':
                            type = G_NORMAL_MAP;
                            break;
                        case 'satellite':
                            type = G_SATELLITE_MAP;
                            break;
                        case 'terrain':
                        case 'physical':
                            type = G_PHYSICAL_MAP;
                            break;
                        }
                    }
                    layer.title = 'Google - ' + variant;
                    layer.options.type = type;
                    break;
                case 'oam':
                    layer.vendor = 'oam';
                    layer.options.type = 'png';
                    layer.options.getURL = osm_getTileURL;
                    layer.options.displayOutsideMaxExtent = true;
                    layer.title = 'OpenAerialMap';
                    layer.options.attribution = '<a href="http://www.openaerialmap.org/">OpenAerialMap</a>';
                    common_options.sphericalMercator = true;
                    break;
                case 'osm':
                    layer.vendor = 'osm';
                    layer.options.type = 'png';
                    layer.options.getURL = osm_getTileURL;
                    layer.options.displayOutsideMaxExtent = true;
                    layer.title = 'OpenStreetMap';
                    layer.options.attribution = '<a href="http://www.openstreetmap.org/">OpenStreetMap</a>';
                    common_options.sphericalMercator = true;
                    break;
                case 've':
                    layer.vendor = 've';
                    if (typeof VEMapStyle == 'undefined') {
                      continue;
                    }
                    var type = VEMapStyle.Hybrid;
                    var variant = 'default';
                    layer.title = 'Virtual Earth - ' + variant;
                    layer.options.type = type;
                    break;
                case 'yahoo':
                    layer.vendor = 'yahoo';
                    if (typeof YAHOO_MAP_HYB == 'undefined') {
                      continue;
                    }
                    var type = YAHOO_MAP_HYB;
                    var variant = 'default';
                    layer.title = 'Yahoo - ' + variant;
                    layer.options.type = type;
                    break;
                default:
                    alert(Drupal.t('Unknown layer type: ' + baselayer[0]));
                    continue;
                }
                layers[layers.length] = layer;
            }
            
            // add layers now
            for (var i = 0; i < layers.length; i++) {
              var layer = layers[i];
              OpenLayers.Util.extend(layer.options, common_options);
              switch (layer.vendor) {
              case 'google':
                map.addLayers([new OpenLayers.Layer.Google(layer.title, layer.options)]);
                break;
              case 'none':
                map.addLayers([new OpenLayers.Layer(Drupal.t('None'), layer.options)]);
                break;
              case 'oam':
                map.addLayers([new OpenLayers.Layer.TMS(layer.title, 'http://tile.openaerialmap.org/tiles/1.0.0/openaerialmap-900913/', layer.options)]);
                break;
              case 'osm':
                map.addLayers([new OpenLayers.Layer.TMS(layer.title, 'http://tile.openstreetmap.org/', layer.options)]);
                break;
              case 've':
                map.addLayers([new OpenLayers.Layer.VirtualEarth(layer.title, layer.options)]);
                break;
              case 'yahoo':
                map.addLayers([new OpenLayers.Layer.Yahoo(layer.title, layer.options)]);
                break;
              }
            }
        }
        
        if (!map.baseLayer && context.layers.length > 0) {
            // the first layer in this context will be the base layer
            context.layers[0].isBaseLayer = true;
        }
        
        if (context.maxExtent) {
            // extend bounds
            map.maxExtent.extend(context.maxExtent);
        }
        
        // default WMC statement
        map.addLayers(context.layers);
        
        // use the context title
        if (!map.title) {
          map.title = context.title;
        }
        return map;
    },
    
    /**
     * Method: mapToContext
     * Create a context object given a map.
     *
     * Parameters:
     * map - {<OpenLayers.Map>} The map.
     *
     * Returns:
     * {Object} A context object.
     */
    mapToContext: function(map) {
        var context = OpenLayers.Format.WMC.prototype.mapToContext.apply(this, arguments);
        
        context.title = map.title;
        
        if (map.displayProjection) {
            // use displayProjection for map context
            context.projection = map.displayProjection;
            
            context.bounds.transform(map.projection, map.displayProjection);
            context.maxExtent.transform(map.projection, map.displayProjection);
        }
        
        return context;
    },

    CLASS_NAME: "OpenLayers.Format.MapContext"
});
