<template>
  <div class="qf-tabs-nav" :class="[type == 'card' ? 'is-card':'', scrollable ? 'is-scrollable' : '', `is-${ tabPosition }`]">
    <span :class="['qf-tabs-nav-prev', scrollable.prev ? '' : 'is-disabled']" @click="scrollPrev" v-if="scrollable">
      <qf-font-icon class="ic-ic_shangyiyue"></qf-font-icon>
    </span>
    <span :class="['qf-tabs-nav-next', scrollable.next ? '' : 'is-disabled']" @click="scrollNext" v-if="scrollable">
      <qf-font-icon class="ic-ic_xiayiyue"></qf-font-icon>
    </span>
    <div class="qf-tabs-nav-scroll" ref="navScroll">
      <div class="qf-tabs-list" ref="nav" role="tablist" :style="navStyle">
        <tab-bar :tabs="panes" ref="bar" v-if="type !== 'card' && !hideBar" :tabPosition="tabPosition"></tab-bar>
        <div v-if="!$slots.default" class="qf-tab-item" :class="[item.active ? 'is-active': '', `is-${ tabPosition }`]" v-for="(item, index) in panes" :key=index :id=tabName(item) :tabindex=tabIndex(item) refInFor @click="onClick(item, $event)" ref="tabs">
          {{tabLabel(item)}}
        </div>
        <slot></slot>
      </div>
    </div>
  </div>
</template>

<script>
import TabBar from './tab-bar';
import QfFontIcon from '../font-icon';
import { addResizeListener, removeResizeListener } from '../util/resize-event';

function noop() {
}

const firstUpperCase = str => {
  return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase());
};

export default {
  name: 'QfTabNav',

  components: {
    TabBar,
    QfFontIcon
  },

  provide() {
    return {
      rootNav: this
    };
  },

  props: {
    activeName: String,
    editable: Boolean,
    hideBar: {
      type: Boolean,
      default: false
    },
    onTabClick: {
      type: Function,
      default: noop
    },
    onTabRemove: {
      type: Function,
      default: noop
    },
    type: String,
    tabPosition: {
      type: String,
      default: 'top'
    },
    value: String
  },

  watch: {
    value(val) {
      if (val) {
        this.currentName = val;
      }
    },
    currentName() {
      this.$nextTick(() => {
        this.scrollToActiveTab();
      });
    }
  },

  data() {
    return {
      panes: [],
      currentName: this.activeName,
      items: [],
      scrollable: false,
      navOffset: 0
    };
  },

  computed: {
    navStyle() {
      const dir = ['top', 'bottom'].indexOf(this.tabPosition) !== -1 ? 'X' : 'Y';
      return {
        transform: `translate${dir}(-${this.navOffset}px)`
      };
    },
    sizeName() {
      return ['top', 'bottom'].indexOf(this.tabPosition) !== -1 ? 'width' : 'height';
    }
  },

  mounted() {
    addResizeListener(this.$el, this.update);
  },

  beforeDestroy() {
    if (this.$el && this.update) removeResizeListener(this.$el, this.update);
  },

  updated() {
    this.update();
  },

  methods: {
    update() {
      const sizeName = this.sizeName;
      const navSize = this.$refs.nav[`offset${firstUpperCase(sizeName)}`];
      const containerSize = this.$refs.navScroll[`offset${firstUpperCase(sizeName)}`];
      const currentOffset = this.navOffset;
      if (containerSize < navSize) {
        const currentOffset = this.navOffset;
        this.scrollable = this.scrollable || {};
        this.scrollable.prev = currentOffset;
        this.scrollable.next = currentOffset + containerSize < navSize;
        if (navSize - currentOffset < containerSize) {
          this.navOffset = navSize - containerSize;
        }
      } else {
        this.scrollable = false;
        if (currentOffset > 0) {
          this.navOffset = 0;
        }
      }
      if (this.$refs.bar) {
        this.$refs.bar.$forceUpdate();
      }
    },

    scrollPrev() {
      const containerSize = this.$refs.navScroll[`offset${firstUpperCase(this.sizeName)}`];
      const currentOffset = this.navOffset;
      if (!currentOffset) return;
      let newOffset = currentOffset > containerSize
        ? currentOffset - containerSize
        : 0;
      this.navOffset = newOffset;
    },

    scrollNext() {
      const navSize = this.$refs.nav[`offset${firstUpperCase(this.sizeName)}`];
      const containerSize = this.$refs.navScroll[`offset${firstUpperCase(this.sizeName)}`];
      const currentOffset = this.navOffset;
      if (navSize - currentOffset <= containerSize) return;
      let newOffset = navSize - currentOffset > containerSize * 2
        ? currentOffset + containerSize
        : (navSize - containerSize);
      this.navOffset = newOffset;
    },

    scrollToActiveTab() {
      if (!this.scrollable) return;
      const nav = this.$refs.nav;
      const activeTab = this.$el.querySelector('.is-active');
      if (!activeTab) return;
      const navScroll = this.$refs.navScroll;
      const activeTabBounding = activeTab.getBoundingClientRect();
      const navScrollBounding = navScroll.getBoundingClientRect();
      const navBounding = nav.getBoundingClientRect();
      const currentOffset = this.navOffset;
      let newOffset = currentOffset;
      if (activeTabBounding.left < navScrollBounding.left) {
        newOffset = currentOffset - (navScrollBounding.left - activeTabBounding.left);
      }
      if (activeTabBounding.right > navScrollBounding.right) {
        newOffset = currentOffset + activeTabBounding.right - navScrollBounding.right;
      }
      if (navBounding.right < navScrollBounding.right) {
        newOffset = nav.offsetWidth - navScrollBounding.width;
      }
      this.navOffset = Math.max(newOffset, 0);
    },

    tabName(item) {
      return item.name || item.index;
    },

    tabIndex(item) {
      return item.active ? 0 : -1;
    },

    tabLabel(item) {
      return item.$slots.label || item.label;
    },

    setCurrentName(value) {
      this.currentName = value;
      this.$emit('input', value);
    },

    onClick(item, $event) {
      this.setCurrentName(this.tabName(item));
      this.onTabClick(item, this.tabName(item), event);
    },

    addItem(item, index) {
      if (index === undefined) {
        index = this.panes.length;
      }
      item.index = index;
      this.panes.splice(index, 0, item);
    },

    getItemIndex(item) {
      return this.panes.indexOf(item);
    },

    removeItem(item) {
      const panes = this.panes;
      const index = panes.indexOf(item);
      if (index > -1) {
        panes.splice(index, 1);
      }
    }
  }
};
</script>