/**
 * Measurement Window
 * Singleton object - we never need more than one
 */
MeasureWin = function() {

   MeasureWin.superclass.constructor.call(this, {
      title: 'Measurement Totals'
      ,closable: true
      ,closeAction: 'hide'
      ,collapsible: true
      ,bodyStyle: 'padding: 7px'
      ,width: 225
      ,height: 100 
      ,x: 350
      ,y: 100
      ,resizable: true
      ,modal: false
      ,listeners: {
         'hide': function() { MeasureWin.getInstance().deactivate(); }
      }
      ,items: [{
         xtype: 'panel'
         ,id: 'measure_results'
         ,bodyStyle: 'background-color: transparent'
         ,html: 'Click on the map to start measuring.'
         ,border: false
         ,autoHeight: true
      },{
         xtype: 'radiogroup'
         ,autoHeight: true
         ,defaultType: 'radio'
         ,items: [{
            hideLabel: true
            ,autoWidth:true
            ,autoHeight: true
            ,boxLabel: 'Miles'
            ,name: 'units'
            ,checked: true
            ,handler: function() {
               if (this.checked) {
                  MeasureWin.getInstance().setUnits(MeasureWin.MILES);
               }
            }
         },{
            hideLabel: true
            ,autoWidth:true
            ,autoHeight: true
            ,boxLabel: 'Kilometers'
            ,name: 'units'
            ,handler: function() {
               if (this.checked) {
                  MeasureWin.getInstance().setUnits(MeasureWin.KM);
               }
            }
         }]
      }]
   });
   this.doLayout();
}

MeasureWin.instance = null;
MeasureWin.MILES = "miles";
MeasureWin.KM = "km";

/**
 * Return the MeasureWin instance. Create it if necessary.
 * @return MeasureWin object
 */
MeasureWin.getInstance = function() {
   if (MeasureWin.instance == null) {
      MeasureWin.instance = new MeasureWin();
   }
   return MeasureWin.instance;
};

Ext.extend(MeasureWin, Ext.Window, {
   /*
   * Handle Measurement tool
   * takes in a feature from the measure tool
   * every time a point is added this gets called with the new point
   * we take that point and calc the distance from the last point to there
   * @param {OpenLayers.Measure Event}
   */
   total: 0
   ,previousTotal: 0
   ,units: MeasureWin.MILES
   ,startOver: false
   /**
    * Handle the single-click event that adds another vertx to the measurement
    * When this function is called the 'this' scope is Openlayers.Control.Measure, NOT
    * MeasureWin.
    * @param Event Click Event
    */
   ,handleMeasurements: function(event) {
       if (measureWin.startOver) {
          measureWin.total = 0;
          measureWin.previousTotal = 0;
          measureWin.startOver = false;
       }
       measureWin.previousTotal = measureWin.total;
       var geom    = event.geometry;
       measureWin.total = MeasureWin.calcVincenty(geom);
       measureWin.updateResults();
   }

   /**
    * Handle the double-click event to end measurement
    * When this function is called the 'this' scope is Openlayers.Control.Measure, NOT
    * MeasureWin.
    * @param Event Click Event
    */
   ,handleEndMeasurements: function(event) {
       var geom    = event.geometry;
       measureWin.total = MeasureWin.calcVincenty(geom);
       measureWin.updateResults();
       measureWin.startOver = true;  // Start with a new measurement next time
   }    

   /**
    * Set the units, based on the radio buttons
    * @param String units (based on constants defined above)
    */
   ,setUnits: function(units) {
      this.units = units;
      this.updateResults();
   }

   /**
    * Update the text in the measurement panel based on the current units selection
    */
   ,updateResults: function() {
      if (measureWin.units == MeasureWin.MILES) {
         Ext.get('measure_results').update(
            "Segment Distance: " + ((this.total - this.previousTotal) * .62137).toFixed(3) + 
            " Miles<br/>Total Distance: " + (this.total * .62137).toFixed(3) + " Miles"
         ); 
      } else {
         Ext.get('measure_results').update(
            "Segment Distance: " + (this.total - this.previousTotal).toFixed(3) + 
            " km<br/>Total Distance: " + this.total.toFixed(3) + " km");
      }
   }
   
   ,deactivate: function() {
      Ext.get('measure_results').update("Click on the map to start measuring");
      this.total = 0;
      this.previousTotal = 0;
      tbar_items.measure.deactivate();
      Ext.getCmp('measureButton').toggle(false);
      document.body.style.cursor = 'default';
   }
});

MeasureWin.calcVincenty = function(geometry) {
    /**
     * Note: this function assumes geographic coordinates and
     *     will fail otherwise.  OpenLayers.Util.distVincenty takes
     *     two objects representing points with geographic coordinates
     *     and returns the geodesic distance between them (shortest
     *     distance between the two points on an ellipsoid) in *kilometers*.
     *
     * It is important to realize that the segments drawn on the map
     *     are *not* geodesics (or "great circle" segments).  This means
     *     that in general, the measure returned by this function
     *     will not represent the length of segments drawn on the map.
     */
    var dist = 0;
    for (var i = 1; i < geometry.components.length; i++) {
        var first = geometry.components[i-1];
        firstPnt = new OpenLayers.LonLat(first.x, first.y);
        firstPnt.transform(map.getProjectionObject(), map.displayProjection);

        var second = geometry.components[i];
        secondPnt = new OpenLayers.LonLat(second.x, second.y);
        secondPnt.transform(map.getProjectionObject(), map.displayProjection);

        dist += OpenLayers.Util.distVincenty(
            {lon: firstPnt.lon, lat: firstPnt.lat},
            {lon: secondPnt.lon, lat: secondPnt.lat}
        );
    }
    return dist;
}

