import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { utils } from 'amos-tool';
import { Modal, Input, message, PureRenderMixin, AmosAlert } from 'amos-framework';
import { tools, stopEvent, graph, handlers, domTools } from 'amos-jsplumb';
import { PubSub } from 'ray-eventpool';
import { browserHistory } from 'amos-react-router';
import { initStageView, saveStageView, addViewTrigger, delViewNode, addViewNode, addViewLink } from './../../../services/ruleDesignService';
import StageHeader from './header/StageHeader';
import RuleScene from './RuleScenePlumb';
import EleCatalogPanel from './extra/EleCatalogPanel';
import {
  ELE_ADD_TOPIC,
  ELE_DEL_TOPIC, ELE_CATALOG_TOPIC,
  ELE_ENTRY_TOPIC, locale, isStatusDragLink, transferDropData, isDragEle,typeValue } from './modelConf/stageConf';
import { commonAddNode, addTrigerAndAction, commonAddNodeAndConn, getEleNode } from './addNode';


const extraSize = {
  top: 90,
  left: 230
};

/**
 * 舞台
 *
 * @class RuleStage 
 * @extends {Component}
 */
class RuleStage extends Component {
  static propTypes = {
    objId: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    needReloadStage: PropTypes.bool,
    toggleReloadStage: PropTypes.func,
    onStatusConnLink: PropTypes.func
  };

  constructor(props) {
    super(props);
    this.state = {
      connections: [],
      nodes: [],
      zoom: 1,
      visible: false,
      catalogVisible: false,
      eleType: '',
      statusId: '',
      position: {
        left: 0,
        top: 0
      },
      ruleSubObj: {},
      needDestroy: false,
      catalogOptions: {},
      subGraphVisible: false,
      subGraphOptions: {}
    };
  }

  componentWillMount() {
  }
  onAddConnection = (connId, sourceId, targetId) => {
      const newConn = {
        id: connId,
        sourceId,
        targetId
      };
      this.setState({
        connections: [...this.state.connections, newConn]
      });
  }
  onRemoveConnection = (connectionId, sourceId) => {
      this.setState({
        connections: this.state.connections.filter(connection => connection.id !== connectionId)
      });
  }
  onZoom = (zoom) => {
      this.setState({
        zoom
      });
    }  
  changeZoom = (zoomIn) => {
    let zoom = this.props.zoom;
    if (zoomIn) {
      zoom += 0.2;
    } else {
      zoom -= 0.2;
    }
    this.props.onZoom(zoom);
  }
  onRemoveNode = (nodeId) => {
    const { nodes } = this.state;
    const newNodes = nodes.filter(n => n.id !== nodeId);
    this.setState({
      nodes: newNodes
    });
}

