/*
 * $Id: chart_addonDrawer_Advanced.js,v 1.2 2011/08/09 13:04:55 obo Exp $
 */
dojo.declare("swx.inv.ChartAddonDrawer", null, {

/*************************************************************************************************
 * Constructor                                                                                   *
 *************************************************************************************************/
  constructor: function(surface_offset, chartLayout, isVML) {  // all arrays and complex objects should be declared here

    this._chartLayout = chartLayout;

    this._isVML = isVML;

    this._axisTechIndiDivNode = dojo.byId("techIndicatorAxis");

    var label_height = dojo.isIE ? 12 : 13;
    var label_left = dojo.isIE ? 3 : 5;
    if (dojo.isFF == 2)
      label_left = 4;

    var techIndiHolderNode = dojo.byId("techIndicator_holder");
    this.techIndiSurface = dojox.gfx.createSurface(techIndiHolderNode, chartLayout.surfaceWidth, this.statics.SURFACE_TI_HEIGHT);
    dojo.style(techIndiHolderNode, "left", addPX(0 - surface_offset.x));
    dojo.style(techIndiHolderNode, "top", addPX(label_height - surface_offset.y));
    dojo.style("techIndicator_id", "left", addPX(0 - surface_offset.x + label_left));
    dojo.style("techIndicatorAxis", "top", addPX(label_height - surface_offset.y));

    this._techIndiBorder = this.techIndiSurface.createRect(
                     {
                       x: this._chartLayout.marginLeft,
                       y: 0.5,
                       width: this._chartLayout.paddingLeft + this._chartLayout.graphWidth
                            + this._chartLayout.paddingRight,
                       height: this.statics.PADDING_TI_HIGH + this.statics.GRAPH_TI_HEIGHT + this.statics.PADDING_TI_LOW
                     }
                   ).setStroke(swx.inv.ChartDrawer.prototype.statics.BORDER_COLOR);
    this._techIndiBorder.getNode().setAttribute("shape-rendering","crispEdges"); // not needed because we draw at 0.5 px

    var volumeHolderNode = dojo.byId("volume_holder");
    if (volumeHolderNode) { // maybe no volume exists (for indices for example)
      this._axisVolDivNode = dojo.byId("volumeAxis");

      this.volumeSurface = dojox.gfx.createSurface(volumeHolderNode, chartLayout.surfaceWidth, this.statics.SURFACE_VOL_HEIGHT);
      dojo.style(volumeHolderNode, "left", addPX(0 - surface_offset.x));
      dojo.style(volumeHolderNode, "top", addPX(label_height - surface_offset.y));
      dojo.style("volume_id", "left", addPX(0 - surface_offset.x + label_left));
      dojo.style("volumeAxis", "top", addPX(label_height - surface_offset.y));

      this._volumeBorder = this.volumeSurface.createRect(
        {
          x: this._chartLayout.marginLeft,
          y: 0.5,
          width: this._chartLayout.paddingLeft + this._chartLayout.graphWidth
            + this._chartLayout.paddingRight,
          height: this.statics.PADDING_VOL_HIGH + this.statics.GRAPH_VOL_HEIGHT
            + this.statics.PADDING_VOL_LOW
        }
      ).setStroke(swx.inv.ChartDrawer.prototype.statics.BORDER_COLOR);
      this._volumeBorder.getNode().setAttribute("shape-rendering","crispEdges"); // not needed because we draw at 0.5 px
    }

    this.isVolumeVisible = false;

  },

/*************************************************************************************************
 * Static members ( You have to use this.statics.XXXX )                                          *
 *************************************************************************************************/
  statics: {
    GRAPH_VOL_HEIGHT   : 55,
    SURFACE_VOL_HEIGHT : 62,
    PADDING_VOL_HIGH   : 5,
    PADDING_VOL_LOW    : 0,

    GRAPH_TI_HEIGHT    : 56,
    SURFACE_TI_HEIGHT  : 62,
    PADDING_TI_HIGH    : 2,
    PADDING_TI_LOW     : 2,

    RSI_GRAPH_MIN      : 0,
    RSI_GRAPH_MAX      : 100,
    RSI_GRID_TICKS     : [10, 30, 50, 70, 90],

    VOLUME_DOWN_COLOR  : "red",
    VOLUME_UP_COLOR    : "green"

  },

/*************************************************************************************************
 * Public function.                                                                              *
 *************************************************************************************************/
  showVolume: function() {
    var node = dojo.byId("volume");
    if (node) {
      this.isVolumeVisible = true;
      dojo.style(node, "display", "");
    }
  },

/*************************************************************************************************
 * Public function.                                                                              *
 *************************************************************************************************/
  hideVolume: function() {
    this.isVolumeVisible = false;
    var node = dojo.byId("volume");
    if (node) {
      dojo.style(node, "display", "none");
    }
  },

/*************************************************************************************************
 * Public function.                                                                              *
 *************************************************************************************************/
  showTechnicalIndicator: function() {
    this.isTechnicalIndicatorVisible = true;
    dojo.style("techIndicator", "display", "");
  },

/*************************************************************************************************
 * Public function.                                                                              *
 *************************************************************************************************/
  hideTechnicalIndicator: function() {
    this.isTechnicalIndicatorVisible = false;
    dojo.style("techIndicator", "display", "none");
  },

/*************************************************************************************************
 * Public function.                                                                              *
 *************************************************************************************************/
  clean: function() {
    if (this._volumeShape) this.volumeSurface.remove(this._volumeShape);
    if (this._volumeGrid) {
      this.volumeSurface.remove(this._volumeGrid);
      // Clean axis : remove Divs
      while (this._axisVolDivNode.hasChildNodes())
      {
        this._axisVolDivNode.removeChild(this._axisVolDivNode.firstChild);
      }
    }

    if (this._techIndiShape) this.techIndiSurface.remove(this._techIndiShape);
    if (this._techIndiGrid) {
      this.techIndiSurface.remove(this._techIndiGrid);
      // Clean axis : remove Divs
      while (this._axisTechIndiDivNode.hasChildNodes())
      {
        this._axisTechIndiDivNode.removeChild(this._axisTechIndiDivNode.firstChild);
      }
    }

  },

  drawVolume: function(graph_values, values_displayed) {
    if (!this.isVolumeVisible) return; // don't draw if not visible

    this._volumeGrid = this._drawGrid(this._axisVolDivNode, this.volumeSurface, 0,
                                      values_displayed.vMax, this.statics.PADDING_VOL_HIGH,
                                      this.statics.GRAPH_VOL_HEIGHT, "VOL");
    this._volumeShape = this._drawVolume( graph_values, this.techIndiSurface, values_displayed.oldClose );

    this._volumeBorder.moveToFront();
  },

  drawTechnicalIndicator: function(graph_values) {
    if (!this.isTechnicalIndicatorVisible) this.showTechnicalIndicator();

    this._techIndiGrid = this._drawGrid(this._axisTechIndiDivNode, this.techIndiSurface,
                                        graph_values.gMin,
                                        graph_values.gMax, this.statics.PADDING_TI_HIGH,
                                        this.statics.GRAPH_TI_HEIGHT, graph_values.techId);
    this._techIndiShape = this._drawAddon( graph_values, this.techIndiSurface );

  },

/*************************************************************************************************
 * 'Private' function                                                                            *
 * This function draws the volume graphic in the 'volumeSurface' surface                         *
 *************************************************************************************************/
  _drawVolume: function(graphValues, oldClose) {

    var g = this.volumeSurface.createGroup();

    var graph_vol_bottom = this.statics.PADDING_VOL_HIGH + this.statics.GRAPH_VOL_HEIGHT;
    var path1 = new StringBuffer();
    var path2 = new StringBuffer();
    if (this._isVML) { // create a vml path myself!
      for (var i=0; i<graphValues.length; i++) {
        if (graphValues[i].close != null) {
          if (graphValues[i].close <= oldClose) {  // going up (down pixelwise!)
            path1.append(" m").append(graphValues[i].px).append(",").append(graph_vol_bottom).append(" l")
                 .append(graphValues[i].px).append(",").append(graphValues[i].vol);
          } else {
            path2.append(" m").append(graphValues[i].px).append(",").append(graph_vol_bottom).append(" l")
                 .append(graphValues[i].px).append(",").append(graphValues[i].vol);
          }
          oldClose = graphValues[i].close;
        }
      }
      var p1 = g.createPath().setStroke({color: this.statics.VOLUME_UP_COLOR});
      swx.inv.ChartDrawer.prototype.statics.setVmlPath(p1, path1.toString());
      var p2 = g.createPath().setStroke({color: this.statics.VOLUME_DOWN_COLOR});
      swx.inv.ChartDrawer.prototype.statics.setVmlPath(p2, path2.toString());
    } else {
      for (var i=0; i<graphValues.length; i++) {
        if (graphValues[i].close != null) {
          if (graphValues[i].close <= oldClose) {  // going up (down pixelwise!)
            path1.append(" M").append(graphValues[i].px).append(" ").append(graph_vol_bottom).append(" V")
                 .append(graphValues[i].vol);
          } else {
            path2.append(" M").append(graphValues[i].px).append(" ").append(graph_vol_bottom).append(" V")
                 .append(graphValues[i].vol);
          }
          oldClose = graphValues[i].close;
        }
      }
      g.createPath(path1.toString()).setStroke({color: this.statics.VOLUME_UP_COLOR});
      g.createPath(path2.toString()).setStroke({color: this.statics.VOLUME_DOWN_COLOR});
    }

    // remove anti-alias for this!
    g.getNode().setAttribute("shape-rendering","crispEdges");

    return g;
  },

/*************************************************************************************************
 * 'Private' function                                                                            *
 * This function draws the volume graphic in the surface                                  *
 *************************************************************************************************/
  _drawAddon: function(graphValues, surface) {

    var g = surface.createGroup();

    var col = swx.inv.ChartDrawer.prototype.statics.TI1_COLOR;
    advancedChart.chartDrawer._graphDrawer._myCreatePolyline(graphValues.line, g)
                                          .setStroke({color: col, width: 1});

    return g;
  },

/*************************************************************************************************
 * 'Private' function                                                                            *
 * This function draws the volume grid in the 'volumeSurface' surface                                     *
 *************************************************************************************************/
  _drawGrid: function(axisDivNode, surface, vMin, vMax, graphPaddingHigh, graphHeight, techId) {
    var g = surface.createGroup();

    var graph_right = this._chartLayout.marginLeft + this._chartLayout.paddingLeft +
                      this._chartLayout.graphWidth + this._chartLayout.paddingRight +
                      this._chartLayout.marginRight;

    var path = new StringBuffer();
    var fatPath = new StringBuffer();

    var gridTicks = this._getGridTicksForAddon(techId, vMin, vMax);

    for (var j=0; j<gridTicks.ticks.length; j++) {
      var tick = gridTicks.ticks[j];

      var py = Math.floor(graphPaddingHigh + graphHeight - (graphHeight * (tick-vMin) / (vMax-vMin)));

      if (tick == gridTicks.fatTick) {
        if (this._isVML) {
          fatPath.append(" m").append(this._chartLayout.marginTop).append(",").append(py).append(" l").append(graph_right).append(",").append(py);
        } else {
          fatPath.append(" M").append(this._chartLayout.marginTop).append(" ").append(py).append(" h").append(graph_right-this._chartLayout.marginLeft);
        }
      } else {
        if (tick>0 || techId != "VOL") {  // no grid on the bottom of volume
          if (this._isVML) {
            path.append(" m").append(this._chartLayout.marginLeft).append(",").append(py).append(" l").append(graph_right).append(",").append(py);
          } else {
            path.append(" M").append(this._chartLayout.marginLeft).append(" ").append(py).append(" h").append(graph_right-this._chartLayout.marginLeft);
          }
        }
      }

      var txt = null;
      if (techId == "VOL") {
        if (tick >= 1000000) {
          txt = chartGetNiceNumber(tick / 1000000) + " M";
        } else if (tick >= 1000) {
          txt = chartGetNiceNumber(tick / 1000) + " k";
        }
      }
      if (txt == null) {
        txt = chartGetNiceNumber(tick, gridTicks.fixed);
      }
      if (techId.indexOf("RSI") == 0) { // add % for RSI
        txt += "%";
      }
      var divNode = document.createElement("div");
      dojo.addClass(divNode, "axisDiv");
      var leftSpace = 5;
      if (dojo.isIE)
        leftSpace += 1;
      dojo.style(divNode, "left", addPX(graph_right + leftSpace));
      divNode.appendChild(document.createTextNode(txt));
      axisDivNode.appendChild(divNode);
      var heightOfNode = dojo.coords(divNode).h;
      dojo.style(divNode, "top", addPX(py - heightOfNode/2)); // FF is 1px too low and IE is 1px too high :(
    }

    var gridColor ;
    var darkGridColor ;

    if (this._chartLayout.chartStyles && this._chartLayout.chartStyles.GRID_COLOR)
      gridColor =  this._chartLayout.chartStyles.GRID_COLOR;
    else
      gridColor = swx.inv.ChartDrawer.prototype.statics.GRID_COLOR;

    if (this._chartLayout.chartStyles && this._chartLayout.chartStyles.DARK_GRID_COLOR)
      darkGridColor =  this._chartLayout.chartStyles.DARK_GRID_COLOR;
    else
      darkGridColor = swx.inv.ChartDrawer.prototype.statics.DARK_GRID_COLOR;

    if (this._isVML) {
      var p = g.createPath().setStroke({color: gridColor});
      swx.inv.ChartDrawer.prototype.statics.setVmlPath(p, path.toString());
    } else {
      g.createPath(path.toString()).setStroke({color: gridColor});
    }

    if ("" != fatPath.toString()) {
      if (this._isVML) {
        var p = g.createPath().setStroke({color: darkGridColor});
        swx.inv.ChartDrawer.prototype.statics.setVmlPath(p, fatPath.toString());
      } else {
        g.createPath(fatPath.toString()).setStroke({color: darkGridColor});
      }
    }

    // remove antialias for this!
    g.getNode().setAttribute("shape-rendering","crispEdges");

    return g;
  },


/*************************************************************************************************
 * 'Private' function                                                                            *
 * This function returns a specific grid if the technical indicator needs one,                   *
 * otherwise returns null                                                                        *
 *************************************************************************************************/
  _getGridTicksForAddon: function(techId, vMin, vMax) {
    if (techId.indexOf("RSI") == 0) {
      return { ticks: this.statics.RSI_GRID_TICKS, fixed: 0, fatTick: 50 };

    } else if (techId.indexOf("MOM") == 0) {
      // Make a grid having 100 always in it
      var gridTicks = [];

      var unit_fixed = swx.inv.ChartAxisGridDrawer.prototype.statics.getUnitTickForRange(vMax-vMin, 5);
      var unit = unit_fixed[0];
      fixed = unit_fixed[1];

      for (var i=100-5*unit; i<=vMax; i+= unit) {
        if (i<vMin) continue; // go to next tick.
        gridTicks.push(i);
      }

      return { ticks: gridTicks, fixed: fixed, fatTick: 100 };

    } else {
      var gridTicks = []; // create one from 0 to vMax

      var unit_fixed = swx.inv.ChartAxisGridDrawer.prototype.statics.getUnitTickForRange(vMax-vMin, 5);
      var unit = unit_fixed[0];
      fixed = unit_fixed[1];

      for (var i=vMin; i<=vMax; i+= unit) {
        gridTicks.push(i);
      }

      return { ticks: gridTicks, fixed: fixed };
    }

  }

}); // End of VolumeAddon class

