text: /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for 
   * full list of contributors). Published under the Clear BSD license.  
   * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
   * full text of the license. */
  
  /**
   * @requires OpenLayers/Layer.js
   */
  
  /**
   * Class: OpenLayers.Layer.FixedZoomLevels
   *   Some Layers will already have established zoom levels (like google 
   *    or ve). Instead of trying to determine them and populate a resolutions[]
   *    Array with those values, we will hijack the resolution functionality
   *    here.
   * 
   *   When you subclass FixedZoomLevels: 
   * 
   *   The initResolutions() call gets nullified, meaning no resolutions[] array 
   *    is set up. Which would be a big problem getResolution() in Layer, since 
   *    it merely takes map.zoom and indexes into resolutions[]... but....
   * 
   *   The getResolution() call is also overridden. Instead of using the 
   *    resolutions[] array, we simply calculate the current resolution based
   *    on the current extent and the current map size. But how will we be able
   *    to calculate the current extent without knowing the resolution...?
   *  
   *   The getExtent() function is also overridden. Instead of calculating extent
   *    based on the center point and the current resolution, we instead 
   *    calculate the extent by getting the lonlats at the top-left and 
   *    bottom-right by using the getLonLatFromViewPortPx() translation function,
   *    taken from the pixel locations (0,0) and the size of the map. But how 
   *    will we be able to do lonlat-px translation without resolution....?
   * 
   *   The getZoomForResolution() method is overridden. Instead of indexing into
   *    the resolutions[] array, we call OpenLayers.Layer.getExent(), passing in
   *    the desired resolution. With this extent, we then call getZoomForExtent() 
   * 
   * 
   *   Whenever you implement a layer using OpenLayers.Layer.FixedZoomLevels, 
   *    it is your responsibility to provide the following three functions:
   * 
   *   - getLonLatFromViewPortPx
   *   - getViewPortPxFromLonLat
   *   - getZoomForExtent
   * 
   *  ...those three functions should generally be provided by any reasonable 
   *  API that you might be working from.
   *
   */
  OpenLayers.Layer.FixedZoomLevels = OpenLayers.Class({
        
    /********************************************************/
    /*                                                      */
    /*                 Baselayer Functions                  */
    /*                                                      */
    /*    The following functions must all be implemented   */
    /*                  by all base layers                  */
    /*                                                      */
    /********************************************************/
      
      /**
       * Constructor: OpenLayers.Layer.FixedZoomLevels
       * Create a new fixed zoom levels layer.
       */
      initialize: function() {
          //this class is only just to add the following functions... 
          // nothing to actually do here... but it is probably a good
          // idea to have layers that use these functions call this 
          // inititalize() anyways, in case at some point we decide we 
          // do want to put some functionality or state in here. 
      },
      
      /**
       * Method: initResolutions
       * Populate the resolutions array
       */
      initResolutions: function() {
  
          var props = new Array('minZoomLevel', 'maxZoomLevel', 'numZoomLevels');
            
          for(var i=0, len=props.length; i<len; i++) {
              var property = props[i];
              this[property] = (this.options[property] != null)  
                                       ? this.options[property] 
                                       : this.map[property];
          }
  
          if ( (this.minZoomLevel == null) ||
               (this.minZoomLevel < this.MIN_ZOOM_LEVEL) ){
              this.minZoomLevel = this.MIN_ZOOM_LEVEL;
          }        
  
          //
          // At this point, we know what the minimum desired zoom level is, and
          //  we must calculate the total number of zoom levels. 
          //  
          //  Because we allow for the setting of either the 'numZoomLevels'
          //   or the 'maxZoomLevel' properties... on either the layer or the  
          //   map, we have to define some rules to see which we take into
          //   account first in this calculation. 
          //
          // The following is the precedence list for these properties:
          // 
          // (1) numZoomLevels set on layer
          // (2) maxZoomLevel set on layer
          // (3) numZoomLevels set on map
          // (4) maxZoomLevel set on map*
          // (5) none of the above*
          //
          // *Note that options (4) and (5) are only possible if the user 
          //  _explicitly_ sets the 'numZoomLevels' property on the map to 
          //  null, since it is set by default to 16. 
          //
  
          //
          // Note to future: In 3.0, I think we should remove the default 
          // value of 16 for map.numZoomLevels. Rather, I think that value 
          // should be set as a default on the Layer.WMS class. If someone
          // creates a 3rd party layer and does not specify any 'minZoomLevel', 
          // 'maxZoomLevel', or 'numZoomLevels', and has not explicitly 
          // specified any of those on the map object either.. then I think
          // it is fair to say that s/he wants all the zoom levels available.
          // 
          // By making map.numZoomLevels *null* by default, that will be the 
          // case. As it is, I don't feel comfortable changing that right now
          // as it would be a glaring API change and actually would probably
          // break many peoples' codes. 
          //
  
          //the number of zoom levels we'd like to have.
          var desiredZoomLevels;
  
          //this is the maximum number of zoom levels the layer will allow, 
          // given the specified starting minimum zoom level.
          var limitZoomLevels = this.MAX_ZOOM_LEVEL - this.minZoomLevel + 1;
  
          if ( ((this.options.numZoomLevels == null) && 
                (this.options.maxZoomLevel != null)) // (2)
                ||
               ((this.numZoomLevels == null) &&
                (this.maxZoomLevel != null)) // (4)
             ) {
              //calculate based on specified maxZoomLevel (on layer or map)
              desiredZoomLevels = this.maxZoomLevel - this.minZoomLevel + 1;
          } else {
              //calculate based on specified numZoomLevels (on layer or map)
              // this covers cases (1) and (3)
              desiredZoomLevels = this.numZoomLevels;
          }
  
          if (desiredZoomLevels != null) {
              //Now that we know what we would *like* the number of zoom levels
              // to be, based on layer or map options, we have to make sure that
              // it does not conflict with the actual limit, as specified by 
              // the constants on the layer itself (and calculated into the
              // 'limitZoomLevels' variable). 
              this.numZoomLevels = Math.min(desiredZoomLevels, limitZoomLevels);
          } else {
              // case (5) -- neither 'numZoomLevels' not 'maxZoomLevel' was 
              // set on either the layer or the map. So we just use the 
              // maximum limit as calculated by the layer's constants.
              this.numZoomLevels = limitZoomLevels;
          }
  
          //now that the 'numZoomLevels' is appropriately, safely set, 
          // we go back and re-calculate the 'maxZoomLevel'.
          this.maxZoomLevel = this.minZoomLevel + this.numZoomLevels - 1;
  
          if (this.RESOLUTIONS != null) {
              var resolutionsIndex = 0;
              this.resolutions = [];
              for(var i= this.minZoomLevel; i <= this.maxZoomLevel; i++) {
                  this.resolutions[resolutionsIndex++] = this.RESOLUTIONS[i];            
              }
              this.maxResolution = this.resolutions[0];
              this.minResolution = this.resolutions[this.resolutions.length - 1];
          }       
      },
      
      /**
       * APIMethod: getResolution
       * Get the current map resolution
       * 
       * Returns:
       * {Float} Map units per Pixel
       */
      getResolution: function() {
  
          if (this.resolutions != null) {
              return OpenLayers.Layer.prototype.getResolution.apply(this, arguments);
          } else {
              var resolution = null;
              
              var viewSize = this.map.getSize();
              var extent = this.getExtent();
              
              if ((viewSize != null) && (extent != null)) {
                  resolution = Math.max( extent.getWidth()  / viewSize.w,
                                         extent.getHeight() / viewSize.h );
              }
              return resolution;
          }
       },
  
      /**
       * APIMethod: getExtent
       * Calculates using px-> lonlat translation functions on tl and br 
       *     corners of viewport
       * 
       * Returns:
       * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat 
       *                       bounds of the current viewPort.
       */
      getExtent: function () {
          var extent = null;
          
          
          var size = this.map.getSize();
          
          var tlPx = new OpenLayers.Pixel(0,0);
          var tlLL = this.getLonLatFromViewPortPx(tlPx);
  
          var brPx = new OpenLayers.Pixel(size.w, size.h);
          var brLL = this.getLonLatFromViewPortPx(brPx);
          
          if ((tlLL != null) && (brLL != null)) {
              extent = new OpenLayers.Bounds(tlLL.lon, 
                                         brLL.lat, 
                                         brLL.lon, 
                                         tlLL.lat);
          }
  
          return extent;
      },
  
      /**
       * Method: getZoomForResolution
       * Get the zoom level for a given resolution
       *
       * Parameters:
       * resolution - {Float}
       *
       * Returns:
       * {Integer} A suitable zoom level for the specified resolution.
       *           If no baselayer is set, returns null.
       */
      getZoomForResolution: function(resolution) {
        
          if (this.resolutions != null) {
              return OpenLayers.Layer.prototype.getZoomForResolution.apply(this, arguments);
          } else {
              var extent = OpenLayers.Layer.prototype.getExtent.apply(this, []);
              return this.getZoomForExtent(extent);
          }
      },
  
  
  
      
      /********************************************************/
      /*                                                      */
      /*             Translation Functions                    */
      /*                                                      */
      /*    The following functions translate GMaps and OL    */ 
      /*     formats for Pixel, LonLat, Bounds, and Zoom      */
      /*                                                      */
      /********************************************************/
      
      
      //
      // TRANSLATION: MapObject Zoom <-> OpenLayers Zoom
      //
    
      /**
       * Method: getOLZoomFromMapObjectZoom
       * Get the OL zoom index from the map object zoom level
       *
       * Parameters:
       * moZoom - {Integer}
       * 
       * Returns:
       * {Integer} An OpenLayers Zoom level, translated from the passed in zoom
       *           Returns null if null value is passed in
       */
      getOLZoomFromMapObjectZoom: function(moZoom) {
          var zoom = null;
          if (moZoom != null) {
              zoom = moZoom - this.minZoomLevel;
              if (this.map.baseLayer !== this) {
                  zoom = this.map.baseLayer.getZoomForResolution(
                      this.getResolutionForZoom(zoom)
                  )
              }
          }
          return zoom;
      },
      
      /**
       * Method: getMapObjectZoomFromOLZoom
       * Get the map object zoom level from the OL zoom level
       *
       * Parameters:
       * olZoom - {Integer}
       * 
       * Returns:
       * {Integer} A MapObject level, translated from the passed in olZoom
       *           Returns null if null value is passed in
       */
      getMapObjectZoomFromOLZoom: function(olZoom) {
          var zoom = null; 
          if (olZoom != null) {
              zoom = olZoom + this.minZoomLevel;
              if (this.map.baseLayer !== this) {
                  zoom = this.getZoomForResolution(
                      this.map.baseLayer.getResolutionForZoom(zoom)
                  );
              }
          }
          return zoom;
      },
  
      CLASS_NAME: "OpenLayers.Layer.FixedZoomLevels"
  });
  
  