import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { deepEqual, pwdPolicy } from 'amos-tool';
import go from 'amos-gojs';
import classnames from 'classnames';
import { nodeDetailTopoAction } from './../../../services/dynamicRingService';

const goObj = go.GraphObject.make;
const deviceSource = '/src/assets/bizView/dynamicRing';

class TopologyComponent extends Component {

  constructor(props) {
    super(props);
    this.state = {
      detailData: []
    };
    this.diagram = null; //gojs图
    this.customEditor = null;
    this.updateTopologyData = {};
  }

  componentDidMount() {
    this.renderCanvas();
  }

  componentDidUpdate(prevProps, prevState) {
    const { topologyData } = this.props;
    const { nodeData, linkData } = topologyData;
    if (!deepEqual(prevProps.topologyData,this.props.topologyData)) {
      this.diagram.model = new go.GraphLinksModel(nodeData, linkData);
      this.initTop = 0;
      this.initLeft = 0;
    }
  }

  // this function is the Node.dragComputation, to limit the movement of the parts
  stayInFixedArea = (part, pt, gridpt) => {
    let diagram = part.diagram;
    if (diagram === null) {return pt;}
		// compute the document area without padding
    let v = diagram.documentBounds.copy();
    v.subtractMargin(diagram.padding);
		// get the bounds of the part being dragged
    let b = part.actualBounds;
    let loc = part.location;
		// now limit the location appropriately
    let x = Math.max(v.x, Math.min(pt.x, v.right - b.width)) + (loc.x - b.x);
    let y = Math.max(v.y, Math.min(pt.y, v.bottom - b.height)) + (loc.y - b.y);
    return new go.Point(x, y);
  }

  // 选择节点
  nodeSelectionChanged = (node) => {
    this.props.nodeSelectionChanged(node);
  }

  // 设备资源图片
  getDeviceSource = (v) => {
    return `${deviceSource}/${v}.png`;
  }

  // 告警图片
  getWarnPic = (v) => {
    if (v) {
      return '/src/assets/bizView/netTopology/alarm.png';
    }
  }

  // 告警高亮
  warnHighlights = (d,v) => {
    if (d.warnState) {
      this.showWarnHighlights(d, v);
      return d.text;
    }
    return d.text;
  }

  // 获取线颜色
  getLinkColor = (v) => {
    if (v) {
      return '#FF0000';
    }
    return 'rgba(0,255,8,1)';
  }

  showWarnHighlights = (d, v) => {
    const oldDom = this[d.key];
    this.isDrag = true;
    if (oldDom) {
      let pos = this.diagram.transformDocToView(go.Point.parse(d.loc));
      oldDom.style.width = '100px';
      oldDom.style.height = '100px';
      oldDom.style.left = `${pos.x + 18}px`;
      oldDom.style.top  = `${pos.y + 20}px`;
    } else {
      let pos = this.diagram.transformDocToView(go.Point.parse(d.loc));
      let customBox = document.createElement('div');
      customBox.style.left = `${pos.x + 10}px`;
      customBox.style.top  = `${pos.y + 26}px`;
      customBox.style.position = 'absolute';
      customBox.style.zIndex = 1;
      customBox.style.width = '100px';
      customBox.style.height = '100px';
      customBox.style.backgroundPosition = 'center';
      customBox.id = d.key;
      customBox.setAttribute('class','amos-help-tip-pulse-second');
      this.diagram.div.appendChild(customBox);
    }
  };

  // 更新位置信息
  updateTopo = () => {
    const { nodeDataArray } = this.updateTopologyData;
    let pos;
    nodeDataArray.filter(item => item.warnState).map(item => {
      pos = this.diagram.transformDocToView(go.Point.parse(item.loc));
      this[item.key].style.left = `${pos.x + 18}px`;
      this[item.key].style.top  = `${pos.y + 20}px`;
    });
  }

