import React, { useState, useEffect, useRef } from 'react'
import PropTypes from 'prop-types'
import ReactDOM from 'react-dom'
import { Layout, Page, Block, constants as C } from '../ADLayout'
import ADBlock from './ADBlock.js'
import ToolBar from '../ADLayout/src/com/ToolBar'

function nullFunc () {
  // do nothing
}

/**
 * ADLayout (React)編輯器
 * @component
 */
function ADLayout (props) {
  const domLayout = useRef()
  const [layout] = useState(new Layout())
  const [page] = useState(new Page())
  useEffect(() => {
    layout.attachTo(domLayout.current)
    const _toolbar = new ToolBar(layout)
    layout.add(page)
      .registerEvent(C`ADLEVENT_BLOCK_CLICK`, props.onBlockClick || nullFunc)
      .registerEvent(C`ADLEVENT_BLOCK_MOUSEDOWN`, props.onBlockMouseDown || nullFunc)
      .registerEvent(C`ADLEVENT_BLOCK_MOUSEUP`, props.onBlockMouseUp || nullFunc)
      .registerEvent(C`ADLEVENT_BLOCK_MOUSEMOVE`, props.onBlockMouseMove || nullFunc)
      .registerEvent(C`ADLEVENT_BLOCK_MOUSEENTER`, props.onBlockMouseEnter || nullFunc)
      .registerEvent(C`ADLEVENT_BLOCK_MOUSELEAVE`, props.onBlockMouseLeave || nullFunc)
      .registerEvent(C`ADLEVENT_BLOCK_DBLCLICK`, props.onBlockDblClick || nullFunc)
      .registerEvent(C`ADLEVENT_BLOCK_SELECT_CHANGED`, props.onSelectionChange || nullFunc)
      .registerEvent(C`ADLEVENT_BLOCK_MOVE`, props.onBlockMove || nullFunc)
      .registerEvent(C`ADLEVENT_BLOCK_RESIZE`, props.onBlockResize || nullFunc)
  }, [])

  useEffect(() => {
    layout.grid(props.grid)
  }, [props.grid])

  useEffect(() => {
    switch (props.mode) {
      case 'readonly':
        layout.state.tool('none')
        break
      case 'edit':
      default:
        layout.state.tool('select')
        break
    }
  }, [props.mode])

  useEffect(() => {
    React.Children.forEach(props.children, child => {
      const vdom = document.createElement('div')
      ReactDOM.render(child, vdom, () => {
        const block = vdom.querySelector('div.block')
        if (block) page.append(Block(child.props, block))
      })
    })
  }, [props.children])

  return <div id='adlayoutWrapper' style={{ width: '100%', height: '100%' }} ref={domLayout} className='adlayout-wrapper' />
}

ADLayout.propTypes = {
  /**
   * 格線大小，單位px
   */
  grid: PropTypes.number,
  /**
   * 編輯模式，使用'edit'開啟編輯功能，使用'readonly'進入唯讀模式
   */
  mode: PropTypes.oneOf(['edit', 'readonly']),
  /**
   * 可編輯子元素，僅接受ADBlock物件
   */
  children: ({ children }) => React.Children.toArray(children).some(child => child.type !== ADBlock) && new Error('`ADLayout` children should be `ADBlock`.'),
  /**
   * 當ADBlock選取範圍改變觸發，此事件無參數
   */
  onSelectionChange: PropTypes.func,
  /**
   * 當ADBlock被點選觸發
   * @param {MouseEvent} MouseEvent物件
   */
  onBlockClick: PropTypes.func,
  /**
   * 當ADBlock被雙擊觸發
   * @param {MouseEvent} MouseEvent物件
   */
  onBlockDblClick: PropTypes.func,
  /**
   * 當滑鼠在ADBlock上移動觸發
   * @param {MouseEvent} MouseEvent物件
   */
  onBlockMouseMove: PropTypes.func,
  /**
   * 當滑鼠在ADBlock上按下觸發
   * @param {MouseEvent} MouseEvent物件
   */
  onBlockMouseDown: PropTypes.func,
  /**
   * 當滑鼠在ADBlock上放開觸發
   * @param {MouseEvent} MouseEvent物件
   */
  onBlockMouseUp: PropTypes.func,
  /**
   * 當ADBlock上改變大小後觸發
   * @param {MouseEvent} MouseEvent物件
   */
  onBlockResize: PropTypes.func,
  /**
   * 當滑鼠移入ADBlock後觸發
   * @param {MouseEvent} MouseEvent物件
   */
  onBlockMove: PropTypes.func,
  /**
   * 當ADBlock被移動後觸發
   * @param {MouseEvent} MouseEvent物件
   */
  onBlockMouseEnter: PropTypes.func,
  /**
   * 當滑鼠移出ADBlock後觸發
   * @param {MouseEvent} MouseEvent物件
   */
  onBlockMouseLeave: PropTypes.func,
  /**
   * 當開始拖曳ADBlock觸發
   * @param {MouseEvent} MouseEvent物件
   */
  onBlockDrogStart: PropTypes.func,
  /**
   * 當結束拖曳ADBlock上時觸發
   * @param {MouseEvent} MouseEvent物件
   */
  onBlockDragEnd: PropTypes.func
}

ADLayout.defaultProps = {
  grid: 1,
  mode: 'edit'
}

export default ADLayout
