'use strict';

import React from 'react';
import PropTypes from 'prop-types';

import { ReactSVGPanZoom, TOOL_NONE, TOOL_PAN, TOOL_ZOOM_IN, TOOL_ZOOM_OUT, TOOL_AUTO } from 'react-svg-pan-zoom';
import * as constants from '../../constants';
import State from './state';

function mode2Tool(mode) {
  switch (mode) {
    case constants.MODE_2D_PAN:
      return TOOL_PAN;
    case constants.MODE_2D_ZOOM_IN:
      return TOOL_ZOOM_IN;
    case constants.MODE_2D_ZOOM_OUT:
      return TOOL_ZOOM_OUT;
    case constants.MODE_IDLE:
      return TOOL_AUTO;
    default:
      return TOOL_NONE;
  }
}

function mode2PointerEvents(mode) {
  switch (mode) {
    case constants.MODE_DRAWING_LINE:
    case constants.MODE_DRAWING_HOLE:
    case constants.MODE_DRAWING_ITEM:
    case constants.MODE_DRAGGING_HOLE:
    case constants.MODE_DRAGGING_ITEM:
    case constants.MODE_DRAGGING_LINE:
    case constants.MODE_DRAGGING_VERTEX:
      return { pointerEvents: 'none' };

    default:
      return {};
  }
}

function mode2Cursor(mode) {
  switch (mode) {
    case constants.MODE_DRAGGING_HOLE:
    case constants.MODE_DRAGGING_LINE:
    case constants.MODE_DRAGGING_VERTEX:
    case constants.MODE_DRAGGING_ITEM:
      return { cursor: 'move' };

    case constants.MODE_ROTATING_ITEM:
      return { cursor: 'ew-resize' };

    case constants.MODE_WAITING_DRAWING_LINE:
    case constants.MODE_DRAWING_LINE:
      return { cursor: 'crosshair' };
    default:
      return { cursor: 'default' };
  }
}

function mode2DetectAutopan(mode) {
  switch (mode) {
    case constants.MODE_DRAWING_LINE:
    case constants.MODE_DRAGGING_LINE:
    case constants.MODE_DRAGGING_VERTEX:
    case constants.MODE_DRAGGING_HOLE:
    case constants.MODE_DRAGGING_ITEM:
    case constants.MODE_DRAWING_HOLE:
    case constants.MODE_DRAWING_ITEM:
      return true;

    default:
      return false;
  }
}

function extractElementData(node) {
  while (!node.attributes.getNamedItem('data-element-root') && node.tagName !== 'svg') {
    node = node.parentNode;
  }
  if (node.tagName === 'svg') return null;

  return {
    part: node.attributes.getNamedItem('data-part') ? node.attributes.getNamedItem('data-part').value : undefined,
    layer: node.attributes.getNamedItem('data-layer').value,
    prototype: node.attributes.getNamedItem('data-prototype').value,
    selected: node.attributes.getNamedItem('data-selected').value === 'true',
    id: node.attributes.getNamedItem('data-id').value,
    name: node.attributes.getNamedItem('data-name') ? node.attributes.getNamedItem('data-name').value : null,
  }
}

class Viewer2D extends React.Component {

