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

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

    this._key = key;
    this._chartLayout = chartLayout;
    this._isVML = isVML;

    this._eventDivNode = null;  // the DOM node that will contain all the axis divs
    this._tooltips = [];        // save all the tooltips to erase them

    this.visible = false;

    this._init();
  },

/*************************************************************************************************
 * Static members ( You have to use this.statics.XXXX )                                          *
 *************************************************************************************************/
  statics: {
    CLASS_FOR_EVENT_TYPES : {
      D : "chart_D_Icon",
      C : "chart_C_Icon",
      S : "chart_S_Icon",
      R : "chart_R_Icon",
      N : "chart_N_Icon",
      G : "chart_G_Icon",
      MIX : "chart_M_Icon",
      T : "chart_T_Icon",
      A : "chart_A_Icon",
      H : "chart_H_Icon"
    }
  },

/*************************************************************************************************
 * Private init function. Used to initialise everything                                          *
 *************************************************************************************************/
  _init: function() {
    // add the div that will contain all the divs for the axis
    this._eventDivNode = dojo.byId("chartGraphEvent"+this._key);

    this._rightLimit = this._chartLayout.marginLeft + this._chartLayout.paddingLeft
      + this._chartLayout.graphWidth;
    if (dojo.isIE)
      this._rightLimit += 2;

    this._leftLimit = this._chartLayout.marginLeft - 2;
    if (dojo.isIE)
      this._leftLimit += 2;

    this._leftSpace = this._chartLayout.marginLeft + this._chartLayout.paddingLeft;
    this._topSpace  = this._chartLayout.marginTop  + this._chartLayout.paddingTop;

  },

/*************************************************************************************************
 * Public function.                                                                              *
 *************************************************************************************************/
  show: function() {
    this.visible = true;
  },

/*************************************************************************************************
 * Public function.                                                                              *
 *************************************************************************************************/
  hide: function() {
    if (this.visible) {
      this.visible = false;
      this.clean();
    }
  },