  componentDidMount() {
    this.initData();

    // 添加元素
    this.pubsub_eleadd = PubSub.subscribe(ELE_ADD_TOPIC.eleAdd, (topic, { eleType, statusId, position }) => {
      if (!utils.isEmpty(eleType)){
        this.setState({
          visible: true,
          eleType,
          statusId,
          position
        });
      }
    });

    // 删除元素
    this.pubsub_eledel = PubSub.subscribe(ELE_DEL_TOPIC.eleDel, (topic, { eleId }) => {
      if (!utils.isEmpty(eleId)){
        // 删除
        delViewNode(eleId).then(data => {
          message.success('删除成功！');
          // 刷新
          this.setState({
            needDestroy: true
          }, () => this.reloadPlumb());
        },
        err => {
          message.danger(err || '删除失败');
        });
      }
    });

    // 子操作
    this.pubsub_catalog = PubSub.subscribe(ELE_CATALOG_TOPIC.NORMAL, (topic, { catalogOptions, catalogVisible }) => {
      if (!utils.isEmpty(catalogOptions)){
        this.setState({
          catalogVisible,
          catalogOptions
        });
      }
    });

    // 子视图
    this.pubsub_subgraph = PubSub.subscribe(ELE_ENTRY_TOPIC.eleEntry, (topic, { subGraphOptions, subGraphVisible }) => {
      if (!utils.isEmpty(subGraphOptions)){
        this.setState({
          subGraphOptions,
          subGraphVisible
        });
      }
    });
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.needReloadStage){
      // 设置已reload
      this.props.toggleReloadStage(false);
      this.setState({
        needDestroy: true
      }, () => this.reloadPlumb());
    }
  }

  shouldComponentUpdate(nextProps, nextState) {
    return PureRenderMixin.shouldComponentUpdate.apply(this, nextProps, nextState);
  }

  componentWillUnmount() {
    PubSub.unsubscribe(this.pubsub_eleadd);
    PubSub.unsubscribe(this.pubsub_eledel);
    PubSub.unsubscribe(this.pubsub_catalog);
    PubSub.unsubscribe(this.pubsub_subgraph);
  }

  onChange = ({ nodes, connections }) => {
    this.setState({ nodes, connections });
  }

  onSceneCreated = (plumbInstance) => {
    this.plumbInstance = plumbInstance;
  }

  onSceneClick = (e) => {
    const catalogOptions = {
      eleType: '',
      sourceId: '',
      position: { left: 0, top: 0 },
      catalogs: []
    };
    this.setState({
      catalogVisible: false,
      catalogOptions
    });
  }

  onSubGraphClosed = () => {
    this.setState({
      subGraphVisible: false,
      subGraphOptions: {}
    });
  }

  /**
   * 双击连线
   */
  onConnectionDbClick = (conn, e) => {
    // 判断仅是 状态之间的连线
    console.log(conn, e, conn.getData());
    let { source, target } = conn;
    if (isStatusDragLink(target)) {
      this.props.onStatusConnLink(source, target, conn.getData());
    }
  }

  initData = () => {
    const { objId } = this.props;
    if (objId){
      initStageView(objId).then(data => {
        this.setState({
          connections: data.linkVoList,
          nodes: data.nodeVoList,
          ruleSubObj: data.rule
        });
      });
    }
  }

  reloadPlumb = () => {
    const { objId } = this.props;
    if (objId){
      initStageView(objId).then(data => {
        this.setState({
          needDestroy: false,
          connections: data.linkVoList,
          nodes: data.nodeVoList
        });
      });
    }
  }

  filterNodes = (nodes) => {
    const oldNodes = this.state.nodes;
    const newNodes = nodes.filter(n => !oldNodes.find(on => on.id === n.id));
    return [
      ...oldNodes,
      ...newNodes
    ];
  }

  filterConns = (conns) => {
    const oldConns = this.state.connections;
    const newConns = conns.filter(
      c =>
      !oldConns.find(
        oc => oc.sourceId === c.sourceId && oc.targetId === c.targetId
      )
    );

    return [
      ...oldConns,
      ...newConns
    ];
  }

  saveStage = (objId) => {
    const { nodes, connections } = this.state;
    // 获取布局
    graph.completePosition(this.plumbInstance, nodes);
    saveStageView({
      id: objId,
      nodeVoList: nodes,
      linkVoList: connections
    }).then(
      data => {
        message.success('保存成功！');
      },
      err => {
        message.danger(err || '保存失败!');
      }
    );
  }

  exitStage = () => {
    browserHistory.goBack();
  }

  addNode = ({ labelValue }) => {
    const { nodes, connections, position, statusId } = this.state;

    const result = addTrigerAndAction({ labelValue, position, statusId });
    // 持久化
    addViewTrigger(result);

    this.setState({
      nodes: [ ...nodes, ...result.node ],
      connections: [ ...connections, ...result.conn ],
      visible: false,
      eleType: '',
      statusId: ''
    });
  }

  cancel = (modal) => {
    this.setState({
      visible: false
    });
  }

  /**
   * 拖拽结束事件
   * @memberOf RuleStage
   */
  handleDrop = (event) => {
    stopEvent(event);
    const { left: x, top: y } = domTools.getNodeOffset(event);
    const data = event.dataTransfer.getData('FlowChartNode');
    const ruleNodeId = data.split('-')[1];
    const label = data.split('-')[2];
    const { nodeType, sourceId } = transferDropData(data.split('-')[0]);
    if (isDragEle(nodeType)) {
      if (sourceId){
        this.doDropAddNodeAndConn({ nodeType, x, y, sourceId });
      } else {
        this.doDropAddNode({ nodeType, x, y,ruleNodeId,label });
      }
    } else {
      const target = event.target;
      if (target.className !== 'plumb-charts'){
        const ele = getEleNode(target);
        if (ele){
          this.doDropAddConn(sourceId, ele.id);
        }
      }
    }
  }

  doDropAddNode = ({ nodeType: eleType, x, y,ruleNodeId,label }) => {
    const { nodes } = this.state;
    const { objId } = this.props;
    const labelValue = label || '节点';
    const position = {
      left: x,
      top: y
    };
    const result = commonAddNode({ eleType, labelValue, position,ruleNodeId });
    // 持久化
    Object.assign(result,{ ruleId: objId });
    addViewNode(result);
    this.setState({
      catalogVisible: false,
      nodes: [ ...nodes, result ]
    });
  }

  doDropAddNodeAndConn = ({ nodeType: eleType, x, y, sourceId }) => {
    const { nodes, connections } = this.state;
    const { objId } = this.props;
    const labelValue = locale[eleType] || '节点';
    const position = {
      left: x,
      top: y
    };
    const result = commonAddNodeAndConn({ eleType, labelValue, position, sourceId });
    // 持久化
    addViewNode({
      ...result.node,
      subObjId: objId,
      sourceId
    });

    this.setState({
      catalogVisible: false,
      nodes: [ ...nodes, result.node ],
      connections: [ ...connections, result.conn ]
    });
  }

  doDropAddConn = (sourceId, targetId) => {
    const { objId } = this.props;

    // 持久化
    addViewLink({
      oid: objId,
      sourceId,
      targetId
    }).then(data => {
      // 刷新
      this.setState({
        needDestroy: true,
        catalogVisible: false
      }, () => this.reloadPlumb());
    },
    err => {
      message.danger(err || '添加链路失败！');
    });
  }

  /**
   * 准备添加元素,用于填写必要字段
   */
  doPreAddEle = ({ type, x, y }) => {
    if (!utils.isEmpty(type)){
      this.setState({
        visible: true,
        eleType: type,
        position: {
          left: x,
          top: y
        }
      });
    }
  }
  //检查是否已经建立过连接
  beforeDrop = (info) => {
  info.targetId = info.dropEndpoint.elementId; 
  if (info.targetId === info.sourceId) {
    return;
  } else {
    let connections = this.jspInstance.getConnections({ source: info.sourceId, target: info.targetId });
    if (!connections.length === 0) {
      return;
    } 
  }
}
updateGraph = (args = {}) => {
  this.setState({
    ...args
  });
}

