/**
 * eventRiver 布局算法
 * @module echarts/layout/eventRiver
 * @author clmtulip  (车丽美, clmtulip@gmail.com)
 */
module.exports = function (require) {
  function eventRiverLayout(series, intervalX, area) {
    var space = 4;
    var scale = intervalX;

    function importanceSort(a, b) {
      var x = a.importance;
      var y = b.importance;
      return x > y ? -1 : x < y ? 1 : 0;
    }
    /**
     * 查询数组中元素的index
     */


    function indexOf(array, value) {
      if (array.indexOf) {
        return array.indexOf(value);
      }

      for (var i = 0, len = array.length; i < len; i++) {
        if (array[i] === value) {
          return i;
        }
      }

      return -1;
    } // step 0. calculate event importance and sort descending


    for (var i = 0; i < series.length; i++) {
      for (var j = 0; j < series[i].data.length; j++) {
        if (series[i].data[j].weight == null) {
          series[i].data[j].weight = 1;
        }

        var importance = 0;

        for (var k = 0; k < series[i].data[j].evolution.length; k++) {
          importance += series[i].data[j].evolution[k].valueScale;
        }

        series[i].data[j].importance = importance * series[i].data[j].weight;
      }

      series[i].data.sort(importanceSort);
    } // step 1. 计算每个group的重要值importance，并按递减顺序排序


    for (var i = 0; i < series.length; i++) {
      if (series[i].weight == null) {
        series[i].weight = 1;
      }

      var importance = 0;

      for (var j = 0; j < series[i].data.length; j++) {
        importance += series[i].data[j].weight;
      }

      series[i].importance = importance * series[i].weight;
    } // 根据importance对groups进行递减排序


    series.sort(importanceSort); // step 3. set bubble positions in group order, then in event order
    // 找到包含所有事件的时间段，即最小和最大时间点

    var minTime = Number.MAX_VALUE;
    var maxTime = 0;

    for (var i = 0; i < series.length; i++) {
      for (var j = 0; j < series[i].data.length; j++) {
        for (var k = 0; k < series[i].data[j].evolution.length; k++) {
          var time = series[i].data[j].evolution[k].timeScale;
          minTime = Math.min(minTime, time);
          maxTime = Math.max(maxTime, time);
        }
      }
    } //console.log('minTime: ' + minTime);
    //console.log('maxTime: ' + maxTime);
    // 时间范围 即 x轴显示的起始范围


    minTime = ~~minTime;
    maxTime = ~~maxTime; // 气泡之间的间隙

    var flagForOffset = function () {
      var length = maxTime - minTime + 1 + ~~intervalX;

      if (length <= 0) {
        return [0];
      }

      var result = [];

      while (length--) {
        result.push(0);
      }

      return result;
    }();

    var flagForPos = flagForOffset.slice(0);
    var bubbleData = [];
    var totalMaxy = 0;
    var totalOffset = 0;

    for (var i = 0; i < series.length; i++) {
      for (var j = 0; j < series[i].data.length; j++) {
        var e = series[i].data[j];
        e.time = [];
        e.value = [];
        var tmp;
        var maxy = 0;

        for (var k = 0; k < series[i].data[j].evolution.length; k++) {
          tmp = series[i].data[j].evolution[k];
          e.time.push(tmp.timeScale);
          e.value.push(tmp.valueScale);
          maxy = Math.max(maxy, tmp.valueScale);
        } // 边界计算


        bubbleBound(e, intervalX, minTime); // 得到可以放置的位置

        e.y = findLocation(flagForPos, e, function (e, index) {
          return e.ypx[index];
        }); // 得到偏移量

        e._offset = findLocation(flagForOffset, e, function () {
          return space;
        });
        totalMaxy = Math.max(totalMaxy, e.y + maxy);
        totalOffset = Math.max(totalOffset, e._offset);
        bubbleData.push(e);
      }
    } // 映射到显示区域内


    scaleY(bubbleData, area, totalMaxy, totalOffset);
  }
  /**
   * 映射到显示区域内
   */


  function scaleY(bubbleData, area, maxY, offset) {
    var height = area.height;
    var offsetScale = offset / height > 0.5 ? 0.5 : 1;
    var yBase = area.y;
    var yScale = (area.height - offset) / maxY;

    for (var i = 0, length = bubbleData.length; i < length; i++) {
      var e = bubbleData[i];
      e.y = yBase + yScale * e.y + e._offset * offsetScale;
      delete e.time;
      delete e.value;
      delete e.xpx;
      delete e.ypx;
      delete e._offset; // 修改值域范围

      var evolutionList = e.evolution;

      for (var k = 0, klen = evolutionList.length; k < klen; k++) {
        evolutionList[k].valueScale *= yScale;
      }
    }
  }
  /**
   * 得到两点式的方程函数 y = k*x + b
   * @param {number} x0 起点横坐标
   * @param {number} y0 起点纵坐标
   * @param {number} x1 终点横坐标
   * @param {number} y1 终点纵坐标
   * @returns {Function} 输入为横坐标 返回纵坐标s
   */


  function line(x0, y0, x1, y1) {
    // 横坐标相同,应该抛出错误
    if (x0 === x1) {
      throw new Error('x0 is equal with x1!!!');
    } // 纵坐标相同


    if (y0 === y1) {
      return function () {
        return y0;
      };
    }

    var k = (y0 - y1) / (x0 - x1);
    var b = (y1 * x0 - y0 * x1) / (x0 - x1);
    return function (x) {
      return k * x + b;
    };
  }
  /**
   * 计算当前气泡的值经过的边界
   * @param {object} e 气泡的值
   * @param {array} e.time 时间范围
   * @param {array} e.value 值域范围
   * @param {number} intervalX 气泡尾巴长度
   */


  function bubbleBound(e, intervalX, minX) {
    var space = ~~intervalX;
    var length = e.time.length;
    e.xpx = [];
    e.ypx = [];
    var i = 0;
    var x0 = 0;
    var x1 = 0;
    var y0 = 0;
    var y1 = 0;
    var newline;

    for (; i < length; i++) {
      x0 = ~~e.time[i];
      y0 = e.value[i] / 2;

      if (i === length - 1) {
        // i = length - 1  ~  += intervalX
        x1 = x0 + space;
        y1 = 0;
      } else {
        x1 = ~~e.time[i + 1];
        y1 = e.value[i + 1] / 2;
      } // to line


      newline = line(x0, y0, x1, y1); //

      for (var x = x0; x < x1; x++) {
        e.xpx.push(x - minX);
        e.ypx.push(newline(x));
      }
    }

    e.xpx.push(x1 - minX);
    e.ypx.push(y1);
  }

  function findLocation(flags, e, yvalue) {
    var pos = 0;
    var length = e.xpx.length;
    var i = 0;
    var y;

    for (; i < length; i++) {
      y = yvalue(e, i);
      pos = Math.max(pos, y + flags[e.xpx[i]]);
    } // reset flags


    for (i = 0; i < length; i++) {
      y = yvalue(e, i);
      flags[e.xpx[i]] = pos + y;
    }

    return pos;
  }

  return eventRiverLayout;
}(require);