/*************************************************************************************************
 * Public function.                                                                              *
 *************************************************************************************************/
  clean: function() {
    // Clean events :   ( remove Divs )
    while (this._eventDivNode.hasChildNodes())
    {
      this._eventDivNode.removeChild(this._eventDivNode.firstChild);
    }

    for (var i=this._tooltips.length-1; i>=0; i--) {
      this._tooltips[i].destroy();
    }

  },

  drawEvents: function(values, events, showedEvents) {

    // Look if we have something to show in showedEvents
    var allEvents = [];
    for (eventType in showedEvents) {
      if (showedEvents[eventType] && events[eventType].eventArray) {
        for (var i=0; i<events[eventType].eventArray.length; i++) {
          allEvents.push(events[eventType].eventArray[i]);
        }
      }
    }
    if (allEvents.length == 0) return // no events to display, don't bother

    // Sort the events by dates
    allEvents.sort( function(a,b) {
            return a.d - b.d; // sort by dates
    });

    var pixelEvents = [];

    var vals = values.vals;
    var points = values.points;

    var startPoint = values.previousValue.d;
    if (values.valuesType != swx.inv.Chart.prototype.statics.INTRADAY) {
      startPoint = values.vals[0].d; // for historical data, just use the first date (0h00)
    }

    var eventIndex = this._getEventIndexForDate(startPoint, allEvents);
    if (eventIndex >= allEvents.length) return; // no events to display in this range

    var nextEventDate = null;
    if (values.valuesType == swx.inv.Chart.prototype.statics.INTRADAY) {
      nextEventDate = allEvents[eventIndex].d;
    } else {
      nextEventDate = allEvents[eventIndex].histoDate;
    }


    var newsEventsToShow = []; // News events to show array, will be filled.
    var managementTransactionEventsToShow = []; // News events to show array, will be filled.
    var otherEventsToShow = []; // Other events to show array, will be filled.

    var haveWePassedTheFirstRealTrade = false;
    for (var i=0; i<points.length; i++) { // we look ate the points on the chart (pixels)

      if (!haveWePassedTheFirstRealTrade) { // we need the first price of the chart to be able to place the event
        if (!points[i].close) continue;
        haveWePassedTheFirstRealTrade = true;
      }

      while (vals[points[i].close_i].d >= nextEventDate) {
        var event = allEvents[eventIndex];
        if (event.type == "N") {
          newsEventsToShow.push(event);
        }
        else if (event.type == "T") {
          managementTransactionEventsToShow.push(event);
        }
        else {
          otherEventsToShow.push(event);
        }
        eventIndex++;
        if (eventIndex < allEvents.length) {
          if (values.valuesType == swx.inv.Chart.prototype.statics.INTRADAY) {
            nextEventDate = allEvents[eventIndex].d;
          } else {
            nextEventDate = allEvents[eventIndex].histoDate;
          }
        } else {
          break; // no more event in the array, no more to be showed!
        }
      }

      if (newsEventsToShow.length > 0 || otherEventsToShow.length > 0 || managementTransactionEventsToShow.length > 0) {

        // If this point does not have a price (intraday values between days for example, calculate it)
        var price = points[i].close;
        if (!price) {
          // We did not fall on a trading point, calculate the price with last and next trading point
          var leftSteps = i;
          var rightSteps = i;
          while (leftSteps>0 && !price) price = points[--leftSteps].close; //  should always happen because we waited for first point
          price = null;
          while (rightSteps<points.length-1 && !price) price = points[++rightSteps].close;

          // Calculate the fake price
          if (!points[leftSteps].close) {
            // Use right point price since no left step?
            price = points[rightSteps].close;
          } else if (!points[rightSteps].close) {
            // Use left point, we don't have another choice
            price = points[leftSteps].close;
          } else {
            // Calculate the fake price between the left and right real points
            price = points[leftSteps].close + (points[rightSteps].close - points[leftSteps].close) / (rightSteps - leftSteps) * (i - leftSteps);
          }
        }

        var px = Math.floor(this._leftSpace + this._chartLayout.graphWidth * points[i].i / (vals.length - 1));
        var py = Math.floor(this._topSpace + this._chartLayout.graphHeight *
                          (values.gMax - price) / values.gRange);


        var pixelEvent = {};
        pixelEvent.px = px;
        pixelEvent.py = py;
        pixelEvent.newsEvents = newsEventsToShow;
        pixelEvent.managementTransactionEvents = managementTransactionEventsToShow;
        pixelEvent.otherEvents = otherEventsToShow;
        pixelEvent.id = "chartIconID_" + vals[points[i].close_i].d +"_rnd"+(new Date()).getTime();

        pixelEvents.push(pixelEvent);

        newsEventsToShow = []; // reset the eventsToShow arrays;
        otherEventsToShow = [];
        managementTransactionEventsToShow = [];
      }

      if (eventIndex == allEvents.length) {
        break;
      }
    }

    for (var i=0; i<pixelEvents.length; i++) {

      this._drawPixelEvent( pixelEvents[i] );

    }
  },

  _getEventIndexForDate: function(startPoint, eventArray) {
    for (var i=0; i<eventArray.length; i++) {
      if (eventArray[i].d >= startPoint) { // if news 'i' is now or after start point, take it
        return i;
      }
    }
    return eventArray.length; // no news found after startPoint
  },

  _drawPixelEvent: function(pixelEvent) {

    // Using div with class and background image is faster than using img directly
    // because we have many images that are the same
    var divNode = document.createElement("div");
    dojo.addClass(divNode, "iconDiv");
    // save class name to do hover with it (IE bug with 'last class name')
    divNode.imgClass = this._getClassFromPixelEvent(pixelEvent);
    dojo.addClass(divNode, divNode.imgClass);
    divNode.style.width = "14px";
    divNode.style.height = "14px";
    divNode.onmouseover = function() {
            dojo.addClass(this, divNode.imgClass+"_Hover");
            this.style.zIndex = 3;
    };
    divNode.onmouseout = function() {
            dojo.removeClass(this, divNode.imgClass+"_Hover");
            this.style.zIndex = 2;
    };

    if( pixelEvent.newsEvents.length > 0 && pixelEvent.managementTransactionEvents.length > 0) {
      divNode.style.cursor = "pointer"; // link to tooltip or news
      divNode.newsEvents = pixelEvent.newsEvents;
      divNode.managementTransactionEvents = pixelEvent.managementTransactionEvents;
      divNode.onclick = function() {
              chartShowBothNewsAndMT(this);
      }

    }
    else if (pixelEvent.newsEvents.length > 0) {
      divNode.style.cursor = "pointer"; // link to tooltip or news
      divNode.events = pixelEvent.newsEvents; // save events into the div element for chartShowNews function
      divNode.onclick = function() {
              chartShowNews(this);
      }
    }
    else if (pixelEvent.managementTransactionEvents.length > 0) {
      divNode.style.cursor = "pointer";
      divNode.events = pixelEvent.managementTransactionEvents; // save events into the div element for chartShowMT function
      divNode.onclick = function() {
              chartShowMT(this);
      }
    }
    divNode.id = pixelEvent.id;

    var left = pixelEvent.px - 7;
    var top = pixelEvent.py - 6;
    if (dojo.isIE)
      left += 1;

    dojo.style(divNode, "top", addPX(top));
    dojo.style(divNode, "left", addPX(left));
    this._eventDivNode.appendChild(divNode);

    this._tooltips.push(
      new dijit.Tooltip(
        { label: this._createTooltipLabelFromPixelEvent(pixelEvent),
          connectId: [pixelEvent.id],
          id: "tt_"+pixelEvent.id,
          showDelay: 50
        }
      )
    );
  },

  // What king of icon we show depending on the events (news / dividends / ...)
  _getClassFromPixelEvent: function(pixelEvent) {
    var classString = null;

    if (pixelEvent.newsEvents.length > 0) {
      classString = this.statics.CLASS_FOR_EVENT_TYPES.N;
    }

    if (pixelEvent.managementTransactionEvents.length > 0) {
       if (classString != null && classString != newClass) {
        return this.statics.CLASS_FOR_EVENT_TYPES.MIX;
      }
      else {
        classString =  this.statics.CLASS_FOR_EVENT_TYPES.T;
        }
    }

    for (var i=0; i<pixelEvent.otherEvents.length; i++) {
      var event = pixelEvent.otherEvents[i];

      var newClass = this.statics.CLASS_FOR_EVENT_TYPES[event.type];
      if (classString != null && classString != newClass) {
        return this.statics.CLASS_FOR_EVENT_TYPES.MIX;
      } else {
        classString = newClass;
      }
    }
    return classString;
  },

  // Tooltip html depending on the events (news / dividends / ...)
  _createTooltipLabelFromPixelEvent: function(pixelEvent) {

    var retString = "<div class=\"chartEventTooltip\">";
    retString += "<table cellspacing='0' cellpadding='0' border='0'>";

    // For events that are not news (on top)
    if (pixelEvent.otherEvents.length > 0) {
      for (var i=0; i<pixelEvent.otherEvents.length; i++) {
        var event = pixelEvent.otherEvents[i];
        if (i>0) { // not the first event, put a line in between each one
          retString += "<tr><td colspan='2'><img src='/resources/images/trans.gif' class='chartTooltipHeaderSeparator'/></td></tr>";
        }
        retString += "<tr><td colspan='2' class='chartTooltipHeader'>" + CHART_HEADER_FOR_EVENT_TYPES[event.type]
                   + "</td></tr>" + this._getBodyFromEvent(event);
      }
    }

   // For events that are management transaction (on top)
    if (pixelEvent.managementTransactionEvents.length > 0) {

      if (pixelEvent.otherEvents.length > 0 || pixelEvent.newsEvents.length ) {
        if(pixelEvent.otherEvents.length > 0 ){
                retString += "<tr><td colspan='2'><img src='/resources/images/trans.gif' class='chartTooltipHeaderSeparator'/></td></tr>";
        }
        retString += "<tr><td colspan='2' class='chartTooltipHeader'>" + CHART_HEADER_FOR_EVENT_TYPES.T;
      }

      retString += "<tr><td colspan='2'>";
      var firstMT = pixelEvent.managementTransactionEvents[0];
      var MTDate = new Date(firstMT.d);
      var firstDate = chartGetNiceDate(MTDate);

      if (pixelEvent.managementTransactionEvents.length == 1) {
        retString += firstDate + " : " +firstMT.v;
      } else {
        var lastMT = pixelEvent.managementTransactionEvents[pixelEvent.managementTransactionEvents.length - 1];
        newsDate = new Date(lastMT.d);
        var lastDate = chartGetNiceDate(newsDate);
        if (lastDate != firstDate) {
          firstDate += "-" + lastDate;
        }
        retString += firstDate + " : " + pixelEvent.managementTransactionEvents.length + CHART_MULTIPLE_MT_TXT;
      }
      retString += "</td></tr>"

    }


    if (pixelEvent.newsEvents.length > 0) {

      if (pixelEvent.otherEvents.length > 0 || pixelEvent.managementTransactionEvents.length > 0) { // Separate from non news events
        retString += "<tr><td colspan='2'><img src='/resources/images/trans.gif' class='chartTooltipHeaderSeparator'/></td></tr>"
                  +  "<tr><td colspan='2' class='chartTooltipHeader'>" + CHART_HEADER_FOR_EVENT_TYPES.N;
      }

      retString += "<tr><td colspan='2'>";
      var firstNews = pixelEvent.newsEvents[0];
      var newsDate = new Date(firstNews.d);
      var firstDate = chartGetNiceDate(newsDate);

      if (pixelEvent.newsEvents.length == 1) {
        retString += firstDate + " (" + chartGetNiceHourMinutes(newsDate) + ") : " +firstNews.h;
      } else {
        var lastNews = pixelEvent.newsEvents[pixelEvent.newsEvents.length - 1];
        newsDate = new Date(lastNews.d);
        var lastDate = chartGetNiceDate(newsDate);
        if (lastDate != firstDate) {
          firstDate += "-" + lastDate;
        }
        retString += firstDate + " : " + pixelEvent.newsEvents.length + CHART_MULTIPLE_NEWS_TXT;
      }
      retString += "</td></tr>"
    }

    retString += "</table>";
    retString += "</div>";

    return retString;
  },

  _getBodyFromEvent: function(event) {
    if ("D" == event.type) {
      return this._getMainBody(event, CHART_EX_DIV_DATE, CHART_DIVIDEND_AMOUNT);
    } else if ("C" == event.type) {
      return this._getMainBody(event, CHART_EX_DATE, CHART_REDUCTION_AMOUNT);
    } else if ("S" == event.type || "R" == event.type) {
      return this._getMainBody(event, CHART_SPLIT_DATE, CHART_SPLIT_RATIO);
    } else if ("G" == event.type) {
      return this._getMainBody(event, CHART_GENERAL_MEETING_DATE);
    } else if ("A" == event.type) {
      return this._getMainBody(event, CHART_AMALGAMATION_DATE, CHART_AMALGAMATION_RATIO);
    } else if ("H" == event.type) {
      return this._getDualTxtMainBody(event, CHART_CCYCHANGE_DATE, CHART_CCYCHANGE_OLD, CHART_CCYCHANGE_NEW);
    }
    return "ERROR";
  },

  _getMainBody: function(event, dateTxt, valueTxt) {
    var eventDate = new Date(event.d);

    var ret = "<tr><td style='padding-right: 30px;'>"
            + dateTxt + "</td><td align='right'>" + chartGetNiceDate(eventDate) + "</td></tr>";

    if (valueTxt) {
      ret += "<tr><td style='padding-right: 30px;'>" +  valueTxt
           + "</td><td align='right'>" + event.v + "</td></tr>";
    }

    return ret;
  },

  _getDualTxtMainBody: function(event, dateTxt, valueTxtOne, valueTxtTwo) {
    var eventDate = new Date(event.d);

    var ret = "<tr><td style='padding-right: 30px;'>"
            + dateTxt + "</td><td align='right'>" + chartGetNiceDate(eventDate) + "</td></tr>";

    if (valueTxtOne) {
      ret += "<tr><td style='padding-right: 30px;'>" +  valueTxtOne
           + "</td><td align='right'>" + event.v1 + "</td></tr>";
    }

    if (valueTxtTwo) {
      ret += "<tr><td style='padding-right: 30px;'>" +  valueTxtTwo
           + "</td><td align='right'>" + event.v2 + "</td></tr>";
    }

    return ret;
  }

}); // Endof ChartEventDrawer class

