text: /**
   * The axis-base submodule contains functionality for the handling of axis data in a chart.
   *
   * @module charts
   * @submodule axis-base
   */
  /**
   * An abstract class that provides the core functionality used by the following classes:
   * <ul>
   *      <li>{{#crossLink "CategoryAxisBase"}}{{/crossLink}}</li>
   *      <li>{{#crossLink "NumericAxisBase"}}{{/crossLink}}</li>
   *      <li>{{#crossLink "StackedAxisBase"}}{{/crossLink}}</li>
   *      <li>{{#crossLink "TimeAxisBase"}}{{/crossLink}}</li>
   *      <li>{{#crossLink "CategoryAxis"}}{{/crossLink}}</li>
   *      <li>{{#crossLink "NumericAxis"}}{{/crossLink}}</li>
   *      <li>{{#crossLink "StackedAxis"}}{{/crossLink}}</li>
   *      <li>{{#crossLink "TimeAxis"}}{{/crossLink}}</li>
   *  </ul>
   *
   * @class AxisBase
   * @constructor
   * @extends Base
   * @uses Renderer
   * @param {Object} config (optional) Configuration parameters.
   * @submodule axis-base
   */
  Y.AxisBase = Y.Base.create("axisBase", Y.Base, [Y.Renderer], {
      /**
       * @method initializer
       * @private
       */
      initializer: function()
      {
          this.after("minimumChange", Y.bind(this._keyChangeHandler, this));
          this.after("maximumChange", Y.bind(this._keyChangeHandler, this));
          this.after("keysChange", this._keyChangeHandler);
          this.after("dataProviderChange", this._dataProviderChangeHandler);
      },
  
      /**
       * Handles changes to `dataProvider`.
       *
       * @method _dataProviderChangeHandler
       * @param {Object} e Event object.
       * @private
       */
      _dataProviderChangeHandler: function()
      {
          var keyCollection = this.get("keyCollection").concat(),
              keys = this.get("keys"),
              i;
          if(keys)
          {
              for(i in keys)
              {
                  if(keys.hasOwnProperty(i))
                  {
                      delete keys[i];
                  }
              }
          }
          if(keyCollection && keyCollection.length)
          {
              this.set("keys", keyCollection);
          }
      },
  
      /**
       * Calculates the maximum and minimum values for the `Data`.
       *
       * @method _updateMinAndMax
       * @private
       */
      _updateMinAndMax: function() {
      },
  
      /**
       * Constant used to generate unique id.
       *
       * @property GUID
       * @type String
       * @private
       */
      GUID: "yuibaseaxis",
  
      /**
       * Type of data used in `Axis`.
       *
       * @property _type
       * @type String
       * @readOnly
       * @private
       */
      _type: null,
  
      /**
       * Storage for `setMaximum` attribute.
       *
       * @property _setMaximum
       * @type Object
       * @private
       */
      _setMaximum: null,
  
      /**
       * Storage for `setMinimum` attribute.
       *
       * @property _setMinimum
       * @type Object
       * @private
       */
      _setMinimum: null,
  
      /**
       * Reference to data array.
       *
       * @property _data
       * @type Array
       * @private
       */
      _data: null,
  
      /**
       * Indicates whether the all data is up to date.
       *
       * @property _updateTotalDataFlag
       * @type Boolean
       * @private
       */
      _updateTotalDataFlag: true,
  
      /**
       * Storage for `dataReady` attribute.
       *
       * @property _dataReady
       * @type Boolean
       * @readOnly
       * @private
       */
      _dataReady: false,
  
      /**
       * Adds an array to the key hash.
       *
       * @method addKey
       * @param value Indicates what key to use in retrieving
       * the array.
       */
      addKey: function (value)
  	{
          this.set("keys", value);
  	},
  
      /**
       * Gets an array of values based on a key.
       *
       * @method _getKeyArray
       * @param {String} key Value key associated with the data array.
       * @param {Array} data Array in which the data resides.
       * @return Array
       * @private
       */
      _getKeyArray: function(key, data)
      {
          var i = 0,
              obj,
              keyArray = [],
              len = data.length;
          for(; i < len; ++i)
          {
              obj = data[i];
              keyArray[i] = obj[key];
          }
          return keyArray;
      },
  
      /**
       * Updates the total data array.
       *
       * @method _updateTotalData
       * @private
       */
      _updateTotalData: function()
      {
  		var keys = this.get("keys"),
              i;
          this._data = [];
          for(i in keys)
          {
              if(keys.hasOwnProperty(i))
              {
                  this._data = this._data.concat(keys[i]);
              }
          }
          this._updateTotalDataFlag = false;
      },
  
      /**
       * Removes an array from the key hash.
       *
       * @method removeKey
       * @param {String} value Indicates what key to use in removing from
       * the hash.
       */
      removeKey: function(value)
      {
          var keys = this.get("keys");
          if(keys.hasOwnProperty(value))
          {
              delete keys[value];
              this._keyChangeHandler();
          }
      },
  
      /**
       * Returns a value based of a key value and an index.
       *
       * @method getKeyValueAt
       * @param {String} key value used to look up the correct array
       * @param {Number} index within the array
       * @return Number
       */
      getKeyValueAt: function(key, index)
      {
          var value = NaN,
              keys = this.get("keys");
          if(keys[key] && Y_Lang.isNumber(parseFloat(keys[key][index])))
          {
              value = keys[key][index];
          }
          return parseFloat(value);
      },
  
      /**
       * Returns values based on key identifiers. When a string is passed as an argument, an array of values is returned.
       * When an array of keys is passed as an argument, an object literal with an array of values mapped to each key is
       * returned.
       *
       * @method getDataByKey
       * @param {String|Array} value value used to identify the array
       * @return Array|Object
       */
      getDataByKey: function (value)
      {
          var obj,
              i,
              len,
              key,
              keys = this.get("keys");
          if(Y_Lang.isArray(value))
          {
              obj = {};
              len = value.length;
              for(i = 0; i < len; i = i + 1)
              {
                  key = value[i];
                  if(keys[key])
                  {
                      obj[key] = this.getDataByKey(key);
                  }
              }
          }
          else if(keys[value])
          {
              obj = keys[value];
          }
          else
          {
              obj = null;
          }
          return obj;
      },
  
      /**
       * Returns the total number of majorUnits that will appear on an axis.
       *
       * @method getTotalMajorUnits
       * @return Number
       */
      getTotalMajorUnits: function()
      {
          var units,
              majorUnit = this.get("styles").majorUnit;
          units = majorUnit.count;
          return units;
      },
  
      /**
       * Gets the distance that the first and last ticks are offset from there respective
       * edges.
       *
       * @method getEdgeOffset
       * @param {Number} ct Number of ticks on the axis.
       * @param {Number} l Length (in pixels) of the axis.
       * @return Number
       */
      getEdgeOffset: function(ct, l)
      {
          var edgeOffset;
          if(this.get("calculateEdgeOffset")) {
              edgeOffset = (l/ct)/2;
          } else {
              edgeOffset = 0;
          }
          return edgeOffset;
      },
  
      /**
       * Updates the `Axis` after a change in keys.
       *
       * @method _keyChangeHandler
       * @param {Object} e Event object.
       * @private
       */
      _keyChangeHandler: function()
      {
          this._updateMinAndMax();
          this._updateTotalDataFlag = true;
          this.fire("dataUpdate");
      },
  
      /**
       * Gets the default value for the `styles` attribute. Overrides
       * base implementation.
       *
       * @method _getDefaultStyles
       * @return Object
       * @protected
       */
      _getDefaultStyles: function()
      {
          var axisstyles = {
              majorUnit: {
                  determinant:"count",
                  count:11,
                  distance:75
              }
          };
          return axisstyles;
      },
  
      /**
       * Getter method for maximum attribute.
       *
       * @method _maximumGetter
       * @return Number
       * @private
       */
      _maximumGetter: function ()
      {
          var max = this.get("dataMaximum"),
              min = this.get("minimum");
          //If all values are zero, force a range so that the Axis and related series
          //will still render.
          if(min === 0 && max === 0)
          {
              max = 10;
          }
          if(Y_Lang.isNumber(this._setMaximum))
          {
              max = this._setMaximum;
          }
          return parseFloat(max);
      },
  
      /**
       * Setter method for maximum attribute.
       *
       * @method _maximumSetter
       * @param {Object} value
       * @private
       */
      _maximumSetter: function (value)
      {
          this._setMaximum = parseFloat(value);
          return value;
      },
  
      /**
       * Getter method for minimum attribute.
       *
       * @method _minimumGetter
       * @return Number
       * @private
       */
      _minimumGetter: function ()
      {
          var min = this.get("dataMinimum");
          if(Y_Lang.isNumber(this._setMinimum))
          {
              min = this._setMinimum;
          }
          return parseFloat(min);
      },
  
      /**
       * Setter method for minimum attribute.
       *
       * @method _minimumSetter
       * @param {Object} value
       * @private
       */
      _minimumSetter: function(val)
      {
          this._setMinimum = parseFloat(val);
          return val;
      },
  
      /**
       * Indicates whether or not the maximum attribute has been explicitly set.
       *
       * @method _getSetMax
       * @return Boolean
       * @private
       */
      _getSetMax: function()
      {
          return Y_Lang.isNumber(this._setMaximum);
      },
  
      /**
       * Indicates whether or not the minimum attribute has been explicitly set.
       *
       * @method _getSetMin
       * @return Boolean
       * @private
       */
      _getSetMin: function()
      {
          return Y_Lang.isNumber(this._setMinimum);
      }
  }, {
      ATTRS: {
          /**
           * Determines whether and offset is automatically calculated for the edges of the axis.
           *
           * @attribute calculateEdgeOffset
           * @type Boolean
           */
          calculateEdgeOffset: {
              value: false
          },
  
          labelFunction: {
              valueFn: function() {
                  return this.formatLabel;
              }
          },
  
          /**
           * Hash of array identifed by a string value.
           *
           * @attribute keys
           * @type Object
           */
          keys: {
              value: {},
  
              setter: function(val)
              {
                  var keys = {},
                      i,
                      len,
                      data = this.get("dataProvider");
                  if(Y_Lang.isArray(val))
                  {
                      len = val.length;
                      for(i = 0; i < len; ++i)
                      {
                          keys[val[i]] = this._getKeyArray(val[i], data);
                      }
  
                  }
                  else if(Y_Lang.isString(val))
                  {
                      keys = this.get("keys");
                      keys[val] = this._getKeyArray(val, data);
                  }
                  else
                  {
                      for(i in val)
                      {
                          if(val.hasOwnProperty(i))
                          {
                              keys[i] = this._getKeyArray(i, data);
                          }
                      }
                  }
                  this._updateTotalDataFlag = true;
                  return keys;
              }
          },
  
          /**
           *Returns the type of axis data
           *  <dl>
           *      <dt>time</dt><dd>Manages time data</dd>
           *      <dt>stacked</dt><dd>Manages stacked numeric data</dd>
           *      <dt>numeric</dt><dd>Manages numeric data</dd>
           *      <dt>category</dt><dd>Manages categorical data</dd>
           *  </dl>
           *
           * @attribute type
           * @type String
           */
          type:
          {
              readOnly: true,
  
              getter: function ()
              {
                  return this._type;
              }
          },
  
          /**
           * Instance of `ChartDataProvider` that the class uses
           * to build its own data.
           *
           * @attribute dataProvider
           * @type Array
           */
          dataProvider:{
              setter: function (value)
              {
                  return value;
              }
          },
  
          /**
           * The maximum value contained in the `data` array. Used for
           * `maximum` when `autoMax` is true.
           *
           * @attribute dataMaximum
           * @type Number
           */
          dataMaximum: {
              getter: function ()
              {
                  if(!Y_Lang.isNumber(this._dataMaximum))
                  {
                      this._updateMinAndMax();
                  }
                  return this._dataMaximum;
              }
          },
  
          /**
           * The maximum value that will appear on an axis.
           *
           * @attribute maximum
           * @type Number
           */
          maximum: {
              lazyAdd: false,
  
              getter: "_maximumGetter",
  
              setter: "_maximumSetter"
          },
  
          /**
           * The minimum value contained in the `data` array. Used for
           * `minimum` when `autoMin` is true.
           *
           * @attribute dataMinimum
           * @type Number
           */
          dataMinimum: {
              getter: function ()
              {
                  if(!Y_Lang.isNumber(this._dataMinimum))
                  {
                      this._updateMinAndMax();
                  }
                  return this._dataMinimum;
              }
          },
  
          /**
           * The minimum value that will appear on an axis.
           *
           * @attribute minimum
           * @type Number
           */
          minimum: {
              lazyAdd: false,
  
              getter: "_minimumGetter",
  
              setter: "_minimumSetter"
          },
  
          /**
           * Determines whether the maximum is calculated or explicitly
           * set by the user.
           *
           * @attribute setMax
           * @type Boolean
           */
          setMax: {
              readOnly: true,
  
              getter: "_getSetMax"
          },
  
          /**
           * Determines whether the minimum is calculated or explicitly
           * set by the user.
           *
           * @attribute setMin
           * @type Boolean
           */
          setMin: {
              readOnly: true,
  
              getter: "_getSetMin"
          },
  
          /**
           * Array of axis data
           *
           * @attribute data
           * @type Array
           */
          data: {
              getter: function ()
              {
                  if(!this._data || this._updateTotalDataFlag)
                  {
                      this._updateTotalData();
                  }
                  return this._data;
              }
          },
  
          /**
           * Array containing all the keys in the axis.
  
           * @attribute keyCollection
           * @type Array
           */
          keyCollection: {
              getter: function()
              {
                  var keys = this.get("keys"),
                      i,
                      col = [];
                  for(i in keys)
                  {
                      if(keys.hasOwnProperty(i))
                      {
                          col.push(i);
                      }
                  }
                  return col;
              },
              readOnly: true
          },
  
          /**
           * Object which should have by the labelFunction
           *
           * @attribute labelFunctionScope
           * @type Object
           */
          labelFunctionScope: {}
      }
  });
  