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/selfsupport';

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 '#00FFFF';
  };

  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);
  };

  //设置椭圆宽度
  setEllipseWidth = v => {
    let width = v === '西安中心' ? 500 : 300;
    return width;
  };

  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(
      'Shape',
      goObj(
        go.Node,
        'Vertical',
        new go.Binding('position', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
        goObj(
          go.Shape,
          'Rectangle',
          {
            name: 'SHAPE',
            fill: '#5BE3FF',
            stroke: '#5BE3FF',
            strokeWidth: 1,
            width: 500,
            height: 24
          },
          new go.Binding('width', 'text', v => this.setEllipseWidth(v))
        ),
        goObj(go.TextBlock, '无', { textAlign: 'left', margin: -25, stroke: '#fff', font: 'bold 18px Microsoft YaHei UI' }, new go.Binding('text'))
      )
    );

    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.Panel,
        'Auto',
        { stretch: go.GraphObject.Horizontal },
        // 定义画板的样式
        goObj(go.Shape, 'Rectangle', {
          fill: '#E5E5E5',
          stroke: '#49ADDA', // node边框
          strokeWidth: 1,

        }),


        goObj(
          go.TextBlock, // group title
          {
            height: 24,
            font: 'Bold 14px Sans-Serif',
            textAlign: 'left',
            margin: new go.Margin(0, 0, 0, 12),
            verticalAlignment: go.Spot.Center,
            alignment: go.Spot.TopLeft
          },
          new go.Binding('text')
         //new go.Binding('text', (v) => this.setFontText(v))
        )
      ),
      goObj(
        go.Shape,
        'Rectangle',
        {
          name: 'SHAPE',
          parameter1: 14,
          fill: 'rgba(255,255,255,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;
