/*
 * swx.inv.ChartDataUpdater class containing things to get values for investor portal charts
 * and methods to update the chart
 *
 * $Id: chart_dataUpdater.js,v 1.4 2011/09/15 07:50:27 obo Exp $
 */

dojo.declare("swx.inv.ChartDataUpdater", null, {

/*************************************************************************************************
 * Constructor                                                                                   *
 *************************************************************************************************/
  constructor: function(chart) {  // all arrays and complex objects should be declared here
    // save the size
    this._chart = chart;

    // the information in the infoline
    this._infoLine = null;

    // when to put the next point on the graph (in x minutes)
    this._nextGraphUpdateTime = new Date().getTime() + siteChartConfig.UPDATE_GRAPH_PERIOD;

    // save time by knowing if update of graph is needed
    this._needsUpdate = false;

    /*
     * downloadedData contains info on the downloaded data for each line (id, ...):
     *
     * intradayDomain : the biggest intraday values domain we have (1d, 5d, ...)
     * intradayDate   : the oldest intraday values date we have
     *
     * intermediateDomain : the biggest historical values domain we have (6m, 1y, ...)
     * intermediateDate   : the oldest historical date
     *
     * historicalDomain : the biggest historical values domain we have (6m, 1y, ...)
     * historicalDate   : the oldest historical date
     */
    this.downloadedData = {};
  },

  setInfoLine: function(infoLine) {
    this._infoLine = infoLine;
    this._updateInfoLineValues();

    // set the delay icon correctly and mouseover effect
    var infoDelayIconNode = dojo.byId("chartInfoDelayIcon" + this._chart.key);
    if (infoDelayIconNode) {
      if (infoLine.rt == 0) {
        infoDelayIconNode.src = DELAYED_15_IMG_SRC;
        infoDelayIconNode.title = DELAYED_15_TXT_STR;
      } else {
        infoDelayIconNode.src = DELAYED_0_IMG_SRC;
        infoDelayIconNode.title = DELAYED_0_TXT_STR;
      }
    }
  },

  // this is only for minicharts
  _updateInfoLineValues: function() {

    var monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
    if (this._infoLine) {

      // Modify lastTime so we don't see the seconds
      var lastTime = this._infoLine.lastTime;
      if (lastTime.indexOf(":") != lastTime.lastIndexOf(":"))
        lastTime = lastTime.substring(0, lastTime.lastIndexOf(":"));
      // update the div
      var infoLastTimeNode = dojo.byId("chartInfoLastTime" + this._chart.key);
      if (infoLastTimeNode)
        infoLastTimeNode.innerHTML = lastTime;

      // Modify closingDelta
      if ("-0.00%" == this._infoLine.closingDelta)
        this._infoLine.closingDelta = "0.00%";

      var infoClosingDeltaNode = dojo.byId("chartInfoClosingDelta" + this._chart.key);
      if (infoClosingDeltaNode) {
        infoClosingDeltaNode.innerHTML = this._infoLine.closingDelta;
        var color = "green";
        if (this._infoLine.closingDelta.indexOf("-") != -1) {
          color = "red";
        }
        dojo.style(infoClosingDeltaNode, "color", color);
      }


      // Modify closingPrice
      if (this._infoLine.closingPrice != "") {
        var infoClosingPriceNode = dojo.byId("chartInfoClosingPrice" + this._chart.key);
        if (infoClosingPriceNode)
          infoClosingPriceNode.innerHTML = this._infoLine.closingPrice;
      }


      if (this._infoLine.lastDate) {
        var lastDate = this._infoLine.lastDate;
        var day = lastDate.substring(0,2);
        var month = lastDate.substring(3,5);
        var year = lastDate.substring(8,10);
        // update the div
        var infoLastDateNode = dojo.byId("chartInfoLastDate" + this._chart.key);
        if (infoLastDateNode)
          infoLastDateNode.innerHTML = day + "." + month + "." + year;

        // set the javascript base lastDate
        var jsLastDate = new Date();
        jsLastDate.setHours(0);
        jsLastDate.setMinutes(0);
        jsLastDate.setSeconds(0);
        jsLastDate.setMilliseconds(0);
        jsLastDate.setFullYear(lastDate.substring(6,10));
        jsLastDate.setMonth(month-1);
        jsLastDate.setDate(day);
        this._infoLine.javascriptLastDate = jsLastDate;

        // Set full-format date if it is defined on the page (e.g. STOXX 2010)
        var fullFormatLastDateNode = dojo.byId("fullFormatLastDate" + this._chart.key);
        if (fullFormatLastDateNode)
          fullFormatLastDateNode.innerHTML =
            day + " " + monthNames[jsLastDate.getMonth()] + " " + jsLastDate.getFullYear();

        // do not update the lastDate again
        this._infoLine.lastDate = null;
      }

      if (this._infoLine.movie && !this._chart.runtimeConfig.skipMovie) {
        var quotePlayer = new swx.QuotePlayer(this._infoLine.movie,
                                              dojo.hitch(this, this._autoUpdateFromMovie),
                                              dojo.hitch(this, this._autoGraphUpdate));
        // save the quoteplayer, it will be ticked automatically
        this._chart.quotePlayer = quotePlayer;

        // Do not use this movie again
        this._infoLine.movie = null;
      }
    }
  },

  _autoUpdateFromMovie: function(updateEvent) {

    var updateEventType = updateEvent.columnid;

    // trim down the string and do nothing if it is empty
    // Also remove codes 0xA0 = 160 (comes in IE : non breaking space)
    if (updateEvent.newValue.replace(/^\s+|\s+$/g, '').replace(/\u00A0/g, "") == "")
      return; // nothing to do

    if (updateEventType == "ClosingDelta") {
      this._infoLine.closingDelta = updateEvent.newValue;
    }
    else if (updateEventType == "ClosingPrice") {
      this._infoLine.closingPrice = updateEvent.newValue;
      this._needsUpdate = true;
    }
    else if (updateEventType == "LastTime") {
      this._infoLine.lastTime = updateEvent.newValue;
    }
    else if (updateEventType == "LastDate") {

      // If the date changes we latch it with dateHolder and then reload the chart only once.
      // This avoids repeated reloads with sites (e.g. Eurex) that send many LastDate events.
      if (this._chart.dateHolder != updateEvent.newValue) {
        this._chart.dateHolder = updateEvent.newValue;
        this._needsUpdate = false;
        this._chart.changeId(this._chart.id, true);
      }
    }
  },

  _autoGraphUpdate: function(actualTime) {
    this._updateInfoLineValues();

    // we update the graphic every UPDATE_GRAPH_PERIOD
    if (actualTime > this._nextGraphUpdateTime && this._needsUpdate) {

      this._needsUpdate = false; // reset update info

      var lastTime = this._infoLine.lastTime;

      if (this._chart.useIntradayValues) {
        var hours = lastTime.substring(0,2);
        var mins  = lastTime.substring(3,5);
        var secs  = lastTime.substring(6,8);

        var lastDateTime = new Date(this._infoLine.javascriptLastDate);
        lastDateTime.setHours(hours);
        lastDateTime.setMinutes(mins);
        lastDateTime.setSeconds(secs);

        // check where to put the closingPrice knowing the lastDateTime
        this._updateIntraValues(lastDateTime, this._infoLine.closingPrice);
      }
      // change the value of the last day
      else {
        var domainObject = this._chart.values_domain;
        if (domainObject && domainObject.id && domainObject.id.vals)
          domainObject.id.vals[domainObject.id.vals.length - 1].y = this._infoLine.closingPrice;
      }
      try {
        this._chart.draw(true);  // try only to update the line if possible
      } catch (Exception) {
        console.log("Exception when re-drawing the chart.");
      };

      this._nextGraphUpdateTime = new Date().getTime() + siteChartConfig.UPDATE_GRAPH_PERIOD;
    }
  },

  _updateIntraValues: function(lastDateTime, closingPrice) {
    var i = 0;
    var domainObject = this._chart.values_domain;
    if (domainObject && domainObject.id && domainObject.id.vals) {
      for (i = domainObject.id.vals.length - 1; i > 0; i--) {
        var val = domainObject.id.vals[i];
        if (val.d < lastDateTime) {

          // update the next point (if possible)
          if (i < domainObject.id.vals.length - 2)
            val = domainObject.id.vals[i+1];

          val.y = closingPrice;
          return;
        }
      }
    }
  },

  // Returns the values type according to the specified time range
  getValuesTypeFromDomain: function(timeRange) {
      var index = timeRange.indexOf("d");
      if (index > 0 && timeRange.substring(0,index) <= 10) {
        return swx.inv.Chart.prototype.statics.INTRADAY;
      } else {
        return swx.inv.Chart.prototype.statics.HISTORICAL;
      }
  },

  /*
   * This method will download all data needed to render the actual graph. It returns true if we had to do a ajax request
   */
  calculateAndDownloadDataIfNeeded: function(timeRange, callbackFunction, newDate, forceType) {
    if (timeRange == "ytd") {
      if (this._chart.type == this._chart.statics.ADVANCED) {
        timeRange = "1y"; // don't fool around with ytd, go for 1y in advanced charts
      }
    }

    var arraysToDownloadAndCalculate = this._getArraysToDownloadAndCalculate(timeRange, forceType);

    if (arraysToDownloadAndCalculate.arrayOfQueryStringsToDownload.length == 0) {
      return arraysToDownloadAndCalculate; // nothing to download, everything is in memory
    }

    // If we get here, we need to download some data to render the graph
    var queryString = balancerIdDefinition + "&id="+ this._chart.id +"&type="+ this._chart.type + "&"+
                      arraysToDownloadAndCalculate.arrayOfQueryStringsToDownload.join("&");

    if (newDate) {
      // We are changing dates, force the chart to not use caching
      queryString += "&nd=true";
    }

    if (forceType) {
      queryString += "&fvt=" + forceType;
    }

    // do the downloading here with the queryString
    this._getAjaxValuesAndCall(queryString, callbackFunction);


    return arraysToDownloadAndCalculate;
  },

  downloadZoomedIntradayValues: function(arrayOfQueryStringsToDownload, callbackFunction) {

    var queryString = balancerIdDefinition + "&id="+ this._chart.id +"&type="+ this._chart.type
                    + "&fvt=intraday&"      // We force the server to give us back intraday values
                    + arrayOfQueryStringsToDownload.join("&");

    // do the downloading here with the queryString
    this._getAjaxValuesAndCall(queryString, callbackFunction);
  },

  downloadZoomedIntermediateValues: function(arrayOfQueryStringsToDownload, callbackFunction) {

    var queryString = balancerIdDefinition + "&id="+ this._chart.id +"&type="+ this._chart.type
                    + "&fvt=intermediate&"      // force values type
                    + arrayOfQueryStringsToDownload.join("&");

    // do the downloading here with the queryString
    this._getAjaxValuesAndCall(queryString, callbackFunction);
  },

  /*
   * returns null or an array of queryString items we need to download to show this timerange
   * forceType is used to avoid the 1m dilemna. If historical are needed for 1m, we can force.
   */
  _getArraysToDownloadAndCalculate: function(timeRange, forceType) {
    var retObj = {};
    retObj.arrayOfQueryStringsToDownload = [];
    retObj.arrayOfLineTypesToCalculate = [];

    var valuesType = this.getValuesTypeFromDomain(timeRange);
    if (forceType) valuesType = forceType;

    var showingTechIndicators = false;
    for (var lineType in this._chart.showedLines) {
      if (this._chart.showedLines[lineType] && lineType.indexOf("ti") == 0) {
        showingTechIndicators = true;
        break;
      }
    }

    var localTimeRange = timeRange;
    for (var lineType in this._chart.showedLines) {
      if (lineType == "id" && showingTechIndicators) {
        // For id, we might have to add some time for indicators like SMA
        localTimeRange = getIdTimeRangeDependingOnTechnicalIndicators(timeRange, valuesType, this._chart);
      }
      if (this._chart.showedLines[lineType] &&
          this._hasToDownloadOrCalculateDataForLineType(lineType, localTimeRange, valuesType)) {
        if (lineType.indexOf("ti") == 0 &&
            hasToCalculateDataForTechnicalIndicator(lineType, this._chart)) {
          // calculate data, do not download
          retObj.arrayOfLineTypesToCalculate.push([lineType, localTimeRange, valuesType]);
        } else {
          // set this lineType, etc... to the download queue
          try{
            var qstd = this._getQueryStringOfItemToDownload(lineType, localTimeRange, valuesType);
            retObj.arrayOfQueryStringsToDownload.push(qstd);
          } catch (error){console.error(error);}
        }

      }
    }

    for (var eventType in this._chart.showedEvents) {
      if (this._chart.showedEvents[eventType] &&
          this._hasToDownloadOrCalculateDataForEvent(eventType)) {
        // set this lineType, etc... to the download queue
        var qs2 =  this._getQueryStringOfItemToDownload(eventType, localTimeRange, valuesType, true);
        retObj.arrayOfQueryStringsToDownload.push( qs2 );
      }
    }

    return retObj;
  },

  calculateData : function (arrayToCalculate) {
    var lineType = arrayToCalculate[0];
    var timeRange = arrayToCalculate[1];
    var valuesType = arrayToCalculate[2];

    if (lineType.indexOf("ti") == 0) {
      calculateDataForTechnicalIndicator(lineType, timeRange, valuesType);
      // set it as 'downloaded' = calulated
      this._setDownloadedDomainForLineType(lineType, timeRange, "", valuesType);
    }
  },

  _hasToDownloadOrCalculateDataForLineType: function(lineType, timeRange, valuesType) {

    if (!this.downloadedData[lineType]) return true; // nothing downloaded yet!

    if (valuesType==swx.inv.Chart.prototype.statics.INTRADAY) {
      if (!this.downloadedData[lineType].intradayDomain) return true; // no intraday downloaded yet
      var daysToDownload = timeRange.substring(0, timeRange.indexOf("d"));
      var daysDownloaded = this.downloadedData[lineType].intradayDomain.substring(0,
          this.downloadedData[lineType].intradayDomain.indexOf("d"));
      return (parseInt(daysToDownload) > parseInt(daysDownloaded));

    } else if (valuesType==swx.inv.Chart.prototype.statics.INTERMEDIATE) {
      if (!this.downloadedData[lineType].intermediateDomain) return true; // no intermediate data downloaded yet

      var dateToDownload = domainDatesMap["_"+timeRange];
      var dateDownloaded = domainDatesMap["_"+this.downloadedData[lineType].intermediateDomain];
      return (dateToDownload < dateDownloaded);

    } else {
      if (!this.downloadedData[lineType].historicalDomain) return true; // no historical data downloaded yet

      var dateToDownload = domainDatesMap["_"+timeRange];
      var dateDownloaded = domainDatesMap["_"+this.downloadedData[lineType].historicalDomain];

      return (dateToDownload < dateDownloaded);
    }

  },

  _hasToDownloadOrCalculateDataForEvent: function(eventType) {
    // Take only the first word before "," separator
    var index = eventType.indexOf(",");
    if (index > 0) eventType = eventType.substring(0,index);
    if (this._chart.events[eventType]) {
      return false; // already loaded
    }
    return true;
  },

  _getQueryStringOfItemToDownload: function(lineType, timeRange, valuesType, isEvent) {
    if (isEvent) {
      return "event="+lineType+","+this._chart.showedEvents[lineType]; // showedEvents has language
    }

    // LineType, start and stop are always needed
    var queryString = "line=" +
                      lineType +","+
                      timeRange +","+
                      this._getStopDomain(lineType, valuesType);

    if (lineType == "id") { // Basic line (add width)
      queryString += ","+ this._chart._chartLayout.graphWidth;

      //TODO: here go remaining Eurex PK attributes (expirationDate etc.)
      queryString += "," + (this._chart.runtimeConfig.expirationDate != undefined
          ? this._chart.runtimeConfig.expirationDate : "");
      queryString += "," + (this._chart.runtimeConfig.contractType != undefined
          ? this._chart.runtimeConfig.contractType : "");
      queryString += "," + (this._chart.runtimeConfig.strikePrice != undefined
          ? this._chart.runtimeConfig.strikePrice : "");


    } else if (lineType.substring(0,3) == "idx") { // comparing to another security (add security id)
      queryString += ","+ this._chart.showedLines[lineType];

    } else if (lineType.substring(0,2) == "ti") { // technical indicator (add technical indicator id)
      queryString += ","+ this._chart.showedLines[lineType];

    }
    return queryString;
  },

  // finds the stop domain depending on the already downloaded domain
  _getStopDomain: function(lineType, valuesType) {
    if (! this.downloadedData[lineType]) this.downloadedData[lineType] = {}; // create object

    var domainType = "historicalDomain";
    if (valuesType==swx.inv.Chart.prototype.statics.INTRADAY) {
      domainType = "intradayDomain";
    } else if (valuesType==swx.inv.Chart.prototype.statics.INTERMEDIATE) {
      domainType = "intermediateDomain";
    }

    var alreadyDownloaded = this.downloadedData[lineType][domainType];

    if (alreadyDownloaded) {
      return alreadyDownloaded;
    } else {
      return "";
    }
  },

/*************************************************************************************************
 * getAjaxValues function. Used to init the chart values                                  *
 *************************************************************************************************/
  _getAjaxValuesAndCall: function(queryString, callbackFunction) {

    this._chart.chartDrawer.displayLoading();
    var _url = siteChartConfig.CHART_DATA_URL + "?" + queryString;
    var savedThis = this;

    dojo.xhrGet( {
        url          : _url,
        handleAs     : "json",
        timeout      : 20000,      // in miliseconds
        preventCache : true,

        load: function(response, ioArgs) {
            savedThis._setDownloadedDomainForQueryString(queryString, response);
            savedThis._chart.chartDrawer.hideLoading();
            if (savedThis._chart.type != swx.inv.Chart.prototype.statics.SIMPLE)
              savedThis._chart.chartDrawer.displayInfotxt("Transforming..."); // TODO translate
            // use this settimeout to be sure the browser changed the preview text... to transforming
            setTimeout( function() {savedThis._consumeAjaxValues(response, callbackFunction);}, 0);
        },      // end load

        error: function(response, ioArgs) {
            savedThis._chart.chartDrawer.hideLoading();
            savedThis._chart.chartDrawer.displayInfotxt("Error..."); // TODO translate
            console.log("AJAX Error, HTTP status code: " + ioArgs.xhr.status +"\n"+response);
            return response;
        }       // end error

    } );        // end dojo.xhrGet

  },

  _setDownloadedDomainForQueryString: function(queryString, ajaxResponse) {

    var queryObject = dojo.queryToObject(queryString);

    if (queryObject.line) {
      var lines = [].concat(queryObject.line);
      for (var i in lines) {
        var elements = lines[i].split(",");
        var lineType = elements[0];
        var startDomain = elements[1];
        var stopDomain = elements[2];
        var valuesType = swx.inv.Chart.prototype.statics.HISTORICAL;

        if (ajaxResponse[lineType].historical) {
          valuesType = swx.inv.Chart.prototype.statics.HISTORICAL;
        } else if (ajaxResponse[lineType].intraDay) {
          valuesType = swx.inv.Chart.prototype.statics.INTRADAY;
        } else if (ajaxResponse[lineType].intermediate) {
          valuesType = swx.inv.Chart.prototype.statics.INTERMEDIATE;
        }
        this._setDownloadedDomainForLineType(lineType, startDomain, stopDomain, valuesType);
      }
    }

    if (queryObject.event) {
      var events = [].concat(queryObject.event);
      for (var i in events) {
        var elements = events[i].split(",");
        var eventType = elements[0];

        this._chart.events[eventType] = {}; // put an empty object, might be filled with data
      }
    }
  },

  _setDownloadedDomainForLineType: function(lineType, startDomain, stopDomain, valuesType) {
    if (! this.downloadedData[lineType]) this.downloadedData[lineType] = {};

    if (startDomain.length == 8) {
      // start domain is a date, not a period
      this.downloadedData[lineType].lastRequestStart = startDomain;
      if (stopDomain.length==8) this.downloadedData[lineType].lastRequestStop = stopDomain;
      return;
    }

    // if the request was done with a domain, reset these fields
    this.downloadedData[lineType].lastRequestStart = null;
    this.downloadedData[lineType].lastRequestStop = null;

    if (!valuesType) valuesType = this.getValuesTypeFromDomain(startDomain);
    if (valuesType==swx.inv.Chart.prototype.statics.INTRADAY) {
      this.downloadedData[lineType].intradayDomain = startDomain;
    } else if (valuesType==swx.inv.Chart.prototype.statics.INTERMEDIATE) {
      this.downloadedData[lineType].intermediateDomain = startDomain;
    } else if (valuesType==swx.inv.Chart.prototype.statics.HISTORICAL) {
      this.downloadedData[lineType].historicalDomain = startDomain;
    }
  },

  _findExpectedStartDate : function(lineType) {
    var startDate = null;
    if (this.downloadedData[lineType]) startDate=this.downloadedData[lineType].lastRequestStart;
    if (startDate!=null)startDate = this._getDateFromFqsString(startDate);
    return startDate;
  },

  _findExpectedStopDate : function(lineType) {
    var stopDate=null;
    if (this.downloadedData[lineType]) stopDate=this.downloadedData[lineType].lastRequestStop;
    if (stopDate!=null) stopDate = this._getDateFromFqsString(stopDate);
    return stopDate;
  },

  _getDateFromFqsString : function(fqsDate) {
    var result = new Date();result.setDate(fqsDate.substring(6,8));result.setMonth(fqsDate.substring(4,6)-1);result.setYear(fqsDate.substring(0,4));result.setHours(0);result.setMinutes(0);result.setSeconds(0);result.setMilliseconds(0);return result;
  },

  _consumeAjaxValues: function(ajaxResponse, callbackFunction) {
    if (typeof ajaxResponse == "string") {
      alert("Ajax error");
      return;
    }
    // Do id first,we need it know which dates are ok!
    if (ajaxResponse.id) {
      this._consumeAjaxValuesByLineType("id", ajaxResponse.id);
    }

    for (var lineType in ajaxResponse) {
      if ("id" == lineType) continue; // skip it, already done!
      if ("events" == lineType) continue; // skip events
      var err = this._consumeAjaxValuesByLineType(lineType, ajaxResponse[lineType]);

      if (err) {
        // remove the add on as no more data was found
        _addOn("", lineType);
      }
    }
    // Do events if needed
    if (ajaxResponse.events) {
      this._consumeEvents(ajaxResponse.events);
    }

    if (this._chart.type == this._chart.statics.ADVANCED) {

      var isEmpty = true;
      for (var i in ajaxResponse) { isEmpty = false; break; }

      if (!isEmpty) {
        // Call the callback function, (generally displayes values and redraws the graph)
        callbackFunction.call();
      } else {
        this._chart.draw(true);
      }

      // Now that the data is loaded, connect time range/style/volume buttons to make javascript calls
      if (!this._chart._functionsActive) {
        makeConnects();
        this._chart._functionsActive = true;
      }
    }

  },

  // return true if error
  _consumeAjaxValuesByLineType: function(lineType, ajaxResponse) {

    var somethingFound = false;

    var expectedStart = this._findExpectedStartDate(lineType);
    var expectedStop = this._findExpectedStopDate(lineType);

      // try to fill all that we can
    if (ajaxResponse.intraDay && (ajaxResponse.intraDay.vals || ajaxResponse.intraDay.oldClose)) {
      if (this._chart.values_intra[lineType]) {
        var newVals = [];
        var oldClose = this._chart.values_intra[lineType].oldClose;

        // We already have some intraday values, mix them with the new ones received
        var valsReceived = this._chart.valuesHelper.transformIntraValues( ajaxResponse.intraDay, true, lineType ).vals;
        var firstDateReceived = valsReceived[0].d;
        var index = 0;
        while (index < this._chart.values_intra[lineType].vals.length) {
          if (this._chart.values_intra[lineType].vals[index].d > firstDateReceived) break;
          index++;
        }

        if (index > 0) {
          // Set the new values = values received + old values after values received
          var oldValsBeforeReceived = this._chart.values_intra[lineType].vals.slice(0, index-1);
          newVals = oldValsBeforeReceived;
        } else {
          // the values received go before the old ones
          oldClose = ajaxResponse.intraDay.oldClose;
        }

        var lastDateReceived = valsReceived[valsReceived.length - 1].d;
        index = 0;
        while (index < this._chart.values_intra[lineType].vals.length) {
          if (this._chart.values_intra[lineType].vals[index].d > lastDateReceived) break;
          index++;
        }
        // Set the new values = values received + old values after values received
        var oldValsAfterReceived = this._chart.values_intra[lineType].vals.slice(index, this._chart.values_intra[lineType].vals.length);

        // Put it all together
        newVals = newVals.concat(valsReceived).concat(oldValsAfterReceived);
        this._chart.values_intra[lineType].vals = newVals;
        this._chart.values_intra[lineType].oldClose = oldClose;
      } else {
        this._chart.values_intra[lineType] = this._chart.valuesHelper.transformIntraValues(
          ajaxResponse.intraDay, this._chart.type == this._chart.statics.ADVANCED, lineType
        );
      }
      somethingFound = true;
    }

    if (ajaxResponse.intermediate && (ajaxResponse.intermediate.vals || ajaxResponse.intermediate.oldClose)) {
      if (this._chart.values_inter[lineType]) {
        var newVals = [];
        var oldClose = this._chart.values_inter[lineType].oldClose;

        // We already have some intraday values, mix them with the new ones received
        var valsReceived = this._chart.valuesHelper.transformIntermediateValues( ajaxResponse.intermediate, true, lineType, expectedStart, expectedStop).vals;
        var firstDateReceived = valsReceived[0].d;
        var index = 0;
        while (index < this._chart.values_inter[lineType].vals.length) {
          if (this._chart.values_inter[lineType].vals[index].d > firstDateReceived) break;
          index++;
        }
        if (index > 0) {
          // Set the new values = values received + old values after values received
          var oldValsBeforeReceived = this._chart.values_inter[lineType].vals.slice(0, index-1);
          newVals = oldValsBeforeReceived;
          valsReceived[0].newDay = true; // the first day is a new one
        } else {
          // the values received go before the old ones
          oldClose = ajaxResponse.intermediate.oldClose;
        }

        var lastDateReceived = valsReceived[valsReceived.length - 1].d;
        index = 0;
        while (index < this._chart.values_inter[lineType].vals.length) {
          if (this._chart.values_inter[lineType].vals[index].d > lastDateReceived) break;
          index++;
        }
        // Set the new values = values received + old values after values received
        var oldValsAfterReceived = this._chart.values_inter[lineType].vals.slice(index, this._chart.values_inter[lineType].vals.length);
        if (oldValsAfterReceived[0]) {
          oldValsAfterReceived[0].newDay = true; // in intermediate, first day of old ones is a new day
        }
        // Put it all together
        newVals = newVals.concat(valsReceived).concat(oldValsAfterReceived);
        this._chart.values_inter[lineType].vals = newVals;
        this._chart.values_inter[lineType].oldClose = oldClose;
      } else {
        this._chart.values_inter[lineType] = this._chart.valuesHelper.transformIntermediateValues(ajaxResponse.intermediate, this._chart.type == this._chart.statics.ADVANCED, lineType, expectedStart, expectedStop);
      }
      somethingFound = true;
    }

    if (ajaxResponse.historical && ajaxResponse.historical.vals) {
      if (this._chart.values_days[lineType]) {
        // slice the actual values by removing the first data to avoid volume errors
        // but what if the data is not in ajaxresponse, check it
        var oldVals = this._chart.values_days[lineType].vals;
        var newVals = this._chart.valuesHelper.transformDailyValues( ajaxResponse.historical, true, lineType).vals;

        // we can have one (and no more) value that is in the two arrays
        if (newVals.length>0){
          if (oldVals[0].d==newVals[newVals.length-1].d) oldVals.slice(1, oldVals.length);
          if (newVals[0].d==oldVals[oldVals.length-1].d) newVals.slice(1, newVals.length);
        }

        this._chart.values_days[lineType].vals = newVals.concat(
              oldVals.slice(1, oldVals.length)
          );
      } else {
        this._chart.values_days[lineType] = this._chart.valuesHelper.transformDailyValues(
          ajaxResponse.historical, this._chart.type == this._chart.statics.ADVANCED, lineType
        );
      }
      somethingFound = true;
    }

    if (ajaxResponse.infoLine) {
      this.setInfoLine(ajaxResponse.infoLine);
      somethingFound = true;
    }

    if (!somethingFound)
      return true;

    if (this._chart.type == this._chart.statics.SIMPLE) {
      // set the correct values to be drawn for the simple case
      if (ajaxResponse.intraDay && (ajaxResponse.intraDay.vals || ajaxResponse.intraDay.oldClose)) {
        this._chart.useIntradayValues = true;
        this._chart.values_domain = this._chart.values_intra;
      } else if (ajaxResponse.intermediate && (ajaxResponse.intermediate.vals || ajaxResponse.intermediate.oldClose)) {
        this._chart.useIntradayValues = false;
        this._chart.values_domain = this._chart.values_inter;
      } else {
        this._chart.useIntradayValues = false;
        this._chart.values_domain = this._chart.values_days;
      }
      this._chart.draw();
    }
    return false;
  },

  /*
   * This method will download all events for the chart
   */
  downloadEventsIfNeeded: function(eventId, language, callbackFunction) {
    if (this._chart.events[eventId]) {
      return false; // already loaded
    }

    // If we get here, we need to download some data to render the graph
    var queryString = balancerIdDefinition + "&id="+ this._chart.id +"&type="+ this._chart.type +
                      "&event="+eventId+","+language;

    // do the downloading here with the queryString
    this._getAjaxValuesAndCall(queryString, callbackFunction);

    return true;
  },

  _consumeEvents: function(events) {
    if (events.divs) {
      this._chart.events.divs = this._chart.valuesHelper.transformDivsEvents( events.divs );
      this._chart.showedEvents.divs = true; // should be language but ok, since we already have them
    }
    if (events.news) {
      this._chart.events.news = this._chart.valuesHelper.transformNewsEvents( events.news );
      this._chart.showedEvents.news = true;
    }
    if (events.splits) {
      this._chart.events.splits = this._chart.valuesHelper.transformSplitEvents( events.splits );
      this._chart.showedEvents.splits = true;
    }
    if (events.generalMeetings) {
      this._chart.events.generalMeetings = this._chart.valuesHelper.transformGeneralMeetingsEvents( events.generalMeetings );
      this._chart.showedEvents.generalMeetings = true;
    }
    if (events.managementTransaction) {
      this._chart.events.managementTransaction = this._chart.valuesHelper.transformManagementTransactionEvents( events.managementTransaction );
      this._chart.showedEvents.managementTransaction = true;
    }
    if (events.amalgamations) {
      this._chart.events.amalgamations = this._chart.valuesHelper.transformAmalgamationEvents( events.amalgamations );
      this._chart.showedEvents.amalgamations = true;
    }
    if (events.ccychanges) {
      this._chart.events.ccychanges = this._chart.valuesHelper.transformCcyChangeEvents( events.ccychanges );
      this._chart.showedEvents.ccychanges = true;
    }
  }

});

