<template>
  <div class="keyboard"
       @touchmove.prevent>
    <div class="keyboard__input"
         v-if="type==='grid'">
      <div class="keyboard__input-item"
           v-for="(item,index) in inputTexts"
           :key="index"
           @click="keyboardInput(index)"
           :class="{'keyboard__input-energy': index===(inputTexts.length-1)&&!isAbroad, 'keyboard__input-active ignore-height':activeIndex === index}">
        {{item}}
        <em class="keyboard__input-icon"
            v-if="index===(inputTexts.length-1)"
            v-show="!isAbroad"></em>
      </div>
    </div>
    <div class="keyboard__input"
         v-if="type==='input' && !isAbroad">
      <div class="keyboard__input-input"
           @click="!passiveTrigger && keyboardInput(inputIndex)">
        <span class="keyboard__input-text"
              :placeholder="placeholder"
              :class="{'keyboard__input-placeholder':textLength===0 && activeIndex===''}">
          <label v-for="(item,index) in inputTexts"
                 :key="index"
                 class="keyboard__input-txt">{{item}}</label>
        </span>
        <em v-show="activeIndex!==''"
            class="keyboard__input-icon ignore-bg"></em>
        <em class="keyboard__input-energy"
            v-show="textLength===inputTexts.length">新能源</em>
        <slot></slot>
      </div>
    </div>
    <div class="keyboard__input"
         v-if="type==='input' && isAbroad">
      <div class="keyboard__input-input"
           style="padding:0;">
        <input type="text"
               v-model.trim="abroadValue"
               @blur="abroadInputEnd"
               :maxlength="maxlength"
               :placeholder="placeholder"
               class="keyboard__input-abroad" />
        <slot></slot>
      </div>
    </div>
    <div class="keyboard__content"
         ref="keyboardContent"
         v-show="activeIndex !== ''">
      <div class="keyboard__bar">
        <div class="keyboard__btn keyboard__btn-overseas"
             @click="changeAbroad"
             v-if="showSwitch">{{abroadTxt}}</div>
        <div class="keyboard__btn keyboard__btn-close"
             @click="closeKeyboard">关闭</div>
      </div>
      <div class="keyboard__prefix ignore-max-width"
           v-show="!suffixShow"
           @click.stop.prevent>
        <div class="keyboard__box"
             v-for="(item,index) in prefix"
             :key="'row'+index">
          <div class="keyboard__key"
               v-for="(key,index) in item"
               :key="'col'+index"
               :class="[key.class]">
            <span class="keyboard__key-txt"
                  @touchstart.prevent="keyTouchStart($event,key.class,key.text)"
                  @touchend.prevent="keyTouchEnd($event,key.class,key.text)"
                  @mousedown="keyTouchStart($event,key.class,key.text)"
                  @mouseup="keyTouchEnd($event,key.class,key.text)"
                  @contextmenu.prevent>{{key.text}}</span>
          </div>
        </div>
      </div>
      <div class="keyboard__suffix ignore-max-width"
           v-show="suffixShow"
           @click.stop.prevent>
        <div class="keyboard__box"
             v-for="(item,index) in suffix"
             :key="index+'row'">
          <div class="keyboard__key"
               v-for="(key,index) in item"
               :key="index + 'col'"
               :class="[key.disabled ? key.class : '']">
            <span class="keyboard__key-txt"
                  @touchstart.prevent="keyTouchStart($event,key.class,key.text)"
                  @touchend.prevent="keyTouchEnd($event,key.class,key.text)"
                  @mousedown="keyTouchStart($event,key.class,key.text)"
                  @mouseup="keyTouchEnd($event,key.class,key.text)"
                  @contextmenu.prevent>{{key.text}}</span>
          </div>
        </div>
      </div>
      <div class="keyboard__key--hover"
           v-show="isHover"
           :style="hoverPosition">{{hoverText}}</div>
    </div>
  </div>