  componentDidMount() {
    const {height, width,state} = this.props;
    this.Viewer.fitToViewer();
    const scale = this.getScale(state.scene.width, state.scene.height, width, height);
    this.Viewer.setPointOnViewerCenter(this.props.state.scene.width/2, this.props.state.scene.height/2, scale)
  }
  getScale(sceneWidth, sceneHeight, width, height){
    const scaleHeight = height/sceneHeight;
    const scaleWidth = width/sceneWidth;
    return Math.min(scaleHeight,scaleWidth);
  }
  componentDidUpdate(prevProps){
    const {width: nextWidth, height: nextHeight, state: nextState } = this.props; 
    const {width: prevWidth, height: prevHeight, state: prevState } = prevProps; 
    const {width: prevSceneWidth, height: prevSceneHeight} = prevState.scene;
    const {width: nextSceneWidth, height: nextSceneHeight} = nextState.scene;

    const dimensionsExits = nextWidth && nextHeight && nextSceneWidth && nextSceneHeight;
    const sceneDimensionsChanged = nextSceneWidth != prevSceneWidth || nextSceneHeight != prevSceneHeight;
    const containerDimensionsChanged = nextWidth != prevWidth || nextHeight != prevHeight;
 
    if(dimensionsExits && (sceneDimensionsChanged || containerDimensionsChanged)){
      this.Viewer.fitToViewer();
      const scale = this.getScale(nextSceneWidth, nextSceneHeight, nextWidth, nextHeight);
      this.Viewer.setPointOnViewerCenter(nextSceneWidth/2, nextSceneHeight/2, scale)
    }
  }
  render() {

    const { state, width, height, onSelectArea } = this.props;
    const { viewer2DActions, linesActions, holesActions, verticesActions, itemsActions, areaActions, projectActions, catalog } = this.context;

    let { viewer2D, mode, scene } = state;

    let layerID = scene.selectedLayer;

    let mapCursorPosition = ({ x, y }) => {
      return { x, y: -y + scene.height }
    };

    let onMouseMove = viewerEvent => {

      //workaround that allow imageful component to work
      var evt = new Event('mousemove-planner-event');
      evt.viewerEvent = viewerEvent;
      document.dispatchEvent(evt);

      let { x, y } = mapCursorPosition(viewerEvent);

      projectActions.updateMouseCoord({ x, y });

      switch (mode) {
        case constants.MODE_DRAWING_LINE:
          linesActions.updateDrawingLine(x, y, state.snapMask);
          break;

        case constants.MODE_DRAWING_HOLE:
          holesActions.updateDrawingHole(layerID, x, y);
          break;

        case constants.MODE_DRAWING_ITEM:
          itemsActions.updateDrawingItem(layerID, x, y);
          break;

        case constants.MODE_DRAGGING_HOLE:
          holesActions.updateDraggingHole(x, y);
          break;

        case constants.MODE_DRAGGING_LINE:
          linesActions.updateDraggingLine(x, y, state.snapMask);
          break;

        case constants.MODE_DRAGGING_VERTEX:
          verticesActions.updateDraggingVertex(x, y, state.snapMask);
          break;

        case constants.MODE_DRAGGING_ITEM:
          itemsActions.updateDraggingItem(x, y);
          break;

        case constants.MODE_ROTATING_ITEM:
          itemsActions.updateRotatingItem(x, y);
          break;
      }

      viewerEvent.originalEvent.stopPropagation();
    };



    let onMouseUp = viewerEvent => {
      let event = viewerEvent.originalEvent;
      var evt = new Event('mouseup-planner-event');
      evt.viewerEvent = viewerEvent;
      document.dispatchEvent(evt);
      let { x, y } = mapCursorPosition(viewerEvent);

      switch (mode) {

        case constants.MODE_IDLE:
          let elementData = extractElementData(event.target);

          if (elementData && elementData.selected) return;

          switch (elementData ? elementData.prototype : 'none') {
            case 'areas':
              areaActions.selectArea(elementData.layer, elementData.id, elementData.name);
              onSelectArea(elementData.name);
              break;

            case 'none':
              projectActions.unselectAll();
              onSelectArea(null);
              break;
          }
          break;

        case constants.MODE_WAITING_DRAWING_LINE:
          linesActions.beginDrawingLine(layerID, x, y, state.snapMask);
          break;

        case constants.MODE_DRAWING_LINE:
          linesActions.endDrawingLine(x, y, state.snapMask);
          linesActions.beginDrawingLine(layerID, x, y, state.snapMask);
          break;

        case constants.MODE_DRAWING_HOLE:
          holesActions.endDrawingHole(layerID, x, y);
          break;

        case constants.MODE_DRAWING_ITEM:
          itemsActions.endDrawingItem(layerID, x, y);
          break;

        case constants.MODE_DRAGGING_LINE:
          linesActions.endDraggingLine(x, y, state.snapMask);
          break;

        case constants.MODE_DRAGGING_VERTEX:
          verticesActions.endDraggingVertex(x, y, state.snapMask);
          break;

        case constants.MODE_DRAGGING_ITEM:
          itemsActions.endDraggingItem(x, y);
          break;

        case constants.MODE_DRAGGING_HOLE:
          holesActions.endDraggingHole(x, y);
          break;

        case constants.MODE_ROTATING_ITEM:
          itemsActions.endRotatingItem(x, y);
          break;
      }

      event.stopPropagation();
    };

    let onChangeValue = (value) => {
      projectActions.updateZoomScale(value.a);
      return viewer2DActions.updateCameraView(value)
    };

    let onChangeTool = (tool) => {
      switch (tool) {
        case TOOL_NONE:
          projectActions.selectToolEdit();
          break;

        case TOOL_PAN:
          viewer2DActions.selectToolPan();
          break;

        case TOOL_ZOOM_IN:
          viewer2DActions.selectToolZoomIn();
          break;

        case TOOL_ZOOM_OUT:
          viewer2DActions.selectToolZoomOut();
          break;
      }
    };
   const scale = this.getScale(scene.width, scene.height, width, height);

    return (

      <ReactSVGPanZoom
        ref={Viewer => this.Viewer = Viewer}
        width={width}
        height={height}
        value={viewer2D.isEmpty() ? null : viewer2D.toJS()}
        onChangeValue={onChangeValue}
        background={'transparent'}
        tool={mode2Tool(mode)}
        toolbarPosition={'none'}
        onChangeTool={onChangeTool}
        detectAutoPan={mode2DetectAutopan(mode)}
        onMouseUp={onMouseUp}
        SVGBackground={'transparent'}
        preventPanOutside={true}
        scaleFactorMin={scale}
        miniaturePosition='none'>

        <svg width={scene.width} height={scene.height}>
          <g style={Object.assign(mode2Cursor(mode), mode2PointerEvents(mode))}>
            <State state={state} catalog={catalog} />
          </g>
        </svg>

      </ReactSVGPanZoom>

    );
  }

}

Viewer2D.propTypes = {
  state: PropTypes.object.isRequired,
  width: PropTypes.number.isRequired,
  height: PropTypes.number.isRequired,
};

Viewer2D.contextTypes = {
  viewer2DActions: PropTypes.object.isRequired,
  linesActions: PropTypes.object.isRequired,
  holesActions: PropTypes.object.isRequired,
  verticesActions: PropTypes.object.isRequired,
  itemsActions: PropTypes.object.isRequired,
  areaActions: PropTypes.object.isRequired,
  projectActions: PropTypes.object.isRequired,
  catalog: PropTypes.object.isRequired,
};


export default Viewer2D;