/*
 * $Id: chart_valuesHelper_Advanced.js,v 1.3 2010/08/12 11:39:06 obo Exp $
 */  
dojo.declare("swx.inv.ChartValuesAdvancedHelper", swx.inv.ChartValuesHelper, {
  
/*************************************************************************************************
 * Constructor                                                                                   *
 *************************************************************************************************/
  constructor: function() {  // all arrays and complex objects should be declared here
  
  },
  
/*************************************************************************************************
 * Static members ( You have to use this.statics.XXXX )                                          *
 *************************************************************************************************/
  statics: {
    // to know if we have to regroup points by days or by weeks
    REGROUP_DAYS    : 1,
    REGROUP_WEEKS   : 2,
    REGROUP_POINTS  : 3,
    REGROUP_2POINTS : 4,
    
    PREVIEW_TICKS : 20
    
  },
  
  // update all the values (id, idx1, idx2, ...) with some date ranges
  cutValuesByDates: function(values, startDate, stopDate) {
    var values_domain = {};
    
    // search real date start - this avoids having a diffrent scale for 1y 
    // and followers when the data is not traded for a long time
    var realStart = new Date(values.id.vals[0].d);
    realStart.setHours(0);
    realStart.setMinutes(0);
    realStart.setSeconds(0);
    realStart.setMilliseconds(0);
    if (startDate>realStart) realStart = startDate;
    
    values_domain.id = this.getSubValuesByDates(values.id, false, realStart, stopDate);
    if (values.idx1) values_domain.idx1 = this.getSubValuesByDates(values.idx1, true, realStart, stopDate);
    if (values.idx2) values_domain.idx2 = this.getSubValuesByDates(values.idx2, true, realStart, stopDate);
    
    for (var i=1; i<=10; i++) {
      if (values["ti"+i]) {
        values_domain["ti"+i] = this.getSubValuesByDates(values["ti"+i], true, realStart, stopDate);
      }
    }
    
    return values_domain;
  },
  
  // cuts the values array depending on the start and stop percent (x axis)  
  cutValuesByPercent: function(values, showedLines, startPercent, stopPercent, onlyId) {
    
    // The min and max index of the array values we need to take
    var minIndex = Math.round(values.id.vals.length * startPercent);
    var maxIndex = Math.ceil(values.id.vals.length * stopPercent);
    
    var startDate = values.id.vals[minIndex].date;
    var stopDate  = values.id.vals[maxIndex-1].date;
    
    var values_displayed = {};
    values_displayed.id = this.getSubValuesByDates(values.id, false, startDate, stopDate);
    
    if (!onlyId && showedLines.idx1) {
      values_displayed.idx1 = this.getSubValuesByDates(values.idx1, true, startDate, stopDate);
    } else {
      values_displayed.idx1 = null;
    }
    
    if (!onlyId && showedLines.idx2) {
      values_displayed.idx2 = this.getSubValuesByDates(values.idx2, true, startDate, stopDate);
    } else {
      values_displayed.idx2 = null;
    }
    
    for (var i=1; i<=10; i++) {
      if (!onlyId && showedLines["ti"+i]) {
        values_displayed["ti"+i] = this.getSubValuesByDates(values["ti"+i], true, startDate, stopDate);
      } else {
        values_displayed["ti"+i] = null;
      }
    }
    return values_displayed;
  },
  
  // cuts the values array depending on the start and stop date (x axis)  
  getSubValuesByDates: function(values, onlyClosing, startDate, stopDate) {
    
    // something wrong!
    if (!values) return;
    
    // No dates given, start at the most beginning
    if (!startDate) startDate = new Date(0);
    
    // only 1 parameter, only the start Date given, stop is end of today
    if (!stopDate) {
    	stopDate = new Date();
    	stopDate.setHours(23);
    	stopDate.setMinutes(59);
    	stopDate.setSeconds(59);
    }
    
    var startTime = startDate.getTime();
    var stopTime = stopDate.getTime();
    
    var minIndex = null; // the first index (used for oldClose)
    var yMin = null;     // minimum price
    var iForyMin = null; // index for minimum price
    var yMax = null;     // maximum price
    var iForyMax = null; // index for maximum price
    var vMax = 0;     // maximum volume for the points
    var gMin = null;  // Minimum for the graph (could be that this is not a real trade: between trades)
    var gMax = null;  // Maximum for the graph
    
    var regroupType = this._getRegroupType(values.valuesType, stopTime - startTime);

    var points = [];
    // first point (open price will be corrected once minIndex is known.
    var point = {};
    point.i = 0;  // index of values.vals[i] it goes with
    point.open_i = 0;
    point.days = 0;
    point.vol = 0;
    
    var modulo = 0; // used if more than one point is put together in intraday values
    var newDay = false;
    var newDayPoint = false;
    
    var tmpArray = [];  // keep only the range we want
    
    for (var i=0; i<values.vals.length; i++) {
          
      if (values.vals[i].d < startTime) continue; // do not take this value (before limit)
    
      tmpArray.push( values.vals[i] );  // save every values for date range and retObj.vals
    
      // minIndex is the first index of the values for this startDate 
      if (minIndex == null) {
        minIndex = i;
      }
    
      // For intraday or intermediate values, we need to know if this is a new point for the day
      if ((values.valuesType==swx.inv.Chart.prototype.statics.INTRADAY) && values.vals[i].newDay) newDay = true; 
    
      if (values.vals[i].open) { // this point has a real trade (sometimes in intraday, there are no trades!)
    
        if (newDay && values.valuesType==swx.inv.Chart.prototype.statics.INTRADAY) { 
          // this is a real trading point and it is a new day, 
          // save this info to do some cheating to place the points correctly on the graph
          modulo = 0; // restart
          point.firstTradeOfDay = true;
          newDayPoint = true;
          newDay = false;
        }
    
        if (!point.open) { // first opening price of this point (or regrouped points)
          point.open = values.vals[i].open; 
        }
    
        if (yMin == null || yMin > values.vals[i].min) {
          yMin = values.vals[i].min;
          iForyMin = i-minIndex;
        }
        if (yMax == null || yMax < values.vals[i].max) {
          yMax = values.vals[i].max;
          iForyMax = i-minIndex;
        }
      
        if (!onlyClosing) {
          point.vol += values.vals[i].v;
          if (!point.max) {
            point.max = values.vals[i].max;
          } else {
            point.max = Math.max(point.max, values.vals[i].max);
          }
        
          if (!point.min) {
            point.min = values.vals[i].min;
          } else {
            point.min = Math.min(point.min, values.vals[i].min);
          }
        }
      
        point.close = values.vals[i].y; // closing price, will be erased if another point is in the same regroupement
      }
      
      point.days++;
    
      // if this point is the last one 
      if (i+1 == values.vals.length || values.vals[i+1].d > stopTime) {
        point.i = i - minIndex;              // Cheat: the last point should be all the way on the right
        if (!point.close) point.close = values.vals[i].y; // use this point as closing point (not a real point but used by the graph)
        if (gMin == null || gMin > point.close) {
          gMin = point.close;
        }
        if (gMax == null || gMax < point.close) {
          gMax = point.close;
        }
        point.close_i = i - minIndex;
      
        if (!onlyClosing) {
          if (values.valuesType!=swx.inv.Chart.prototype.statics.INTRADAY) {
            point.vol = point.vol / point.days;  // volume is average volume
          }
          vMax = Math.max(vMax, point.vol);    // save maximum volume
        }
      
        points.push( point );                // save the point
        break;  // stop looping for points
              
      } else if ((regroupType == this.statics.REGROUP_WEEKS && values.vals[i+1].newWeek) 
                    || (regroupType == this.statics.REGROUP_DAYS)
                    || (regroupType == this.statics.REGROUP_POINTS) 
                    || (regroupType == this.statics.REGROUP_2POINTS && 
                          ( modulo%2 == 1 || values.vals[i+1].newDay ) ) ) {  // if next point should be another pixel
              
        point.i = i - minIndex - Math.floor(point.days / 2);
              
        if (!point.close) point.close = values.vals[i].y; // use this point as closing point (not a real point but used by the graph)
              
        if (gMin == null || gMin > point.close) {
          gMin = point.close;
        }
              
        if (gMax == null || gMax < point.close) {
          gMax = point.close;
        }
              
        point.close_i = i - minIndex;
              
        if (!onlyClosing) {
          if (values.valuesType!=swx.inv.Chart.prototype.statics.INTRADAY) {
            point.vol = point.vol / point.days;  // volume is average volume for historical prices
          }
          vMax = Math.max(vMax, point.vol);    // save maximum volume
        }
              
        points.push( point );                // save the point
            
        // new point
        point = {};
        point.open_i = i - minIndex + 1;
        point.days = 0;
        point.vol = 0;
      }
            
      if (newDayPoint) {
        newDayPoint = false;
        point.firstTradeOfDay = true;
        modulo++; // Skip next point, it was to cheat!
      }
      modulo++;
    }

    // Check if we found common points
    if (tmpArray.length == 0) return; // nothing to do
    
    // Cheat: the first point should be all the way on the left
    points[0].i = 0;

    var retObj = {};
    
    if (minIndex > 0) {
      // in some cases this is not the very last value IPO-469
      var last = minIndex-1;
      while (last>=0 && !values.vals[last].y) {
        last--;
      }
      if (last>=0) {
        retObj.oldClose = values.vals[last].y;
        retObj.previousValue = values.vals[last];  // Save the value just before the ones we show (used to know the date before)
      }
    } else { // we do not have the old closing price, say it was 0!
      retObj.oldClose = values.oldClose;
      if (values.previousValue) {
        retObj.previousValue = values.previousValue;
      } else {
        retObj.previousValue = values.vals[0];
      }
    }
    
    retObj.valuesType = values.valuesType;
    retObj.dMin = tmpArray[0].d;
    retObj.dMax = tmpArray[tmpArray.length-1].d;
    retObj.dRange = retObj.dMax - retObj.dMin;
    retObj.yMin = yMin;
    retObj.iForyMin = iForyMin;
    retObj.yMax = yMax;
    retObj.iForyMax = iForyMax;
    retObj.yRange = retObj.yMax - retObj.yMin;
    retObj.vMax = vMax;
    
    if (yMin) {
      retObj.gMin = Math.min(yMin, gMin);
    } else {
      retObj.gMin = gMin;
    }
    if (yMax) {
      retObj.gMax = Math.max(yMax, gMax);
    } else {
      retObj.gMax = gMax;
    }
    // Only one point, we have no range!
    if (retObj.gMin == retObj.gMax) {
      // We add 5% on each side
      retObj.gMin -= 0.05 * retObj.gMin;
      retObj.gMax += 0.05 * retObj.gMin;
    }
    retObj.gRange = retObj.gMax - retObj.gMin;

    retObj.vals = tmpArray;
    retObj.points = points;
    
    if (values.isAddon) {
      retObj.isAddon = values.isAddon; 
    }
    
    return retObj;
  },
  
  _getRegroupType: function(valuesType, milliseconds) {
    var regroup = null;
    if (valuesType==swx.inv.Chart.prototype.statics.INTRADAY) {
      if (milliseconds < 1000 * 60 * 60 * 24 * 3) {
        // every points if under 3 days
        return this.statics.REGROUP_POINTS;
      } else {
        return this.statics.REGROUP_2POINTS;
      }
    } else {
      if (milliseconds < 1000 * 60 * 60 * 24 * 365.25) {
        return this.statics.REGROUP_DAYS;
      } else {
        return this.statics.REGROUP_WEEKS;
      }
    }
  }, 
  
  // function to mix different values together. To have a common min, max and range
  mixValues: function(values, previousDayClosingPrice) {
    
    // find the first index in common for every line shown (some may start at 8h30 some at 9h00)
    var index = this.findStartPrices(values);
    if (index < 0) { // impossible to find a point for the id line!
    	return;
    }
    var id_start_price = values.id.vals[index].y;

    var idx1_factor = 1;
    if (values.idx1) {
      var idx1_start_price = values.idx1.vals[index].y;
      
      if (idx1_start_price) {
        idx1_factor = idx1_start_price / id_start_price;
      
        values.id.gMin = Math.min(values.id.gMin, values.idx1.gMin / idx1_factor);
        values.id.gMax = Math.max(values.id.gMax, values.idx1.gMax / idx1_factor);
      }
    }
    
    var idx2_factor = 1;
    if (values.idx2) {
      var idx2_start_price = values.idx2.vals[index].y;
      if (idx2_start_price) {
        idx2_factor = idx2_start_price / id_start_price;
      
        values.id.gMin = Math.min(values.id.gMin, values.idx2.gMin / idx2_factor);
        values.id.gMax = Math.max(values.id.gMax, values.idx2.gMax / idx2_factor);
      }
    }
    
    for (var i=1; i<= 10; i++) {
      if (values["ti"+i] && !values["ti"+i].isAddon) { // Don't take addon technical indicators
        var ti_start_price = values["ti"+i].vals[index].y;
        if (ti_start_price) {
          values.id.gMin = Math.min(values.id.gMin, values["ti"+i].gMin);
          values.id.gMax = Math.max(values.id.gMax, values["ti"+i].gMax);
        }
      }
    }
    
    // Add oldClose to the gmin, gmax if we will show it!
    if ("1d" == selectedTimeRange && previousDayClosingPrice && !values.idx1 && !values.idx2) {
      values.id.gMin = Math.min(values.id.gMin, previousDayClosingPrice);
      values.id.gMax = Math.max(values.id.gMax, previousDayClosingPrice);
    }
    
    values.id.gRange = values.id.gMax - values.id.gMin;

    // recalibrate everyone based on the id
    if (values.idx1) {
      values.idx1.gMin = values.id.gMin * idx1_factor;
      values.idx1.gMax = values.id.gMax * idx1_factor;
      values.idx1.gRange = values.idx1.gMax - values.idx1.gMin;
    }
    if (values.idx2) {
      values.idx2.gMin = values.id.gMin * idx2_factor;
      values.idx2.gMax = values.id.gMax * idx2_factor;
      values.idx2.gRange = values.idx2.gMax - values.idx2.gMin;
    }
    for (var i=1; i<=10; i++) {
      if (values["ti"+i] && !values["ti"+i].isAddon) { // Don't take addon technical indicators) {
        values["ti"+i].gMin = values.id.gMin;
        values["ti"+i].gMax = values.id.gMax;
        values["ti"+i].gRange = values["ti"+i].gMax - values["ti"+i].gMin;
      }
    }
    
  },
  
  // This function takes all the values and returns the points in pixels!
  getAdvancedGraphValues: function(values, lineOnly, doSmallGraph, previousDayClosingPrice) {
    
    if (!values) return null; // Don't draw anything if no values
    
    var PADDING_LEFT = advancedChart._chartLayout.marginLeft;
    var PADDING_HIGH = advancedChart._chartLayout.marginTop;
    var GRAPH_WIDTH = advancedChart._chartLayout.paddingLeft + 
                      advancedChart._chartLayout.graphWidth + 
                      advancedChart._chartLayout.paddingRight;
    var GRAPH_HEIGHT = advancedChart._chartLayout.paddingTop + 
                       advancedChart._chartLayout.graphHeight + 
                       advancedChart._chartLayout.paddingBottom;
                       
    var leftSpace = advancedChart._chartLayout.marginLeft + advancedChart._chartLayout.paddingLeft;
    var topSpace  = advancedChart._chartLayout.marginTop  + advancedChart._chartLayout.paddingTop;
                       
    var pointIndex = 0;
    // Array we will return;
    var pixelPoints = [];
    var pixelLine = [];
    var pixelSmallGraphLine = [];
    
    for (var i=0; i<values.vals.length; i++) {
      if (values.points[pointIndex].i == i) {  // draw this point
        var point = values.points[pointIndex];
        if (point.close != null) {
          pixelPoint = {};
          pixelPoint.px = Math.floor(leftSpace + this._chart._chartLayout.graphWidth * (point.i) / (values.vals.length - 1));
          pixelPoint.close = Math.floor(topSpace + this._chart._chartLayout.graphHeight * (1 - (point.close - values.gMin) / values.gRange));
        
          if (!lineOnly) {
            pixelPoint.open = Math.floor(topSpace + this._chart._chartLayout.graphHeight * (1 - (point.open - values.gMin) / values.gRange));
            pixelPoint.min = Math.floor(topSpace + this._chart._chartLayout.graphHeight * (1 - (point.min - values.gMin) / values.gRange));
            pixelPoint.max = Math.floor(topSpace + this._chart._chartLayout.graphHeight * (1 - (point.max - values.gMin) / values.gRange));
            pixelPoint.vol = Math.floor(swx.inv.ChartAddonDrawer.prototype.statics.PADDING_VOL_HIGH + 
                                        swx.inv.ChartAddonDrawer.prototype.statics.GRAPH_VOL_HEIGHT * (1 - (point.vol) / values.vMax));
            pixelPoints.push(pixelPoint);
          }

          pixelLine.push(pixelPoint.px);
          pixelLine.push(pixelPoint.close);
        
          if (doSmallGraph) {
            pixelSmallGraphLine.push(pixelPoint.px);
            pixelSmallGraphLine.push(Math.floor(topSpace + this._chart._chartLayout.graphHeight * (1 - (point.close - values.yMin) / values.yRange)));
          }
          
        }
        
        pointIndex++; // wait for next point;
      }
    }
    
    var pixelOldClose = null;
    if (previousDayClosingPrice) {
      pixelOldClose = Math.floor(this._chart._chartLayout.marginTop + this._chart._chartLayout.paddingTop 
                      + this._chart._chartLayout.graphHeight * ( 1 - (previousDayClosingPrice - values.gMin) / values.gRange));
    }
    
    
    return { points: pixelPoints, line: pixelLine, smallGraphLine: pixelSmallGraphLine, oldClosePy: pixelOldClose};
  },
  
  // This function takes all the values and returns an array for the graphic preview (in pixels)!
  getPreviewGraphValues: function(values) {
  	
    var leftSpace = advancedChart._chartLayout.marginLeft + advancedChart._chartLayout.paddingLeft;
    var topSpace  = advancedChart._chartLayout.marginTop  + advancedChart._chartLayout.paddingTop;
    
    // Array we will return;
    var retArray = [];
    
    // How many points in which we search a max and a min
    var maxPartX = Math.ceil(values.vals.length / this.statics.PREVIEW_TICKS);
    var iStep = Math.ceil(maxPartX / 3); // search in each third of the part (otherwise it's too slow)
    var part = 1;
    var part_min = {};
    var part_max = {};
    
    // first point
    var startIndex = 0;
    for (;startIndex<values.vals.length; startIndex++) {
      if (values.vals[startIndex].y) break;
    }
    if (!values.vals[startIndex]) return retArray; // return empty array!
    
    
    var actX = Math.floor(leftSpace + this._chart._chartLayout.graphWidth * (startIndex) / (values.vals.length-1));
    var actY = Math.floor(topSpace + this._chart._chartLayout.graphHeight * (1 - (values.vals[startIndex].y - values.gMin) / values.gRange));
    retArray.push(actX);
    retArray.push(actY);
    
    for (var i=1; i<values.vals.length; i+=iStep) {
      if (i > part * maxPartX) {
        part++;
        if (part_min.px < part_max.px) {
          retArray.push(part_min.px);
          retArray.push(part_min.py);
          retArray.push(part_max.px);
          retArray.push(part_max.py);
        } else {
          retArray.push(part_max.px);
          retArray.push(part_max.py);
          retArray.push(part_min.px);
          retArray.push(part_min.py);
        }
        part_min = {};
        part_max = {};
      }
      if (part_min.py == null || part_min.py > actY) {part_min.py = actY; part_min.px = actX;}
      if (part_max.py == null || part_max.py < actY) {part_max.py = actY; part_max.px = actX;}
      
      if (!values.vals[i].y) continue; // skip empty zones (between days)
      
      actX = Math.floor(leftSpace + this._chart._chartLayout.graphWidth * (i) / (values.vals.length-1));
      actY = Math.floor(topSpace + this._chart._chartLayout.graphHeight * (1 - (values.vals[i].y - values.gMin) / values.gRange));
    }
    if (part_min.py == null || part_min.py > actY) {part_min.py = actY; part_min.px = actX;}
    if (part_max.py == null || part_max.py < actY) {part_max.py = actY; part_max.px = actX;}
    if (part_min.px < part_max.px) {
      retArray.push(part_min.px);
      retArray.push(part_min.py);
      retArray.push(part_max.px);
      retArray.push(part_max.py);
    } else {
      retArray.push(part_max.px);
      retArray.push(part_max.py);
      retArray.push(part_min.px);
      retArray.push(part_min.py);
    }
    // last one:
    retArray.push( actX );
    retArray.push( actY );
    return retArray;
  },
  
  getAdvancedAddonGraphValues: function(techId, values) {
    var retObj = {};
    
    retObj.isAddon = true;
    
    var gMin = null;
    var gMax = null;
    var graphRange = null;
    if (techId.indexOf("RSI") == 0) {
      // RSI addon
      gMin = swx.inv.ChartAddonDrawer.prototype.statics.RSI_GRAPH_MIN;
      gMax = swx.inv.ChartAddonDrawer.prototype.statics.RSI_GRAPH_MAX;
      graphRange = gMax - gMin;
    } else if (techId.indexOf("MOM") == 0) {
      // MOM addon  > Make 100 always visible
      gMin = Math.min(values.gMin, 100);
      gMax = Math.max(values.gMax, 100);
      graphRange = gMax - gMin;
    } else {
      gMin = values.gMin;
      gMax = values.gMax;
      graphRange = values.gRange;
    }
    retObj.techId = techId;
    retObj.gMin = gMin;
    retObj.gMax = gMax;
    
    var leftSpace = advancedChart._chartLayout.marginLeft + advancedChart._chartLayout.paddingLeft;
    var topSpace  = swx.inv.ChartAddonDrawer.prototype.statics.PADDING_TI_HIGH;
    var addonHeight = swx.inv.ChartAddonDrawer.prototype.statics.GRAPH_TI_HEIGHT;
    
    var pointIndex = 0;
    // Array of points we will return;
    var pixelLine = [];
    
    for (var i=0; i<values.vals.length; i++) {
      if (values.points[pointIndex].i == i) {  // draw this point
        var point = values.points[pointIndex];
        if (point.close != null) {
          pixelPoint = {};
          pixelPoint.px = Math.floor(leftSpace + this._chart._chartLayout.graphWidth * (point.i) / (values.vals.length - 1));
          pixelPoint.close = Math.floor(topSpace + addonHeight * (1 - (point.close - gMin) / graphRange));
        
          pixelLine.push(pixelPoint.px);
          pixelLine.push(pixelPoint.close);
        }
        
        pointIndex++; // wait for next point;
      }
    }
    retObj.line = pixelLine;
    
    return retObj;
  },

  findStartPrices: function(values) {

    var index_id = -1;
    var found = false;
    if (values.idx1 && values.idx2) {

      while (++index_id < values.id.vals.length && values.id.vals[index_id].y == null ||
             index_id < values.idx1.vals.length && values.idx1.vals[index_id].y == null ||
             index_id < values.idx2.vals.length && values.idx2.vals[index_id].y == null) {
      }
      
      if (index_id < values.id.vals.length && 
          index_id < values.idx1.vals.length &&
          index_id < values.idx2.vals.length) found = true;
            
    } else if (values.idx1) {

      while (++index_id < values.id.vals.length && values.id.vals[index_id].y == null ||
             index_id < values.idx1.vals.length && values.idx1.vals[index_id].y == null) {
      }
      
      if (index_id < values.id.vals.length && 
          index_id < values.idx1.vals.length) found = true;
      
    } else if (values.idx2) {

      while (++index_id < values.id.vals.length && values.id.vals[index_id].y == null ||
             index_id < values.idx2.vals.length && values.idx2.vals[index_id].y == null) {
      }
      
      if (index_id < values.id.vals.length && 
          index_id < values.idx2.vals.length) found = true;
      
    } else {

      while (++index_id < values.id.vals.length && values.id.vals[index_id].y == null) {
      }
      
      if (index_id < values.id.vals.length) found = true;
      
    }
    
    if (found) {
      return index_id;
    } else {
      return -1;
    }
  },
  
  transformDivsEvents: function(divs) {
    var retObj = {};
    retObj.eventArray = [];

    // Dividends
    var dividends = divs.d;
    if (dividends) {
      for (var i=0; i<dividends.length; i++) {
        var dividend = dividends[i];
        var event = {};
        event.type = "D";
        event.d = dividend.d;
        event.histoDate = this._getHistoDate(event.d);
        event.v = dividend.c +" "+ dividend.v.toFixed(2);

        retObj.eventArray.push(event);
      }
    }

    // Capital repayments
    var repayements = divs.r;
    if (repayements) {
      for (var i=0; i<repayements.length; i++) {
        var repayement = repayements[i];
        var event = {};
        event.type = "C";
        event.d = repayement.d;
        event.histoDate = this._getHistoDate(event.d);
        event.v = repayement.c +" "+ repayement.v.toFixed(2);
        
        retObj.eventArray.push(event);
      }
    }
    // Sort the array by dates
    retObj.eventArray.sort( function(a,b) {
            return a.d - b.d; // sort by dates
    });
    return retObj;
  },
    
  transformSplitEvents: function(splits) {
    var retObj = {};
    retObj.eventArray = [];
    
    // Splits
    var realSplits = splits.s;
    if (realSplits) {
      for (var i=0; i<realSplits.length; i++) {
        var split = realSplits[i];
        var event = {};
        event.type = "S";
        event.d = split.d;
        event.histoDate = this._getHistoDate(event.d);
        event.v = split.v;
        retObj.eventArray.push(event);
      }
    }
    
    // Reverse splits
    var reverseSplits = splits.r;
    if (reverseSplits) {
      for (var i=0; i<reverseSplits.length; i++) {
        var split = reverseSplits[i];
        var event = {};
        event.type = "R";
        event.d = split.d;
        event.histoDate = this._getHistoDate(event.d);
        event.v = split.v;
        retObj.eventArray.push(event);
      }
    }
    
    // Sort the array by dates
    retObj.eventArray.sort( function(a,b) {
            return a.d - b.d; // sort by dates
    });
    return retObj;
    
  },
  
  transformNewsEvents: function(news) {
    var retObj = {};
    retObj.areNews = true; // we have to know this because news can occur anytime (capital events are day values)
    
    retObj.eventArray = [];
    for (var i=0; i<news.length; i++) {
      var event = news[i]; // keep the whole news object from ajax
      event.histoDate = this._getHistoDate(event.d);
      event.type = "N";
      
      retObj.eventArray.push(event); // push each event into an array (the order comes from the server side)
    }
    // Sort the array by dates
    retObj.eventArray.sort( function(a,b) {
            return a.d - b.d; // sort by dates
    });
    
    return retObj;
  },
  
  transformGeneralMeetingsEvents: function(generalMeetings) {
    var retObj = {};
    retObj.eventArray = [];
    
    // General meetings
    for (var i=0; i<generalMeetings.length; i++) {
      var generalMeetingDate = generalMeetings[i];
      var event = {};
      event.type = "G";
      event.d = generalMeetingDate;
      event.histoDate = this._getHistoDate(event.d);
      
      retObj.eventArray.push(event); // push each event into an array (the order comes from the server side)
    }
    
    return retObj;
  },
  
    transformManagementTransactionEvents: function(managementTransaction) {
    var retObj = {};
    retObj.eventArray = [];
    
    // Transaction Management
    for (var i=0; i<managementTransaction.length; i++) {
      var managementTransactionTime = Number(managementTransaction[i].Time);
      var event = {};
      event.type = "T";
      event.fullObject = managementTransaction[i];
      event.d = managementTransactionTime;
      event.v = managementTransaction[i].Transaction + " (" + managementTransaction[i].Price + ")";
      event.histoDate = this._getHistoDate(event.d);
      
      retObj.eventArray.push(event); 
    }
    
    return retObj;
  },
  
  transformAmalgamationEvents: function(amalgamationsContainer) {
    var retObj = {};
    retObj.eventArray = [];

    // Amalgamations
    var amalgamations = amalgamationsContainer.a;
    if (amalgamations) {
      for (var i=0; i<amalgamations.length; i++) {
        var amalgamation = amalgamations[i];
        var event = {};
        event.type = "A";
        event.d = amalgamation.d;
        event.histoDate = this._getHistoDate(event.d);
        event.v = amalgamation.v;

        retObj.eventArray.push(event);
      }
    }

    // Sort the array by dates
    retObj.eventArray.sort( function(a,b) {
            return a.d - b.d; // sort by dates
    });
    return retObj;
  },

  transformCcyChangeEvents: function(ccyChangesContainer) {
    var retObj = {};
    retObj.eventArray = [];

    // Currency Changes
    var ccychanges = ccyChangesContainer.c;
    if (ccychanges) {
      for (var i=0; i<ccychanges.length; i++) {
        var ccychange = ccychanges[i];
        var event = {};
        event.type = "H";
        event.d = ccychange.d;
        event.histoDate = this._getHistoDate(event.d);
        event.v1 = ccychange.v1;
        event.v2 = ccychange.v2;

        retObj.eventArray.push(event);
      }
    }

    // Sort the array by dates
    retObj.eventArray.sort( function(a,b) {
            return a.d - b.d; // sort by dates
    });
    return retObj;
  },

  _getHistoDate: function(dateTime) {
      var eventDateTime = new Date(dateTime);
      eventDateTime.setHours(0);
      eventDateTime.setMinutes(0);
      eventDateTime.setSeconds(0);
      eventDateTime.setMilliseconds(0);
      return eventDateTime.getTime();
  }
    
});

  

