
/*--
海皮智造 虚拟键盘 20200930
=============================================
React 内调用说明：
import { VirtualKeyboard } from './VK'
VirtualKeyboard 有2个参数，3个方法。
//
参数1：
VirtualKeyboard.isDisableEnter=true|false
是否禁用Enter键，默认为true。
参数2：
VirtualKeyboard.isDisableTab=true|false
是否禁用Tab键，默认为true。
------------------------
方法1：
.showKeyboardSetState(valueObject,reactComponent)
显示虚拟键盘，此方式主要用于Antd Input组件，由于Antd的输入组件直接修改dom的value不生效，故只能传入值Object对象。
valueObject 是一个Object，Object对象必须使用value属性来传递值。
reactComponent 是当前React Component，用于按键后setState更新显示。
如下例子：
let V={value:'123'}
<Input onClick={()=>VirtualKeyboard.showKeyboardSetState(V,this)} value={V.value}/>
方法2：
.showKeyboard(e)
显示虚拟键盘，此方式主要用于大部分模式。
参数e可是3种类型，
1、字符串，即要联动的dom的id
使用举例： VirtualKeyboard.showKeyboard("inputA")
2、直接是要联动的dom对象，
使用举例： VirtualKeyboard.showKeyboard(document.getElementById("xxx"))
3、鼠标/触摸事件
使用举例： <input onClick={VirtualKeyboard.showKeyboard} />
方法3：
.closeKeyboard()
用命令来关闭键盘，一般来说用不到。
--*/
import React from 'react';
import ReactDOM from 'react-dom';
import * as commonUtils from '../../utils/utils';

class VK extends React.Component {
  constructor(props) {
    super(props);
    if (props.values.dom !== null) {
      this.V.currentDom = props.values.dom;
    }
    if (props.values.value !== null && props.values.state !== null) {
      this.V.reactValueObject = props.values.value;
      this.V.reactStateObject = props.values.state;
    }
    const w = document.body.clientWidth;
    // const h = document.body.clientHeight;
    // eslint-disable-next-line no-mixed-operators
    // this.V.x = w / 2 - 970 / 2;
    // this.V.y = h - 300;
    this.V.x = w - 214;
    this.V.y = 10;
  }
  // eslint-disable-next-line react/sort-comp
  // C = [
  //   '~`', '!1', '@2', '#3', '$4', '%5', '^6', '&7', '*8', '(9', ')0', '_-', '+=', 'Backspace',
  //   'Tab', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{[', '}]', '|\\',
  //   'CapsLock', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'L', 'L', ':;', "\"'", 'Enter',
  //   'Shift', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<,', '>.', '?/', 'Space'];
  // eslint-disable-next-line react/sort-comp
  C = [
    '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '0', '←',
  ];
  // eslint-disable-next-line no-sparse-arrays
  W = [, , , , , , , , , , , , , 120, 90, , , , , , , , , , , , , 90, 110, , , , , , , , , , , , 135, 140, , , , , , , , , , , 170]