updateGraphWithDestroy = (args = {}) => {
  this.setState({
    destroy: true
  }, () => {
    this.setState({
      ...args
    });
  });
}
onDropHandler = (id, left, top) => {
  const { nodes } = this.state;
  nodes.map(node => {
    if (node.id === id) {
      let location = { left:left ,top:top};
      node.config.style = location;
    }
  });
  this.setState({
    nodes:nodes
  });
}
  render() {

    const {
      zoom,
      nodes,
      connections,
      catalogOptions,
      catalogVisible,
      ruleSubObj,
      needDestroy
    } = this.state;

    const dataSource = {
      nodes,
      connections
    };  
    const nodeProps = {
      onDrop: this.onDropHandler
    }    
    const { objId,...restProps } = this.props;
    const newRestProps = tools.omit(restProps, [
      'updateGraph', 'updateGraphWithDestroy'
    ]);    
    const eventListeners = {
      dblclick: this.onConnectionDbClick,
      connection: handlers.onConnectionEventHandler,
      beforeDrop: this.beforeDrop
    };

    return (
      <div
        className="rule-stage"
      >
        <StageHeader
          saveStage={this.saveStage}
          exitStage={this.exitStage}
          ruleSubObj={ruleSubObj}
          objId={objId}
        />
        <RuleScene
          handleDrop={this.handleDrop}
          onAddConnection={this.onAddConnection}
          onRemoveConnection={this.onRemoveConnection}   
          onRemoveNode ={this.onRemoveNode}      
          dataSource={dataSource}   
          newRestProps ={newRestProps}
          onPlumbChange={this.onChange}
          nodeProps = {nodeProps}
          onSceneCreated={this.onSceneCreated}
          onPlumbClick={this.onSceneClick}
          eventListeners={eventListeners}
          zoom={zoom}
          onZoom={this.onZoom}
          destroy={needDestroy}
        />
        <EleCatalogPanel
          visible={catalogVisible}
          {...catalogOptions}
        />

      </div>
    );
  }
}

export default RuleStage;
