
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

var SeriesModel = require("../../model/Series");

var createGraphFromNodeEdge = require("../helper/createGraphFromNodeEdge");

var _format = require("../../util/format");

var encodeHTML = _format.encodeHTML;

var Model = require("../../model/Model");

var _config = require("../../config");

var __DEV__ = _config.__DEV__;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var SankeySeries = SeriesModel.extend({
  type: 'series.sankey',
  layoutInfo: null,
  levelModels: null,

  /**
   * Init a graph data structure from data in option series
   *
   * @param  {Object} option  the object used to config echarts view
   * @return {module:echarts/data/List} storage initial data
   */
  getInitialData: function (option, ecModel) {
    var links = option.edges || option.links;
    var nodes = option.data || option.nodes;
    var levels = option.levels;
    var levelModels = this.levelModels = {};

    for (var i = 0; i < levels.length; i++) {
      if (levels[i].depth != null && levels[i].depth >= 0) {
        levelModels[levels[i].depth] = new Model(levels[i], this, ecModel);
      } else {}
    }

    if (nodes && links) {
      var graph = createGraphFromNodeEdge(nodes, links, this, true, beforeLink);
      return graph.data;
    }

    function beforeLink(nodeData, edgeData) {
      nodeData.wrapMethod('getItemModel', function (model, idx) {
        model.customizeGetParent(function (path) {
          var parentModel = this.parentModel;
          var nodeDepth = parentModel.getData().getItemLayout(idx).depth;
          var levelModel = parentModel.levelModels[nodeDepth];
          return levelModel || this.parentModel;
        });
        return model;
      });
      edgeData.wrapMethod('getItemModel', function (model, idx) {
        model.customizeGetParent(function (path) {
          var parentModel = this.parentModel;
          var edge = parentModel.getGraph().getEdgeByIndex(idx);
          var depth = edge.node1.getLayout().depth;
          var levelModel = parentModel.levelModels[depth];
          return levelModel || this.parentModel;
        });
        return model;
      });
    }
  },
  setNodePosition: function (dataIndex, localPosition) {
    var dataItem = this.option.data[dataIndex];
    dataItem.localX = localPosition[0];
    dataItem.localY = localPosition[1];
  },

  /**
   * Return the graphic data structure
   *
   * @return {module:echarts/data/Graph} graphic data structure
   */
  getGraph: function () {
    return this.getData().graph;
  },

  /**
   * Get edge data of graphic data structure
   *
   * @return {module:echarts/data/List} data structure of list
   */
  getEdgeData: function () {
    return this.getGraph().edgeData;
  },

  /**
   * @override
   */
  formatTooltip: function (dataIndex, multipleSeries, dataType) {
    // dataType === 'node' or empty do not show tooltip by default
    if (dataType === 'edge') {
      var params = this.getDataParams(dataIndex, dataType);
      var rawDataOpt = params.data;
      var html = rawDataOpt.source + ' -- ' + rawDataOpt.target;

      if (params.value) {
        html += ' : ' + params.value;
      }

      return encodeHTML(html);
    } else if (dataType === 'node') {
      var node = this.getGraph().getNodeByIndex(dataIndex);
      var value = node.getLayout().value;
      var name = this.getDataParams(dataIndex, dataType).data.name;

      if (value) {
        var html = name + ' : ' + value;
      }

      return encodeHTML(html);
    }

    return SankeySeries.superCall(this, 'formatTooltip', dataIndex, multipleSeries);
  },
  optionUpdated: function () {
    var option = this.option;

    if (option.focusNodeAdjacency === true) {
      option.focusNodeAdjacency = 'allEdges';
    }
  },
  // Override Series.getDataParams()
  getDataParams: function (dataIndex, dataType) {
    var params = SankeySeries.superCall(this, 'getDataParams', dataIndex, dataType);

    if (params.value == null && dataType === 'node') {
      var node = this.getGraph().getNodeByIndex(dataIndex);
      var nodeValue = node.getLayout().value;
      params.value = nodeValue;
    }

    return params;
  },
  defaultOption: {
    zlevel: 0,
    z: 2,
    coordinateSystem: 'view',
    layout: null,
    // The position of the whole view
    left: '5%',
    top: '5%',
    right: '20%',
    bottom: '5%',
    // Value can be 'vertical'
    orient: 'horizontal',
    // The dx of the node
    nodeWidth: 20,
    // The vertical distance between two nodes
    nodeGap: 8,
    // Control if the node can move or not
    draggable: true,
    // Value can be 'inEdges', 'outEdges', 'allEdges', true (the same as 'allEdges').
    focusNodeAdjacency: false,
    // The number of iterations to change the position of the node
    layoutIterations: 32,
    label: {
      show: true,
      position: 'right',
      color: '#000',
      fontSize: 12
    },
    levels: [],
    // Value can be 'left' or 'right'
    nodeAlign: 'justify',
    itemStyle: {
      borderWidth: 1,
      borderColor: '#333'
    },
    lineStyle: {
      color: '#314656',
      opacity: 0.2,
      curveness: 0.5
    },
    emphasis: {
      label: {
        show: true
      },
      lineStyle: {
        opacity: 0.5
      }
    },
    animationEasing: 'linear',
    animationDuration: 1000
  }
});
var _default = SankeySeries;
module.exports = _default;