  componentWillReceiveProps(nextProps) {
    if (nextProps.values.dom !== null) {
      this.V.currentDom = nextProps.values.dom;
      this.V.reactValueObject = null;
      this.V.reactStateObject = null;
    } else if (nextProps.values.value !== null && nextProps.values.state !== null) {
      this.V.reactValueObject = nextProps.values.value;
      this.V.reactStateObject = nextProps.values.state;
      this.V.currentDom = null;
    }
  }
  getComponentFocus = () => {
    const { inputRef, state } = this.props.values;
    let componentId = '';
    if (commonUtils.isNotEmptyObject(state.props.showConfig)) {
      componentId = state[inputRef].props ? state[inputRef].props.id : state[inputRef].getAttribute('id');
    } else {
      componentId = inputRef;
    }
    // 获取光标
    if (commonUtils.isNotEmptyStr('inputRef') && document.getElementById(`${componentId}`) !== null) {
      document.getElementById(`${componentId}`).focus();
    } else {
      console.log('没有获得id');
    }
  }
  // eslint-disable-next-line camelcase
  F_ChangeInput = (c) => {
    let inputContent = '';
    if (this.V.currentDom !== null) {
      inputContent = this.V.currentDom.innerText || this.V.currentDom.textContent || this.V.currentDom.value;
    } else inputContent = this.V.reactValueObject.value;
    inputContent = inputContent.toString();
    const strArr = inputContent.split('');
    if (c === -1) {
      strArr.pop();
    } else strArr.push(c);
    if (this.V.currentDom !== null) {
      if (this.V.currentDom.nodeName === 'INPUT') {
        this.V.currentDom.value = strArr.join('');
      } else if (this.V.currentDom.nodeName !== undefined) {
        this.V.currentDom.innerHTML = strArr.join('');
      }
    } else if (this.V.reactStateObject !== null && this.V.reactValueObject !== null) {
      this.V.reactValueObject.value = strArr.join('');
    }
    const { state, inputRef } = this.props.values;
    const thisProps = state.props;
    if (commonUtils.isNotEmptyObject(thisProps.showConfig)) { // 走配置，commonComponent组件
      const returnValue = {};
      if (inputRef.substring(0, 1) === 'd') {
        if (commonUtils.isNotEmptyStr(this.V.reactValueObject.value)) {
          returnValue[thisProps.showConfig.sName] = this.V.reactValueObject.value * 1;
        } else {
          returnValue[thisProps.showConfig.sName] = '';
        }
      } else {
        returnValue[thisProps.showConfig.sName] = this.V.reactValueObject.value;
      }
      thisProps.onChange(thisProps.name, thisProps.showConfig.sName, returnValue, thisProps.sId, []);
    } else if (commonUtils.isNotEmptyObject(state.form)) { // input存在form组件中
      state.form.setFields({
        [inputRef]: {
          value: commonUtils.isEmptyStr(this.V.reactValueObject.value) ? '' : this.V.reactValueObject.value * 1,
        },
      });
    } else { // 其他类型
      state.handleKeyeBoardValueChange(state[inputRef], this.V.reactValueObject.value);
    }
    this.getComponentFocus();
  };
  V = {
    isCaps: false,
    isShift: false,
    currentDom: null,
    reactValueObject: null,
    reactStateObject: null,
  }
  // eslint-disable-next-line camelcase
  F_Close = () => {
    this.props.values.closeKeyboard();
  }
  // eslint-disable-next-line camelcase
  F_MouseDown = (e) => {
    e = e.nativeEvent;
    if (e.button !== 0) return;
    if (e.target.id.indexOf('VK_') !== 0) {
      if ((e.target.innerText === 'Enter' && this.props.values.isDisableEnter === true) || (e.target.innerText === 'Tab' && this.props.values.isDisableTab === true)) {
        return;
      }
      e.target.style.backgroundColor = '#F80';
      e.target.style.boxShadow = '0px 0px 4px #000 inset';
      this.V.keydom = e.target;
      document.addEventListener('mouseup', this.F_KeyMouseUp);
      return;
    }
    document.addEventListener('mousemove', this.F_MouseMove);
    document.addEventListener('mouseup', this.F_MouseUp);
    // this.V.posX = -e.pageX;
    // this.V.posY = -e.pageY;
    this.V.posX = -e.pageX;
    this.V.posY = -e.pageY;
  }
  // eslint-disable-next-line camelcase
  F_MouseMove = (e) => {
    const tx = this.V.posX + e.pageX + this.V.x;
    const ty = this.V.posY + e.pageY + this.V.y;
    this.dom.style.left = `${tx}px`;
    this.dom.style.top = `${ty}px`;
  }
  // eslint-disable-next-line camelcase
  F_MouseUp = (e) => {
    this.V.x = this.V.posX + e.pageX + this.V.x;
    this.V.y = this.V.posY + e.pageY + this.V.y;
    document.removeEventListener('mousemove', this.F_MouseMove);
    document.removeEventListener('mouseup', this.F_MouseUp);
    this.getComponentFocus();
  }
  // eslint-disable-next-line camelcase
  F_KeyMouseUp = () => {
    this.V.keydom.style.backgroundColor = '#FFF';
    this.V.keydom.style.boxShadow = null;
    document.removeEventListener('mouseup', this.F_KeyMouseUp);
  }
  // eslint-disable-next-line camelcase
  F_TouchStart = (e) => {
    e = e.nativeEvent;
    if (e.target.id.indexOf('VK_') !== 0) {
      if ((e.target.innerText === 'Enter' && this.props.values.isDisableEnter === true) || (e.target.innerText === 'Tab' && this.props.values.isDisableTab === true)) {
        return;
      }
      e.target.style.backgroundColor = '#F80';
      e.target.style.boxShadow = '0px 0px 4px #000 inset';
      this.V.keydom = e.target;
      document.addEventListener('touchend', this.F_KeyTouchEnd);
      return;
    }
    document.addEventListener('touchmove', this.F_TouchMove);
    document.addEventListener('touchend', this.F_TouchEnd);
    this.V.posX = -e.targetTouches[0].pageX;
    this.V.posY = -e.targetTouches[0].pageY;
  }
  // eslint-disable-next-line camelcase
  F_TouchMove = (e) => {
    const tx = this.V.posX + e.targetTouches[0].pageX + this.V.x;
    const ty = this.V.posY + e.targetTouches[0].pageY + this.V.y;
    this.dom.style.left = `${tx}px`;
    this.dom.style.top = `${ty}px`;
  }
  // eslint-disable-next-line camelcase
  F_TouchEnd = (e) => {
    this.V.x = this.V.posX + e.changedTouches[0].pageX + this.V.x;
    this.V.y = this.V.posY + e.changedTouches[0].pageY + this.V.y;
    document.removeEventListener('touchmove', this.F_TouchMove);
    document.removeEventListener('touchend', this.F_TouchEnd);
  }
  // eslint-disable-next-line camelcase
  F_KeyTouchEnd = () => {
    this.V.keydom.style.backgroundColor = '#FFF';
    this.V.keydom.style.boxShadow = null;
    document.removeEventListener('touchend', this.F_KeyTouchEnd);
  }
  // eslint-disable-next-line camelcase
  F_KeyDown = (e) => {
    const dom = e.target;
    const txt = dom.innerText;
    if (txt === 'CapsLock') {
      this.V.isCaps = !this.V.isCaps;
      if (this.V.isCaps) {
        dom.style.backgroundColor = '#F80';
      } else {
        dom.style.backgroundColor = '#FFF';
      }
      this.setState({});
    } else if (txt === 'Shift') {
      this.V.isShift = !this.V.isShift;
      if (this.V.isShift) {
        dom.style.backgroundColor = '#F80';
      } else {
        dom.style.backgroundColor = '#FFF';
      }
      this.setState({});
    } else if (txt === 'Enter') {
      if (this.props.values.isDisableEnter === false) {
        this.F_ChangeInput(String.fromCharCode(13));
      }
    } else if (txt === 'Space') {
      this.F_ChangeInput(' ');
    } else if (txt === 'Tab') {
      if (this.props.values.isDisableTab === false) {
        this.F_ChangeInput(String.fromCharCode(9));
      }
    } else if (txt === '←') {
      this.F_ChangeInput(-1);
    } else if (txt.indexOf('\n') >= 0) {
      if (this.V.isShift) {
        this.F_ChangeInput(txt[0]);
      } else {
        this.F_ChangeInput(txt[2]);
      }
    } else if (this.V.isShift) {
      this.F_ChangeInput(txt.toUpperCase() === txt ? txt.toLowerCase() : txt.toUpperCase());
    } else {
      this.F_ChangeInput(txt);
    }
  }
  render() {
    const keyStyle = {
      boxSizing: 'border-box',
      float: 'left',
      height: 60,
      margin: 2.5,
      borderRadius: 4,
      border: '1px solid #333',
      textAlign: 'center',
      cursor: 'pointer',
    };
    return (
      <div
        onContextMenu={e => e.preventDefault()}
        tabIndex="-1"
        id="VK_Main"
        /* eslint-disable-next-line no-return-assign */
        ref={dom => this.dom = dom}
        style={{
          outline: 'none',
          top: this.V.y,
          left: this.V.x,
          position: 'absolute',
          zIndex: '999999999',
          backgroundColor: 'rgb(217 217 217)',
          padding: 3,
          width: 204,
          fontSize: 20,
          border: '1px solid #444',
          borderRadius: 8,
          userSelect: 'none',
        }}
        onMouseDown={this.F_MouseDown}
        onTouchStart={this.F_TouchStart}
        // onBlur={this.F_Close}
      >
        <div id="VK_Title" style={{ fontSize: 14, margin: 5, textAlign: 'right' }}>可以拖动移开或 <button style={{ borderRadius: 6, border: '1px dotted #333' }} onClick={this.F_Close}>关闭键盘</button></div>
        <div id="VK_Keys" style={{ height: 67, lineHeight: 67 }} onClick={this.F_KeyDown} >
          {this.C.map((c, n) => {
            return (
              <div
                /* eslint-disable-next-line react/no-array-index-key */
                key={n}
                style={{
                  ...keyStyle,
                  width: 60,
                  lineHeight: '60px',
                  backgroundColor: '#fff',
                }}
              >
                {c}
              </div>
            );
          })}
        </div>
      </div>
    );
  }
}
// ===========================================
const data = {
  VK: VK.prototype,
  div: null,
  props: {},
};

