<template>
  <transition name="el-message-fade">
    <div
      :class="[
        'el-message',
        type && !iconClass ? `el-message--${ type }` : '',
        center ? 'is-center' : '',
        showClose ? 'is-closable' : '',
        customClass
      ]"
      v-show="visible"
      @mouseenter="clearTimer"
      @mouseleave="startTimer"
      role="alert"
      :style="{top: messageTopPosition}">

      <fa-icon :icon="iconClass || typeClass" class="el-message__icon"></fa-icon>

      <slot>
        <p v-if="!dangerouslyUseHTMLString" class="el-message__content">{{ message }}</p>
        <p v-else v-html="message" class="el-message__content"></p>
      </slot>
      <span v-if="showClose" class="el-message__closeBtn" @click="close">
        <fa-icon :icon="['fal', 'times']"></fa-icon>
      </span>
    </div>
  </transition>
</template>

<script type="text/babel">
import { messageInstances } from 'element-ui/packages/message/src/main.js';
import { findIndex } from 'lodash';

const typeMap = {
  success: ['fas', 'check-circle'],
  info: ['fas', 'info-circle'],
  warning: ['fas', 'exclamation-circle'],
  error: ['fas', 'times-circle']
};

export default {
  data() {
    return {
      visible: false,
      message: '',
      duration: 3000,
      type: 'info',
      iconClass: '',
      customClass: '',
      onClose: null,
      showClose: false,
      closed: false,
      timer: null,
      dangerouslyUseHTMLString: false,
      center: false,
      stack: false,
      messageInstances
    };
  },

  computed: {
    typeClass() {
      return this.type && !this.iconClass ? typeMap[this.type] : '';
    },
    messageTopPosition() {
      if (!this.stack) return '10px';
      const { messageInstances } = this;
      const position = findIndex(messageInstances, this);
      if (position && position !== -1) {
        const previousMessageNode = messageInstances[position - 1].$el;
        const previousNodeHeight = previousMessageNode.offsetHeight;
        const previousNodeTopPosition = parseInt(previousMessageNode.style.top.replace('px', ''), 10);
        return `${previousNodeTopPosition + previousNodeHeight + 10}px`;
      }
      return '10px'; // first option offset from top of screen
    }
  },

  watch: {
    closed(newVal) {
      if (newVal) {
        this.visible = false;
        this.$el.addEventListener('transitionend', this.destroyElement);
      }
    }
  },

  methods: {
    destroyElement() {
      this.$el.removeEventListener('transitionend', this.destroyElement);
      this.$destroy(true);
      this.$el.parentNode.removeChild(this.$el);
    },

    close() {
      this.closed = true;
      if (typeof this.onClose === 'function') {
        this.onClose(this);
      }
    },

    clearTimer() {
      clearTimeout(this.timer);
    },

    startTimer() {
      if (this.duration > 0) {
        this.timer = setTimeout(() => {
          if (!this.closed) {
            this.close();
          }
        }, this.duration);
      }
    },

    restartTimer() {
      clearTimeout(this.timer);
      if (this.duration > 0) {
        this.timer = setTimeout(() => {
          if (!this.closed) {
            this.close();
          }
        }, this.duration);
      }
    },

    keydown(e) {
      if (e.keyCode === 27) { // esc关闭消息
        if (!this.closed) {
          this.close();
        }
      }
    }
  },
  mounted() {
    this.startTimer();
    document.addEventListener('keydown', this.keydown);
  },
  beforeDestroy() {
    document.removeEventListener('keydown', this.keydown);
  }
};
</script>