</template>
<script>
import { directive as clickOutside } from 'v-click-outside-x';
export default {
  name: 'Keyboard',
  directives: { clickOutside },
  props: {
    placeholder: {
      type: String,
      default: '请输入车牌号'
    },
    showSwitch: {
      type: Boolean,
      default: false
    },
    type: {
      type: String,
      default: 'grid'
    },
    defaultText: {
      type: String,
      default: ''
    },
    passiveTrigger: {
      type: Boolean,
      default: false
    },
    isAbroad: {
      type: Boolean,
      default: false
    },
    maxlength: {
      type: Number,
      default: 10
    },
    hasElementFocus: {
      type: Boolean,
      default: false
    },
    clickOutsideClose: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      inputTexts: ['', '', '', '', '', '', '', ''],
      textLength: 0,
      // grid类型输入的索引
      activeIndex: '',
      // input类型输入的索引
      inputIndex: 0,
      suffixShow: false,
      abroadTxt: '境外',
      abroadValue: '',
      prefix: [
        [{ text: '京', class: '' }, { text: '津', class: '' }, { text: '晋', class: '' }, { text: '冀', class: '' }, { text: '蒙', class: '' }, { text: '辽', class: '' }, { text: '吉', class: '' }, { text: '黑', class: '' }, { text: '沪', class: '' }],
        [{ text: '苏', class: '' }, { text: '浙', class: '' }, { text: '皖', class: '' }, { text: '闽', class: '' }, { text: '赣', class: '' }, { text: '鲁', class: '' }, { text: '豫', class: '' }, { text: '鄂', class: '' }, { text: '湘', class: '' }],
        [{ text: '', class: 'keyboard__key-empty--small' }, { text: '粤', class: '' }, { text: '桂', class: '' }, { text: '琼', class: '' }, { text: '渝', class: '' }, { text: '川', class: '' }, { text: '贵', class: '' }, { text: '云', class: '' }, { text: '藏', class: '' }, { text: '', class: 'keyboard__key-empty--small' }],
        [{ text: '', class: 'keyboard__key-empty' }, { text: '陕', class: '' }, { text: '甘', class: '' }, { text: '青', class: '' }, { text: '宁', class: '' }, { text: '新', class: '' }, { text: 'W', class: '' }, { text: '', class: 'keyboard__key-del' }, { text: '', class: 'keyboard__key-empty' }]
      ],
      suffix: [
        [{ text: '1', class: 'keyboard__key--disaled', disabled: true, active: true }, { text: '2', class: 'keyboard__key--disaled', disabled: true, active: true }, { text: '3', class: 'keyboard__key--disaled', disabled: true, active: true }, { text: '4', class: 'keyboard__key--disaled', disabled: true, active: true }, { text: '5', class: 'keyboard__key--disaled', disabled: true, active: true }, { text: '6', class: 'keyboard__key--disaled', disabled: true, active: true }, { text: '7', class: 'keyboard__key--disaled', disabled: true, active: true }, { text: '8', class: 'keyboard__key--disaled', disabled: true, active: true }, { text: '9', class: 'keyboard__key--disaled', disabled: true, active: true }, { text: '0', class: 'keyboard__key--disaled', disabled: true, active: true }],
        [{ text: 'Q', class: '' }, { text: 'W', class: '' }, { text: 'E', class: '' }, { text: 'R', class: '' }, { text: 'T', class: '' }, { text: 'Y', class: '' }, { text: 'U', class: '' }, { text: 'O', class: '', active: true }, { text: 'P', class: '', active: true }, { text: '军', class: 'keyboard__key--disaled', disabled: true, active: true }],
        [{ text: 'A', class: '' }, { text: 'S', class: '' }, { text: 'D', class: '' }, { text: 'F', class: '' }, { text: 'G', class: '' }, { text: 'H', class: '' }, { text: 'J', class: '' }, { text: 'K', class: '' }, { text: 'L', class: '' }, { text: '警', class: 'keyboard__key--disaled', disabled: true, active: true }],
        [{ text: 'Z', class: '' }, { text: 'X', class: '' }, { text: 'C', class: '' }, { text: 'V', class: '' }, { text: 'B', class: '' }, { text: 'N', class: '' }, { text: 'M', class: '' }, { text: '港', class: 'keyboard__key--disaled', disabled: true, active: true }, { text: '澳', class: 'keyboard__key--disaled', disabled: true, active: true }, { text: '', class: 'keyboard__key-del', disabled: true }]
      ],
      isHover: false,
      hoverPosition: {
        top: 0,
        left: 0
      },
      hoverText: '',
      changePosition: false,
      fixedMaring: false,
      orginRect: 0,
      timeStep: 0,
      startX: 0,
      endX: 0,
      startY: 0,
      endY: 0,
      blockTouch: false,
      setTimeoutObj: null
    };
  },
  watch: {
    inputTexts: function(newValue, oldValue) {
      this.textLength = this.inputTexts.join('').length;
      let len = this.inputTexts.join('').length;
      if (len > this.inputTexts.length - 1) {
        len = this.inputTexts.length - 1;
      }
      this.inputIndex = len;
    },
    defaultText: {
      handler(newValue, oldVal) {
        if (newValue || newValue === '') {
          const newLen = newValue.length;
          const defaultLen = this.inputTexts.length;
          const newArray = newValue.split('');
          if (newLen !== defaultLen) {
            newArray.length = defaultLen;
            newArray.fill('', newLen, defaultLen);
          }
          this.inputTexts = newArray;
          if (this.type === 'grid' || (this.type === 'input' && !this.isAbroad)) {
            this.$emit('onKeyboardInput', newValue);
          }
          if (this.isAbroad) {
            this.abroadValue = newValue;
          }
        }
      },
      immediate: true
    }
  },
  mounted() {
    const that = this;
    setTimeout(() => {
      if (!that.orginRect) {
        that.orginRect = {
          bottom: that.$el.getBoundingClientRect().bottom,
          winHeight: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
        };
      }
    }, 600);
  },
  methods: {
    triggerKeyboardInput(index) {
      if (index === this.inputTexts.length) {
        index = this.inputTexts.length - 1;
      }
      this.keyboardInput(index);
    },
    keyboardInput(index) {
      if (this.hasElementFocus && this.setTimeoutObj === null) {
        this.setTimeoutObj = setTimeout(this.keyboardInput, 120, index);
        return;
      }
      if (!this.inputTexts.join('')) {
        this.activeIndex = 0;
      } else {
        this.activeIndex = index;
      }
      this.toggleKeyboard();
      this.scrollKeyboard();
    },
    scrollKeyboard() {
      let bottom = this.$el.getBoundingClientRect().bottom;
      let winHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
      const u = navigator.userAgent;
      const android = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1;
      setTimeout(function(that) {
        if (!that.$refs.keyboardContent) {
          return;
        }
        const keyboardHeight = that.$refs.keyboardContent.clientHeight || that.$refs.keyboardContent.scrollHeight;
        if (android) { // 安卓浏览器聚焦时窗口大小会变小，导致键盘输入框定位出现问题
          bottom = that.orginRect.bottom;
          winHeight = that.orginRect.winHeight;
        }
        that.fixedMaring = winHeight - bottom < keyboardHeight;
        if (that.fixedMaring) {
          const paddingTop = keyboardHeight - (winHeight - bottom);
          document.body.firstElementChild.style.cssText = 'margin-top:' + (-(paddingTop + 20 + window.scrollY)) + 'px';
        }
      }, 90, this);
    },
    keyTouchStart(e, className, txt) {
      this.blockTouch = true;
      if (className !== 'keyboard__key--disaled' && className !== 'keyboard__key-del') {
        const rect = e.target.getBoundingClientRect();
        this.hoverPosition.top = rect.top + 'px';
        this.hoverPosition.left = rect.left + rect.width / 2 + 'px';
        this.hoverText = txt;
        this.isHover = true;
      }
    },
    keyTouchEnd(e, className, txt) {
      if (e && !this.blockTouch) {
        return;
      }
      this.blockTouch = false;
      if (className !== 'keyboard__key--disaled' && className !== 'keyboard__key-del') {
        this.$set(this.inputTexts, this.activeIndex, txt);
        this.suffixShow = true;
        this.activeIndex++;
        if (this.activeIndex === this.inputTexts.length) {
          this.activeIndex--;
        }
        this.toggleKeyboard();
        this.isHover = false;
      } else if (className === 'keyboard__key-del') {
        // input 类型键盘删除键删除时直接退位
        if (this.type === 'input') {
          if (this.inputIndex) {
            if (this.inputTexts.length - 1 !== this.inputTexts.join('').length - 1) {
              this.activeIndex--;
            }
            this.$set(this.inputTexts, this.inputTexts.join('').length - 1, '');
            if (this.activeIndex <= 0) {
              if (this.isAbroad) {
                this.suffixShow = true;
              } else {
                this.suffixShow = false;
              }
              this.activeIndex = 0;
            }
            this.toggleKeyboard();
          }
          const lpnString = this.getLpnString();
          this.$emit('onKeyboardInput', lpnString);
          return;
        }
        // grid 类型键盘删除键删除时如果该空格没有文字直接退位否则先删除文字再退位
        if (this.inputTexts[this.activeIndex]) {
          this.$set(this.inputTexts, this.activeIndex, '');
        } else {
          this.activeIndex--;
          if (this.activeIndex <= 0) {
            if (this.isAbroad) {
              this.suffixShow = true;
            } else {
              this.suffixShow = false;
            }
            this.activeIndex = 0;
          }
          this.toggleKeyboard();
        }
      }
      const lpnString = this.getLpnString();
      this.$emit('onKeyboardInput', lpnString);
    },
    changeAbroad() {
      this.isAbroad = !this.isAbroad;
      this.abroadTxt = this.isAbroad ? '境内' : '境外';
      this.toggleKeyboard();
    },
    toggleKeyboard() {
      this.suffixShow = true;
      if (this.isAbroad) {
        // 境外键盘
        this.suffix = this.suffix.map(item => {
          item.map(key => {
            if (key.active) {
              if (this.changePosition) {
                if (key.text === 'P') {
                  key.text = 'O';
                } else if (key.text === '学') {
                  key.text = 'P';
                  this.changePosition = false;
                }
              }
              if (key.text === '军' || key.text === '警' || key.text === '港' || key.text === '澳') {
                key.disabled = true;
                key.class = 'keyboard__key--disaled';
              } else {
                key.disabled = false;
                key.class = '';
              }
            }
            return key;
          });
          return item;
        });
      } else {
        // 境外键盘
        if (this.activeIndex === 0) {
          // 第一位省份缩写
          this.suffixShow = false;
        } else if (this.activeIndex === 1) {
          // 第二位只能字母
          this.suffix = this.suffix.map(item => {
            item.map(key => {
              if (key.active) {
                if (this.changePosition) {
                  if (key.text === 'P') {
                    key.text = 'O';
                  } else if (key.text === '学') {
                    key.text = 'P';
                    this.changePosition = false;
                  }
                }
                if (key.text === 'O' || key.text === 'P') {
                  key.disabled = false;
                  key.class = '';
                } else {
                  key.disabled = true;
                  key.class = 'keyboard__key--disaled';
                }
              }
              return key;
            });
            return item;
          });
          // this.changePosition = false;
        } else if (this.activeIndex === 6) {
          // 非能源车牌最后一位可以是军警港澳台
          this.suffix = this.suffix.map(item => {
            item.map(key => {
              if (key.active) {
                key.disabled = false;
                key.class = '';
                if (!this.changePosition) {
                  if (key.text === 'O') {
                    key.text = 'P';
                  } else if (key.text === 'P') {
                    key.text = '学';
                    this.changePosition = true;
                  }
                }
              }
              return key;
            });
            return item;
          });
        } else {
          // 剩下的位数可以不能是军警港澳台和字母O
          this.suffix = this.suffix.map(item => {
            item.map(key => {
              if (key.active) {
                if (this.changePosition) {
                  if (key.text === 'P') {
                    key.text = 'O';
                  } else if (key.text === '学') {
                    key.text = 'P';
                    this.changePosition = false;
                  }
                }
                if (key.text === '军' || key.text === '警' || key.text === '港' || key.text === '澳' || key.text === 'O') {
                  key.disabled = true;
                  key.class = 'keyboard__key--disaled';
                } else {
                  key.disabled = false;
                  key.class = '';
                }
              }
              return key;
            });
            return item;
          });
        }
      }
    },
    handleClose(e) {
      if (!this.clickOutsideClose) {
        return;
      }
      const visible = this.activeIndex !== '';
      if (e && e.type === 'touchstart' && visible) {
        this.timeStep = new Date().getTime();
        this.startX = e.touches[0].pageX;
        this.startY = e.touches[0].pageY;
      }
      if (e && e.type === 'touchmove' && visible) {
        this.timeStep = new Date().getTime();
        this.endX = e.touches[0].pageX;
        this.endY = e.touches[0].pageY;
      }
      if (e && e.type === 'touchend' && visible) {
        const nowStep = new Date().getTime();
        const moveX = Math.abs(this.endX - this.startX);
        const moveY = Math.abs(this.endY - this.startY);
        if ((moveY > 5 || moveX > 5) && this.endX) {
          this.endX = 0;
          this.endY = 0;
          e && e.preventDefault();
          e && e.stopPropagation();
          return;
        }
        if (nowStep - this.timeStep <= 600) {
          this.closeKeyboard();
          e && e.preventDefault();
          e && e.stopPropagation();
        }
      }
    },
    coverClose() {
      this.closeKeyboard();
    },
    closeKeyboard() {
      if (this.fixedMaring) {
        document.body.firstElementChild.style.cssText = '';
      }
      this.setTimeoutObj = null;
      this.suffixShow = false;
      this.activeIndex = '';
      const lpnString = this.getLpnString();
      this.$emit('onKeyboardClose', lpnString);
    },
    abroadInputEnd() {
      const that = this;
      setTimeout(() => {
        if (that.isAbroad) {
          that.$emit('onKeyboardClose', this.abroadValue.replace(/\s/g, ''));
        }
      }, 60);
    },
    getLpnString() {
      const lpnString = this.inputTexts.map(item => {
        return item === '' ? ' ' : item;
      }).join('');
      return lpnString.trim();
    },
    getValue(abroad) {
      if (abroad) {
        return this.abroadValue.replace(/\s/g, '');
      } else {
        return this.getLpnString();
      }
    },
    clear() {
      this.inputTexts = ['', '', '', '', '', '', '', ''];
      this.abroadValue = '';
    }
  }
};
</script>
