text: /**
   * Graph manages and contains series instances for a `CartesianChart`
   * instance.
   *
   * @module charts
   * @class Graph
   * @constructor
   * @extends Widget
   * @uses Renderer
   */
  Y.Graph = Y.Base.create("graph", Y.Widget, [Y.Renderer], {
      /**
       * @method bindUI
       * @private
       */
      bindUI: function()
      {
          var bb = this.get("boundingBox");
          bb.setStyle("position", "absolute");
          this.after("widthChange", this._sizeChangeHandler);
          this.after("heightChange", this._sizeChangeHandler);
          this.after("stylesChange", this._updateStyles);
      },
  
      /**
       * @method syncUI
       * @private
       */
      syncUI: function()
      {
          var background,
              cb,
              bg,
              sc = this.get("seriesCollection"),
              series,
              i = 0,
              len = sc.length,
              hgl = this.get("horizontalGridlines"),
              vgl = this.get("verticalGridlines");
          if(this.get("showBackground"))
          {
              background = this.get("background");
              cb = this.get("contentBox");
              bg = this.get("styles").background;
              bg.stroke = bg.border;
              bg.stroke.opacity = bg.stroke.alpha;
              bg.fill.opacity = bg.fill.alpha;
              bg.width = this.get("width");
              bg.height = this.get("height");
              bg.type = bg.shape;
              background.set(bg);
          }
          for(; i < len; ++i)
          {
              series = sc[i];
              if(series instanceof Y.CartesianSeries)
              {
                  series.render();
              }
          }
          if(hgl && hgl instanceof Y.Gridlines)
          {
              hgl.draw();
          }
          if(vgl && vgl instanceof Y.Gridlines)
          {
              vgl.draw();
          }
      },
     
      /**
       * Object of arrays containing series mapped to a series type.
       *
       * @property seriesTypes
       * @type Object
       * @private
       */
      seriesTypes: null,
  
      /**
       * Returns a series instance based on an index.
       * 
       * @method getSeriesByIndex
       * @param {Number} val index of the series
       * @return CartesianSeries
       */
      getSeriesByIndex: function(val)
      {
          var col = this.get("seriesCollection"),
              series;
          if(col && col.length > val)
          {
              series = col[val];
          }
          return series;
      },
  
      /**
       * Returns a series instance based on a key value.
       * 
       * @method getSeriesByKey
       * @param {String} val key value of the series
       * @return CartesianSeries
       */
      getSeriesByKey: function(val)
      {
          var obj = this._seriesDictionary,
              series;
          if(obj && obj.hasOwnProperty(val))
          {
              series = obj[val];
          }
          return series;
      },
  
      /**
       * Adds dispatcher to a `_dispatcher` used to
       * to ensure all series have redrawn before for firing event.
       *
       * @method addDispatcher
       * @param {CartesianSeries} val series instance to add
       * @protected
       */
      addDispatcher: function(val)
      {
          if(!this._dispatchers)
          {
              this._dispatchers = [];
          }
          this._dispatchers.push(val);
      },
  
      /**
       * Collection of series to be displayed in the graph.
       *
       * @property _seriesCollection
       * @type Array
       * @private 
       */
      _seriesCollection: null,
      
      /**
       * Object containing key value pairs of `CartesianSeries` instances.
       *
       * @property _seriesDictionary
       * @type Object
       * @private
       */
      _seriesDictionary: null,
  
      /**
       * Parses series instances to be displayed in the graph.
       *
       * @method _parseSeriesCollection
       * @param {Array} Collection of `CartesianSeries` instances or objects container `CartesianSeries` attributes values.
       * @private
       */
      _parseSeriesCollection: function(val)
      {
          if(!val)
          {
              return;
          }	
          var len = val.length,
              i = 0,
              series,
              seriesKey;
          if(!this.get("seriesCollection"))
          {
              this._seriesCollection = [];
          }
          if(!this._seriesDictionary)
          {
              this._seriesDictionary = {};
          }
          if(!this.seriesTypes)
          {
              this.seriesTypes = [];
          }
          for(; i < len; ++i)
          {	
              series = val[i];
              if(!(series instanceof Y.CartesianSeries) && !(series instanceof Y.PieSeries))
              {
                  this._createSeries(series);
                  continue;
              }
              this._addSeries(series);
          }
          len = this.get("seriesCollection").length;
          for(i = 0; i < len; ++i)
          {
              series = this.get("seriesCollection")[i];
              seriesKey = series.get("direction") == "horizontal" ? "yKey" : "xKey";
              this._seriesDictionary[series.get(seriesKey)] = series;
          }
      },
  
      /**
       * Adds a series to the graph.
       *
       * @method _addSeries
       * @param {CartesianSeries} series Series to add to the graph.
       * @private
       */
      _addSeries: function(series)
      {
          var type = series.get("type"),
              seriesCollection = this.get("seriesCollection"),
              graphSeriesLength = seriesCollection.length,
              seriesTypes = this.seriesTypes,
              typeSeriesCollection;	
          if(!series.get("graph")) 
          {
              series.set("graph", this);
          }
          seriesCollection.push(series);
          if(!seriesTypes.hasOwnProperty(type))
          {
              this.seriesTypes[type] = [];
          }
          typeSeriesCollection = this.seriesTypes[type];
          series.set("graphOrder", graphSeriesLength);
          series.set("order", typeSeriesCollection.length);
          typeSeriesCollection.push(series);
          this.addDispatcher(series);
          series.after("drawingComplete", Y.bind(this._drawingCompleteHandler, this));
          this.fire("seriesAdded", series);
      },
  
      /**
       * Creates a `CartesianSeries` instance from an object containing attribute key value pairs. The key value pairs include attributes for the specific series and a type value which defines the type of
       * series to be used. 
       *
       * @method createSeries
       * @param {Object} seriesData Series attribute key value pairs.
       * @private
       */
      _createSeries: function(seriesData)
      {
          var type = seriesData.type,
              seriesCollection = this.get("seriesCollection"),
              seriesTypes = this.seriesTypes,
              typeSeriesCollection,
              seriesType,
              series;
              seriesData.graph = this;
          if(!seriesTypes.hasOwnProperty(type))
          {
              seriesTypes[type] = [];
          }
          typeSeriesCollection = seriesTypes[type];
          seriesData.graph = this;
          seriesData.order = typeSeriesCollection.length;
          seriesData.graphOrder = seriesCollection.length;
          seriesType = this._getSeries(seriesData.type);
          series = new seriesType(seriesData);
          this.addDispatcher(series);
          series.after("drawingComplete", Y.bind(this._drawingCompleteHandler, this));
          typeSeriesCollection.push(series);
          seriesCollection.push(series);
      },
      
      /**
       * String reference for pre-defined `Series` classes.
       *
       * @property _seriesMap
       * @type Object
       * @private
       */
      _seriesMap: {
          line : Y.LineSeries,
          column : Y.ColumnSeries,
          bar : Y.BarSeries,
          area :  Y.AreaSeries,
          candlestick : Y.CandlestickSeries,
          ohlc : Y.OHLCSeries,
          stackedarea : Y.StackedAreaSeries,
          stackedline : Y.StackedLineSeries,
          stackedcolumn : Y.StackedColumnSeries,
          stackedbar : Y.StackedBarSeries,
          markerseries : Y.MarkerSeries,
          spline : Y.SplineSeries,
          areaspline : Y.AreaSplineSeries,
          stackedspline : Y.StackedSplineSeries,
          stackedareaspline : Y.StackedAreaSplineSeries,
          stackedmarkerseries : Y.StackedMarkerSeries,
          pie : Y.PieSeries,
          combo : Y.ComboSeries,
          stackedcombo : Y.StackedComboSeries,
          combospline : Y.ComboSplineSeries,
          stackedcombospline : Y.StackedComboSplineSeries
      },
  
      /**
       * Returns a specific `CartesianSeries` class based on key value from a look up table of a direct reference to a class. When specifying a key value, the following options
       * are available:
       *
       *  <table>
       *      <tr><th>Key Value</th><th>Class</th></tr>
       *      <tr><td>line</td><td>Y.LineSeries</td></tr>    
       *      <tr><td>column</td><td>Y.ColumnSeries</td></tr>    
       *      <tr><td>bar</td><td>Y.BarSeries</td></tr>    
       *      <tr><td>area</td><td>Y.AreaSeries</td></tr>    
       *      <tr><td>stackedarea</td><td>Y.StackedAreaSeries</td></tr>    
       *      <tr><td>stackedline</td><td>Y.StackedLineSeries</td></tr>    
       *      <tr><td>stackedcolumn</td><td>Y.StackedColumnSeries</td></tr>    
       *      <tr><td>stackedbar</td><td>Y.StackedBarSeries</td></tr>    
       *      <tr><td>markerseries</td><td>Y.MarkerSeries</td></tr>    
       *      <tr><td>spline</td><td>Y.SplineSeries</td></tr>    
       *      <tr><td>areaspline</td><td>Y.AreaSplineSeries</td></tr>    
       *      <tr><td>stackedspline</td><td>Y.StackedSplineSeries</td></tr>
       *      <tr><td>stackedareaspline</td><td>Y.StackedAreaSplineSeries</td></tr>
       *      <tr><td>stackedmarkerseries</td><td>Y.StackedMarkerSeries</td></tr>
       *      <tr><td>pie</td><td>Y.PieSeries</td></tr>
       *      <tr><td>combo</td><td>Y.ComboSeries</td></tr>
       *      <tr><td>stackedcombo</td><td>Y.StackedComboSeries</td></tr>
       *      <tr><td>combospline</td><td>Y.ComboSplineSeries</td></tr>
       *      <tr><td>stackedcombospline</td><td>Y.StackedComboSplineSeries</td></tr>
       *  </table>
       * 
       * When referencing a class directly, you can specify any of the above classes or any custom class that extends `CartesianSeries` or `PieSeries`.
       *
       * @method _getSeries
       * @param {String | Object} type Series type.
       * @return CartesianSeries
       * @private
       */
      _getSeries: function(type)
      {
          var seriesClass;
          if(Y_Lang.isString(type))
          {
              seriesClass = this._seriesMap[type];
          }
          else 
          {
              seriesClass = type;
          }
          return seriesClass;
      },
  
      /**
       * Event handler for marker events.
       *
       * @method _markerEventHandler
       * @param {Object} e Event object.
       * @private
       */
      _markerEventHandler: function(e)
      {
          var type = e.type,
              markerNode = e.currentTarget,
              strArr = markerNode.getAttribute("id").split("_"),
              series = this.getSeriesByIndex(strArr[1]),
              index = strArr[2];
          series.updateMarkerState(type, index);
      },
  
      /**
       * Collection of `CartesianSeries` instances to be redrawn.
       *
       * @property _dispatchers
       * @type Array
       * @private
       */
      _dispatchers: null,
  
      /**
       * Updates the `Graph` styles.
       *
       * @method _updateStyles
       * @private
       */
      _updateStyles: function()
      {
          var styles = this.get("styles").background,
              border = styles.border;
              border.opacity = border.alpha;
              styles.stroke = border;
              styles.fill.opacity = styles.fill.alpha;
          this.get("background").set(styles);
          this._sizeChangeHandler();
      },
  
      /**
       * Event handler for size changes.
       *
       * @method _sizeChangeHandler
       * @param {Object} e Event object.
       * @private
       */
      _sizeChangeHandler: function(e)
      {
          var hgl = this.get("horizontalGridlines"),
              vgl = this.get("verticalGridlines"),
              w = this.get("width"),
              h = this.get("height"),
              bg = this.get("styles").background,
              weight,
              background;
          if(bg && bg.border)
          {
              weight = bg.border.weight || 0;
          }
          if(this.get("showBackground"))
          {
              background = this.get("background");
              if(w && h)
              {
                  background.set("width", w);
                  background.set("height", h);
              }
          }
          if(this._gridlines)
          {
              this._gridlines.clear();
          }
          if(hgl && hgl instanceof Y.Gridlines)
          {
              hgl.draw();
          }
          if(vgl && vgl instanceof Y.Gridlines)
          {
              vgl.draw();
          }
          this._drawSeries();
      },
  
      /**
       * Draws each series.
       *
       * @method _drawSeries
       * @private
       */
      _drawSeries: function()
      {
          if(this._drawing)
          {
              this._callLater = true;
              return;
          }
          var sc,
              i,
              len,
              graphic = this.get("graphic");
          graphic.set("autoDraw", false);
          this._callLater = false;
          this._drawing = true;
          sc = this.get("seriesCollection");
          i = 0;
          len = sc.length;
          for(; i < len; ++i)
          {
              sc[i].draw();
              if((!sc[i].get("xcoords") || !sc[i].get("ycoords")) && !sc[i] instanceof Y.PieSeries)
              {
                  this._callLater = true;
                  break;
              }
          }
          this._drawing = false;
          if(this._callLater)
          {
              this._drawSeries();
          }
      },  
  
      /**
       * Event handler for series drawingComplete event.
       *
       * @method _drawingCompleteHandler
       * @param {Object} e Event object.
       * @private
       */
      _drawingCompleteHandler: function(e)
      {
          var series = e.currentTarget,
              graphic,
              index = Y.Array.indexOf(this._dispatchers, series);
          if(index > -1)
          {
              this._dispatchers.splice(index, 1);
          }
          if(this._dispatchers.length < 1)
          {
              graphic = this.get("graphic");
              if(!graphic.get("autoDraw"))
              {
                  graphic._redraw();
              }
              this.fire("chartRendered");
          }
      },
  
      /**
       * Gets the default value for the `styles` attribute. Overrides
       * base implementation.
       *
       * @method _getDefaultStyles
       * @return Object
       * @protected
       */
      _getDefaultStyles: function()
      {
          var defs = {
              background: {
                  shape: "rect",
                  fill:{
                      color:"#faf9f2"
                  },
                  border: {
                      color:"#dad8c9",
                      weight: 1
                  }
              }
          };
          return defs;
      }
  }, {
      ATTRS: {
          /**
           * Reference to the chart instance using the graph.
           *
           * @attribute chart
           * @type ChartBase
           * @readOnly
           */
          chart: {},
  
          /**
           * Collection of series. When setting the `seriesCollection` the array can contain a combination of either
           * `CartesianSeries` instances or object literals with properties that will define a series.
           *
           * @attribute seriesCollection
           * @type CartesianSeries
           */
          seriesCollection: {
              getter: function()
              {
                  return this._seriesCollection;
              },
  
              setter: function(val)
              {
                  this._parseSeriesCollection(val);
                  return this._seriesCollection;
              }
          },
         
          /**
           * Indicates whether the `Graph` has a background.
           *
           * @attribute showBackground
           * @type Boolean
           * @default true
           */
          showBackground: {
              value: true
          },
  
          /**
           * Read-only hash lookup for all series on in the `Graph`.
           *
           * @attribute seriesDictionary
           * @type Object
           * @readOnly
           */
          seriesDictionary: {
              readOnly: true,
  
              getter: function()
              {
                  return this._seriesDictionary;
              }
          },
  
          /**
           * Reference to the horizontal `Gridlines` instance.
           *
           * @attribute horizontalGridlines
           * @type Gridlines
           * @default null
           */
          horizontalGridlines: {
              value: null,
  
              setter: function(val)
              {
                  var gl = this.get("horizontalGridlines");
                  if(gl && gl instanceof Y.Gridlines)
                  {
                      gl.remove();
                  }
                  if(val instanceof Y.Gridlines)
                  {
                      gl = val;
                      val.set("graph", this);
                      return val;
                  }
                  else if(val && val.axis)
                  {
                      gl = new Y.Gridlines({direction:"horizontal", axis:val.axis, graph:this, styles:val.styles});
                      return gl;
                  }
              }
          },
          
          /**
           * Reference to the vertical `Gridlines` instance.
           *
           * @attribute verticalGridlines
           * @type Gridlines
           * @default null
           */
          verticalGridlines: {
              value: null,
  
              setter: function(val)
              {
                  var gl = this.get("verticalGridlines");
                  if(gl && gl instanceof Y.Gridlines)
                  {
                      gl.remove();
                  }
                  if(val instanceof Y.Gridlines)
                  {
                      gl = val;
                      val.set("graph", this);
                      return val;
                  }
                  else if(val && val.axis)
                  {
                      gl = new Y.Gridlines({direction:"vertical", axis:val.axis, graph:this, styles:val.styles});
                      return gl;
                  }
              }
          },
  
          /**
           * Reference to graphic instance used for the background.
           *
           * @attribute background
           * @type Graphic
           * @readOnly
           */
          background: {
              getter: function()
              {
                  if(!this._background)
                  {
                      this._backgroundGraphic = new Y.Graphic({render:this.get("contentBox")});
                      Y.one(this._backgroundGraphic.get("node")).setStyle("zIndex", 0); 
                      this._background = this._backgroundGraphic.addShape({type: "rect"});
                  }
                  return this._background;
              }
          },
  
          /**
           * Reference to graphic instance used for gridlines.
           *
           * @attribute gridlines
           * @type Graphic
           * @readOnly
           */
          gridlines: {
              readOnly: true,
  
              getter: function()
              {
                  if(!this._gridlines)
                  {
                      this._gridlinesGraphic = new Y.Graphic({render:this.get("contentBox")});
                      Y.one(this._gridlinesGraphic.get("node")).setStyle("zIndex", 1); 
                      this._gridlines = this._gridlinesGraphic.addShape({type: "path"});
                  }
                  return this._gridlines;
              }
          },
          
          /**
           * Reference to graphic instance used for series.
           *
           * @attribute graphic
           * @type Graphic
           * @readOnly
           */
          graphic: {
              readOnly: true,
  
              getter: function() 
              {
                  if(!this._graphic)
                  {
                      this._graphic = new Y.Graphic({render:this.get("contentBox")});
                      Y.one(this._graphic.get("node")).setStyle("zIndex", 2); 
                      this._graphic.set("autoDraw", false);
                  }
                  return this._graphic;
              }
          }
  
          /**
           * Style properties used for drawing a background. Below are the default values:
           *  <dl>
           *      <dt>background</dt><dd>An object containing the following values:
           *          <dl>
           *              <dt>fill</dt><dd>Defines the style properties for the fill. Contains the following values:
           *                  <dl>
           *                      <dt>color</dt><dd>Color of the fill. The default value is #faf9f2.</dd>
           *                      <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the background fill. The default value is 1.</dd>
           *                  </dl>
           *              </dd>
           *              <dt>border</dt><dd>Defines the style properties for the border. Contains the following values:
           *                  <dl>
           *                      <dt>color</dt><dd>Color of the border. The default value is #dad8c9.</dd>
           *                      <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the background border. The default value is 1.</dd>
           *                      <dt>weight</dt><dd>Number indicating the width of the border. The default value is 1.</dd>
           *                  </dl>
           *              </dd>
           *          </dl>
           *      </dd>
           *  </dl>
           *
           * @attribute styles
           * @type Object
           */
      }
  });
  