export const VirtualKeyboard = {
  isDisableEnter: true,
  isDisableTab: true,
  showKeyboardSetState: (valueObject, reactComponent, inputId) => {
    data.props.value = valueObject;
    data.props.state = reactComponent;
    data.props.inputRef = inputId;
    data.props.dom = null;
    if (data.div !== null) {
      data.VK.setState({});
    } else {
      data.props.closeKeyboard = VirtualKeyboard.closeKeyboard;
      data.props.isDisableEnter = VirtualKeyboard.isDisableEnter;
      data.props.isDisableTab = VirtualKeyboard.isDisableTab;
      const body = document.getElementsByTagName('body')[0];
      if (body === undefined) return;
      const div = document.createElement('div');
      data.div = div;
      body.appendChild(div);
      // eslint-disable-next-line no-return-assign
      const V = <VK ref={dom => data.VK = dom} values={data.props} />;
      ReactDOM.render(V, div);
    }
  },
  showValue: () => {
    return data.props.value;
  },
  showKeyboard: (e) => {
    data.props.value = null;
    data.props.state = null;
    data.props.dom = null;
    if (typeof (e) === 'string') {
      const dom = document.getElementById(e);
      if (dom !== null) {
        data.props.dom = dom;
      }
    } else if (typeof (e) === 'object') {
      if (typeof (e.type) === 'string' && typeof (e.nodeName) === 'string') {
        data.props.dom = e;
      } else if (e.target !== undefined) {
        e = e.target;
        if (typeof (e.type) === 'string' && typeof (e.nodeName) === 'string') {
          data.props.dom = e;
        }
      }
    }
    if (data.props.dom === null) return;
    if (data.div !== null) {
      data.VK.setState({});
    } else {
      data.props.closeKeyboard = VirtualKeyboard.closeKeyboard;
      data.props.isDisableEnter = VirtualKeyboard.isDisableEnter;
      data.props.isDisableTab = VirtualKeyboard.isDisableTab;
      const body = document.getElementsByTagName('body')[0];
      if (body === undefined) return;
      const div = document.createElement('div');
      data.div = div;
      body.appendChild(div);
      // eslint-disable-next-line no-return-assign
      const V = <VK ref={dom => data.VK = dom} values={data.props} />;
      ReactDOM.render(V, div);
    }
  },
  isKeyBoard: () => { // 判断之前是否有全键盘打开
    if (data.div === null) {
      return false;
    } else {
      return true;
    }
  },
  closeKeyboard: () => { // 关闭键盘
    ReactDOM.render(<div />, data.div);
    data.div.remove();
    data.div = null;
  },
};
