/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/release-license.txt 
 * for the full text of the license. */

/**
 * @requires OpenLayers/Control.js
 * @requires OpenLayers/Marker.js
 * @requires OpenLayers/Layer/Markers.js
*/

/**
 * Class: OpenLayers.Control.FeatureInfo
 * The feature info control can be used to retrieve attribute information
 * for several WMS layers in a map.
 * If the map object has set an activeLayer property, it will only query that
 * layer. Else it will query all visible and queryable WMS layers in the map.
 *
 * It is called FeatureInfo and not WMSFeatureInfo since in future new
 * layer types could be added to this control, like vector layers.
 * 
 * Inherits:
 *  - <OpenLayers.Control>
 */
OpenLayers.Control.PostGISFeatureInfo = OpenLayers.Class(OpenLayers.Control, {

    /**
     * APIProperty: showMarker
     * {Boolean} Should we show a marker where the user clicked in the map?
     *     There will only be one marker at a time.
     */
    showMarker: true,

    /**
     * APIProperty: markerIcon
     * {<OpenLayers.Icon>} the icon to use for the featureinfo marker
     */
    markerIcon: OpenLayers.Marker.defaultIcon(),

    /**
     * Constant: EVENT_TYPES
     *
     * Supported event types:
     * - *featureinfostart* Triggered when the user clicks in the map
     * - *featureinfoend* Triggered when all WMS GetFeatureInfo responses are in
     */ 
    EVENT_TYPES: ['featureinfostart', 'featureinfoend'],

    /**
     * Property: callbacks
     * {Object} The functions that are sent to the click handler for callback
     */
    callbacks: null,

    /**
     * Property: markerLayer
     * {<OpenLayers.Layer.Markers>} The marker layer in which the feature info
     *     marker will be drawn.
     */
    markerLayer: null,

    /**
     * Property: location
     * {<OpenLayers.LonLat>} The real-world location where the user clicked
     */
    location: null,

    /**
     * Property: feature
     * {<OpenLayers.Feature>} The feature from which the popup is created
     */
    feature: null,

    /**
     * Property: numVisibleLayers
     * {Integer} the number of layers that will be queried
     */
    numVisibleLayers: null,

    /**
     * Property; counter
     * {Integer} Counter is used to see how many of the WMS GetFeatureInfo 
     *     responses have been retrieved
    */
    counter: null,

    /**
     * Constructor: OpenLayers.Control.FeatureInfo
     * Create a new feature info control
     * 
     * Parameters:
     * options - {Object} An optional object whose properties will be set on
     *     the control
     */
    initialize: function(options) {
        this.EVENT_TYPES =
            OpenLayers.Control.PostGISFeatureInfo.prototype.EVENT_TYPES.concat(
                OpenLayers.Control.prototype.EVENT_TYPES); 

        OpenLayers.Control.prototype.initialize.apply(this, [options]);

        this.handler = new OpenLayers.Handler.Click(this, 
            OpenLayers.Util.extend({click: this.click}, this.callbacks));
    },

    /** 
     * Function: destroy
     * Destroy control.
     */
    destroy: function() {
        if (this.showMarker) {
            this.markerLayer.destroy();
            this.markerLayer = null;
            if (this.feature) {
                this.feature.destroy();
            }
        }
        OpenLayers.Control.prototype.destroy.apply(this, arguments);
    },     

    /**
     * Method: performRequest
     * 
     * Parameters:
     * layer - {<OpenLayers.Layer>} the GML layer
     * evt - {Event}
     */
    performRequest: function(layer, evt) {
    var carte = layer.map;
	    var lonlat = carte.getLonLatFromViewPortPx(evt.xy);
	    lonlat = lonlat.transform(new OpenLayers.Projection("EPSG:900913"), new OpenLayers.Projection("EPSG:4326"));
        var url = "requetePoint.php?layer="+layer.name+"&x="+lonlat.lon+"&y="+lonlat.lat;
        OpenLayers.Request.GET({
            url: url,
            success: this.returnResponse,
            scope: {control: this, layer: layer}
        }); 
    },

    /**
     * Method: click
     * Capture the click event
     *
     * Parameters:
     * evt - {Event}
     */
    click: function (evt) {
      this.events.triggerEvent('featureinfostart');
      this.numVisibleLayers = 0;
      var layer;
      if (!this.map.activeLayer) {
          for (var i=0, len = this.map.layers.length; i<len; i++) {
              layer = this.map.layers[i];
              if ((layer instanceof OpenLayers.Layer.GML) && 
                (layer.visibility) && (layer.queryable)) {
                    this.numVisibleLayers++;
              }
          }
      } else {
          // only the active layer
          if (!this.map.activeLayer.queryable) {
              // a null featurelist means the layer is not queryable
              this.events.triggerEvent('featureinfoend', {
                  featurelist: null
              });
              return false;
          } else {
              this.numVisibleLayers = 1;
          }
      }
      this.counter = 0;
      this.start();
      this.location =  this.map.getLonLatFromPixel(evt.xy);
      if (this.map.activeLayer) {
          this.performRequest(this.map.activeLayer, evt);
      } else {
          for (i=0, len=this.map.layers.length;i<len;i++) {
              layer = this.map.layers[i];
              if (layer instanceof OpenLayers.Layer.GML) {
                  // issue a GetFeatureInfo request to all visible and 
                  // queryable WMS layers
                  if (layer.visibility && layer.queryable) {
                      this.performRequest(layer, evt);
                  }
              }
          }
      }
    },

    /**
     * Method: returnResponse
     * Return the WMS GetFeatureInfo response and start up the processing
     *
     * Parameters:
     * response - {XMLHttpRequest}
    */
    returnResponse: function(response) {
        this.control.counter++;
        this.control.info(response, this.layer);
        if (this.control.counter == this.control.numVisibleLayers) {
            this.control.end();
        }
    },

    /**
     * Method: start
     * User clicked in the map
     */
    start: function() {
        this.featurelist = [];
    },

    /**
     * Method: end
     * All GetFeatureInfo responses have been received
     */
    end: function() {
        if (this.showMarker) {
            // raise the markerLayer to the top
            var idx = -1;
            for (var i=0, len = this.map.layers.length; i<len; i++) {
                var layer = this.map.layers[i];
                if (layer != this.markerLayer) {
                    idx = Math.max(this.map.getLayerIndex(
                        this.map.layers[i]), idx);
                }
            }
            if (this.map.getLayerIndex(this.markerLayer) < idx) {
                this.map.setLayerIndex(this.markerLayer, idx+1);
            }
            this.feature = new OpenLayers.Feature(this.markerLayer, 
                this.location, {icon: this.markerIcon});

            var marker = this.feature.createMarker();
            this.markerLayer.clearMarkers();
            this.markerLayer.addMarker(marker);
        }
        this.events.triggerEvent('featureinfoend', {
            featurelist: this.featurelist
        }); 
    },

    /** 
     * Method: info
     * Handle the response retrieved from the WMS
     *
     * Parameters:
     * response - {XMLHttpRequest} the response received
     * layer - {<OpenLayers.Layer>} the WMS layer on which the GetFeatureInfo 
               was performed
     */
    info: function(response, layer) {
        var format = new OpenLayers.Format.WMSGetFeatureInfo();
        var features = format.read(response.responseXML || 
            response.responseText);
        var obj = {title: layer.name, features: features};
        this.featurelist.push(obj);
    },

    /**
     * Method: setMap
     * 
     * Parameters:
     * map - {<OpenLayers.Map>} 
     */
    setMap: function(map) {
        OpenLayers.Control.prototype.setMap.apply(this, arguments);
        if (this.showMarker) {
            this.markerLayer = new OpenLayers.Layer.Markers('featureinfo', 
                {displayInLayerSwitcher: false});
            this.map.addLayer(this.markerLayer);
        }
    },

    CLASS_NAME: "OpenLayers.Control.PostGISFeatureInfo"

}); 