  getNodeDetail = (id) => {
    nodeDetailTopoAction(id).then(data => {
      this.setState({
        detailData: data
      });
    });
  }

  renderDetail = () => {
    const { detailData } = this.state;
    return (<div id="toolTipDIV" className="tooltip-content" style={{ position: 'absolute', zIndex: 1000, display: 'none' }}>
      {detailData.map(item => {
        return (<div key={item.name} className="tooltip-item">
          <div className="item-name">{item.name}: </div>
          <div className="item-value">{item.value}</div>
        </div>);
      })}
    </div>);
  }

  // 提示框
  showToolTip = (obj, diagram, tool) => {
    let toolTipDIV = document.getElementById('toolTipDIV');
    let pt = diagram.lastInput.viewPoint;
    toolTipDIV.style.left = `${pt.x + 12}px`;
    toolTipDIV.style.top = `${pt.y}px`;
    toolTipDIV.style.display = 'block';
    this.getNodeDetail(obj.data.id);
  }

  hideToolTip = (diagram, tool) => {
    let toolTipDIV = document.getElementById('toolTipDIV');
    toolTipDIV.style.display = 'none';
  }

  renderCanvas = () => {
    const { topologyData } = this.props;
    const { nodeData, linkData } = topologyData;
    const myToolTip = goObj(go.HTMLInfo, {
      show: this.showToolTip,
      hide: this.hideToolTip
    });
    this.customEditor = goObj(go.HTMLInfo,{
      show: this.showWarnHighlights
    });
    this.diagram = goObj(go.Diagram, this.refs.goJsDiv, {
      // allowHorizontalScroll: false,  // disallow scrolling or panning
      // allowVerticalScroll: false,
      allowZoom: false,              // disallow zooming
      initialContentAlignment: go.Spot.TopLeft,
      initialPosition: new go.Point(0, 0),
      'undoManager.isEnabled': true, //// enable undo & redo 是否可撤回
      'animationManager.isEnabled': false, // 过渡动画
      'textEditingTool.defaultTextEditor': this.customEditor,
      // fixedBounds: new go.Rect(0, 0, this.refs.goJsDiv.clientWidth, this.refs.goJsDiv.clientHeight),
      ModelChanged: (e) => {     // just for demonstration purposes,
        if (e.isTransactionFinished) {  // show the model data in the page's TextArea
          // console.log(e.model.toJson(), 'model');
          this.updateTopologyData = JSON.parse(e.model.toJson());
          this.props.nodeChange(e);
        }
      },
      SelectionMoved: (e) => {
        setTimeout(()=> {
          this.updateTopo();
        },0);
      },
      ViewportBoundsChanged: () => {
        setTimeout(()=> {
          this.updateTopo();
        },0);
      }
    });


    this.diagram.nodeTemplateMap.add('Circle',
      goObj(go.Node, 'Vertical',
        {
          selectionObjectName: 'ICON',
          locationObjectName: 'ICON'
        },
        new go.Binding('position', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
        goObj(go.Panel, 'Auto',
          goObj(go.Shape, 'Circle', { name: 'ICON',portId: '',
            width: 22, height: 22, strokeWidth: 0,fill: '#009dd9' },
            ),
        ),
      goObj(go.TextBlock,
        { margin: 15,cursor: 'pointer',font: '15px sans-serif' },
        new go.Binding('text', 'text' )),
        {
          selectionAdornmentTemplate:
              goObj(go.Adornment, 'Auto',
                goObj(go.Shape, 'Circle',
                { fill: null, stroke: '#fbfb7b', strokeWidth: 3 }),
                goObj(go.Placeholder)
              )  // end Adornment
        },
    ));

    this.diagram.nodeTemplateMap.add('Picture',
      goObj(go.Node, 'Vertical',
        {
          locationSpot: go.Spot.Center,
          locationObjectName: 'ICON',
          selectionObjectName: 'ICON',
          // dragComputation: this.stayInFixedArea
          selectionChanged: this.nodeSelectionChanged,
          toolTip: myToolTip
        },
        new go.Binding('position', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
        goObj(go.Panel,'Spot',
          goObj(go.Shape, 'Rectangle',
          { fill: 'lightgreen', stroke: null, width: 1, height: 1 }),
          goObj(go.Picture,
            {
              width: 65,
              height: 45,
              alignment: new go.Spot(1, 0, 100 ,0 )
            },
            new go.Binding('source','warnState',(v) => this.getWarnPic(v))
          ),
          goObj(go.TextBlock,
            {
              alignment: new go.Spot(1, 0, 100 ,-1),
              stroke: 'white',
              font: '15px sans-serif'
            },
            new go.Binding('text', 'warnMessage')
          ),
        ),
        goObj(go.Picture,
          {
            margin: 0,
            name: 'ICON',
            width: 55,
            height: 55,
            cursor: 'pointer',
            portId: ''
          },
          new go.Binding('source','source',(v) => this.getDeviceSource(v))
        ),
        goObj(go.TextBlock, '无',
          { margin: 3, stroke: 'rgba(63,63,63,1)', font: '14px sans-serif' },
          new go.Binding('text','', (v,d) => this.warnHighlights(v,d)),
          ),
        {
          selectionAdornmentTemplate:
              goObj(go.Adornment, 'Auto',
                goObj(go.Shape,
                { fill: null, stroke: '#fbfb7b', strokeWidth: 3 }),
                goObj(go.Placeholder)
              )  // end Adornment
        }
      )
    );

    this.diagram.groupTemplate = goObj(go.Group, 'Vertical',
      {
        resizable: true,
        locationObjectName: 'SHAPE',
        resizeObjectName: 'SHAPE',
        selectionObjectName: 'SHAPE'
        // dragComputation: this.stayInFixedArea,
        // selectionChanged: this.nodeSelectionChanged
      },
      new go.Binding('position', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
      goObj(go.TextBlock,         // group title
        {
          width: 100,
          height: 24,
          font: 'Bold 14px Sans-Serif',
          stroke: 'white',
          background: '#1c9ad2',
          margin: 5,
          textAlign: 'center',
          verticalAlignment: go.Spot.Center
        },
      new go.Binding('text')),
      goObj(go.Shape, 'Rectangle',
        {
          name: 'SHAPE',
          parameter1: 14,
          fill: 'rgba(185,185,185,0.2)',
          stroke: 'rgba(28,154,210,1)',
          strokeWidth: 1
        },
        new go.Binding('desiredSize', 'size', go.Size.parse).makeTwoWay(go.Size.stringify),
      )
    );

    this.diagram.linkTemplate =
      goObj(go.Link,
        goObj(go.Shape, { strokeWidth: 3 },
        new go.Binding('stroke', 'warnState', (v) => this.getLinkColor(v))
        )
      );
    this.diagram.model = new go.GraphLinksModel(nodeData, linkData);
  }

  render() {
    const { className,style, topologyData } = this.props;
    const { nodeData = [] } = topologyData || {};
    return (
      <div ref="goJsDiv" style={style} className={classnames('topology-net', className)}>
        {
          nodeData.filter(e => e.warnState).map(e => <div className="amos-help-tip-pulse-second warn-node" ref={node => this[e.key] = node} key={e.key} id={e.key} />)
        }
        {nodeData.length > 0 && this.renderDetail()}
      </div>
    );
  }
}

TopologyComponent.propTypes = {
  className: PropTypes.string,
  style: PropTypes.object,
  topologyData: PropTypes.object,
  nodeChange: PropTypes.func,
  nodeSelectionChanged: PropTypes.func
};

TopologyComponent.defaultProps = {
  style: { height: '100%' },
  topologyData: {
    nodeData: [],
    linkData: []
  }
};

export default TopologyComponent;
