<template lang="html">
  <nav class="v-pager {{ theme }}">

    <!-- currentPage and totalPages -->
    <div class="other-info" v-if="showOtherInfo">
      <span>{{ currentPage }}</span> / <span>{{ totalPages }}</span>
    </div>

    <ul>

      <!-- previous page -->
      <li
        v-bind:class="{'disabled': disablePreviousPage, 'hide': hidePreviousBtn}"
        @click="go(currentPage - 1)">
        <a class="previous" href="javascript:void(0);">
          <span>{{ previousLabel }}</span>
        </a>
      </li>

      <!-- page list -->
      <li
        v-for="page in pageList"
        class="page-item"
        v-bind:class="{'active': page.label == currentPage}"
        @click="go(page.label)">
        <span
          class="loading"
          v-bind:class="{'hide': !page.isLoading}">
          <span class="loading1 child"></span>
          <span class="loading2 child"></span>
          <span class="loading3 child"></span>
          <span class="loading4 child"></span>
          <span class="loading5 child"></span>
          <span class="loading6 child"></span>
          <span class="loading7 child"></span>
          <span class="loading8 child"></span>
          <span class="loading9 child"></span>
          <span class="loading10 child"></span>
          <span class="loading11 child"></span>
          <span class="loading12 child"></span>
        </span>
        <a
          href="javascript:void(0);"
          v-bind:class="{'hide': page.isLoading}">
          {{ page.label }}
        </a>
      </li>

      <!-- next page -->
      <li
        v-bind:class="{'disabled': disableNextPage, 'hide': hideNextBtn}"
        @click="go(currentPage + 1)">
        <a class="next" href="javascript:void(0);">
          <span>{{ nextLabel }}</span>
        </a>
      </li>
    </ul>

    <!-- pager tool such as move to target page -->
    <div class="pager-tools" v-if="showTools">
      <input type="number" name="name" value="" class="pager-input" v-model="movePageNumber">
      <button
        class="pager-btn"
        v-bind:class="{ 'disabled': disableGoToPage }"
        @click="moveToTargetPage(movePageNumber)">go</button>
    </div>
  </nav>
</template>

<script>
export default {
  props: {
    totalPages: {
      type: Number,
      required: true,
      validator(val) {
        return val > 0;
      }
    },
    visiablePages: {
      type: Number,
      required: true,
      validator(val) {
        return val > 0;
      }
    },
    pageClick: {
      type: Function,
      required: true
    },
    currentPage: {
      type: Number,
      default: 1
    },
    theme: {
      type: String,
      default: ''
    },
    previousLabel: {
      type: String,
      default: 'Previous'
    },
    nextLabel: {
      type: String,
      default: 'Next'
    },
    defaultHideNextStepBtn: {
      type: Boolean,
      default: false
    },
    showOtherInfo: {
      type: Boolean,
      default: false
    },
    showTools: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      pageList: [{isLoading: false, label: 1}],
      disablePreviousPage: false,
      disableNextPage: false,
      disableGoToPage: false,
      hidePreviousBtn: false,
      hideNextBtn: false,
      isLoading: false, // if page is loading, prevent click event
      movePageNumber: 1 // page user want to go
    };
  },
  watch: {

    /**
     * watching user enter, enable or disable "go to page"
     * @param {String} val - new value of movePageNumber
     */
    movePageNumber(val) {
      let self = this, page = Number(val);

      if(page < 1 || page > self.totalPages) {
        self.disableGoToPage = true;

      } else {
        self.disableGoToPage = false;
      }
    }
  },
  ready() {
    let self = this;

    // set default value when props'validator can't check
    self.currentPage =
      self.currentPage > self.totalPages ?
      self.totalPages :
      self.currentPage;

    self.visiablePages =
      self.visiablePages > self.totalPages ?
      self.totalPages :
      self.visiablePages;

    // when init component, calculate visiable page list
    self.pageList = self.calcVisiablePages(self.currentPage).visiablePages;

    self.calcHideNextStepBtn();
  },
  methods: {

    /**
     * accroding current page calaculate visiable page list
     * @param {Number} currentPage - current page user select
     * @returns {Object} - current page and visiable page list array
     */
    calcVisiablePages(currentPage) {
      let half, start, end, pages = [], self = this;

      // get the visiable page list array start item and end item
      half = Math.floor(self.visiablePages / 2);
      start = currentPage - half + 1 - self.visiablePages % 2;
      end = currentPage + half;

      // ensure start item >= 1, and end item <= totalPages
      if(start <= 0) {
        start = 1;
        end = self.visiablePages;
      }
      if(end > self.totalPages) {
        start = self.totalPages - self.visiablePages + 1;
        end = self.totalPages;
      }

      for(let i = start; i <= end; i++) {
        pages.push({
          isLoading: false,
          label: i
        });
      }

      return {
        currentPage: currentPage,
        visiablePages: pages
      };
    },

    /**
     * user select to detail page
     * @param {Number} page - the page number which user selectd
     */
    go(page) {
      let self = this;

      if(self.isLoading) {
        return;
      }

      // if page is the edge of array, disable previous btn or next btn
      // or page equal current page
      if(page < 1 || page == self.currentPage || page > self.totalPages) {
        return;
      }

      // enable previous and next button
      self.disablePreviousPage = false;
      self.disableNextPage = false;

      // active current page and recalculate visiable page list
      self.currentPage = page;
      self.pageList = self.calcVisiablePages(page).visiablePages;

      if(page == 1) {
        self.disablePreviousPage = true;
      }

      if(page == self.totalPages) {
        self.disableNextPage = true;
      }

      self.activePageLoading(page);
      self.calcHideNextStepBtn();
      self.pageClick(self.removePageLoading);
    },

    /**
     *  if user set 'defaultHideNextStepBtn' true, calaculate hide previous button or hide next button
     */
    calcHideNextStepBtn() {
      let self = this;

      if(self.defaultHideNextStepBtn == true) {

        if(self.currentPage == 1) {
          self.hidePreviousBtn = true;
        } else {
          self.hidePreviousBtn = false;
        }

        if(self.currentPage == self.totalPages) {
          self.hideNextBtn = true;
        } else {
          self.hideNextBtn = false;
        }
      }
    },

    /**
     * active target page loading
     * @param {Number} page - the page which want to active loading
     */
    activePageLoading(page) {
      let self = this;

      self.isLoading = true;

      for(let list of self.pageList) {
        if(page === list.label) {
          list.isLoading = true;
        }
      }
    },

    /**
     * remove loading
     * @param {Number} page - the page which want to remove loading
     */
    removePageLoading() {
      let self = this;

      self.isLoading = false;

      for(let list of self.pageList) {
        list.isLoading = false;
      }
    },

    /**
     * move to target page
     * @param {Number} page - the page user want to go
     */
    moveToTargetPage(page) {
      let self = this;

      if(self.disableGoToPage) {
        return;
      }

      self.go(Number(page));
    }
  }
};
</script>

<style lang="less" scoped>

// pager button style
.v-pager .pager-btn {
  background-color: #fff;
  border: 1px solid #ccc;
  border-radius: 4px;
  color: #333;
  cursor: pointer;
  display: inline-block;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.42857143;
  margin-bottom: 0;
  outline: none;
  padding: 6px 12px;
  text-align: center;
  white-space: nowrap;
  vertical-align: middle;

  &:hover {
    background-color: #e6e6e6;
    border-color: #adadad;
    color: #333;
  }

  &.disabled:hover {
    color: #777;
    cursor: not-allowed;
    background-color: #fff;
    border-color: #ddd;
  }
}

// pager input style
.v-pager .pager-input {
  box-sizing: border-box;
  background-color: #fff;
  background-image: none;
  border: 1px solid #ccc;
  border-radius: 4px;
  color: #555;
  font-size: 14px;
  height: 34px;
  line-height: 1.42857143;
  outline: none;
  padding: 6px 12px;
  width: 70px;
}

// use bootstrap's pagination style as default theme
.v-pager.default {

  // other info
  .other-info {
    color: #333;
    float: left;
    font-size: 13px;
    height: 34px;
    line-height: 34px;
    margin-right: 10px
  }

  // pager
  > ul {
    display: inline-block;
    font: 14px "Helvetica Neue",Helvetica,Arial,sans-serif;
    float: left;
    margin: 0;
    padding-left: 0;
    border-radius: 4px;

    > li {
      display: inline;

      > a,
      > span {
        position: relative;
        float: left;
        padding: 6px 12px;
        margin-left: -1px;
        line-height: 1.42857143;
        color: #337ab7;
        text-decoration: none;
        background-color: #fff;
        border: 1px solid #ddd;
      }

      &:first-child > a,
      &:first-child > span {
        margin-left: 0;
        border-top-left-radius: 4px;
        border-bottom-left-radius: 4px;
      }

      &:last-child > a,
      &:last-child > span {
        border-top-right-radius: 4px;
        border-bottom-right-radius: 4px;
      }

      > a:hover,
      > span:hover {
        z-index: 2;
        color: #23527c;
        background-color: #eee;
        border-color: #ddd;
      }
    }

    > .active > a,
    > .active > span,
    > .active > a:hover,
    > .active > span:hover {
      z-index: 3;
      color: #fff;
      cursor: default;
      background-color: #337ab7;
      border-color: #337ab7;
    }

    > .disabled > span,
    > .disabled > span:hover,
    > .disabled > a,
    > .disabled > a:hover {
      color: #777;
      cursor: not-allowed;
      background-color: #fff;
      border-color: #ddd;
    }
  }

  // pager tool
  .pager-tools {
    float: left;
    margin-left: 10px;
  }
}

// mini theme, only have previous btn and next btn
.v-pager.mini {

  // other info
  .other-info {
    color: #333;
    float: left;
    font-size: 13px;
    height: 34px;
    line-height: 34px;
    margin-right: 10px
  }

  // pager
  > ul {
    display: inline-block;
    font: 14px "Helvetica Neue",Helvetica,Arial,sans-serif;
    float: left;
    margin: 0;
    padding-left: 0;
    border-radius: 4px;

    > li {
      display: inline;

      > a,
      > span {
        position: relative;
        float: left;
        padding: 6px 12px;
        margin-left: -1px;
        line-height: 1.42857143;
        color: #337ab7;
        text-decoration: none;
        background-color: #fff;
        border: 1px solid #ddd;
      }

      &:first-child > a,
      &:first-child > span {
        margin-left: 0;
        border-top-left-radius: 4px;
        border-bottom-left-radius: 4px;
      }

      &:last-child > a,
      &:last-child > span {
        border-top-right-radius: 4px;
        border-bottom-right-radius: 4px;
      }

      > a:hover,
      > span:hover {
        z-index: 2;
        color: #23527c;
        background-color: #eee;
        border-color: #ddd;
      }
    }

    > .active > a,
    > .active > span,
    > .active > a:hover,
    > .active > span:hover {
      z-index: 3;
      color: #fff;
      cursor: default;
      background-color: #337ab7;
      border-color: #337ab7;
    }

    > .disabled > span,
    > .disabled > span:hover,
    > .disabled > a,
    > .disabled > a:hover {
      color: #777;
      cursor: not-allowed;
      background-color: #fff;
      border-color: #ddd;
    }
    .page-item {
      display: none;
    }
  }

  // pager tool
  .pager-tools {
    float: left;
    margin-left: 10px;
  }
}

// hide element
nav.v-pager ul .hide {
  display: none;
}

// using spinkit loading animate
.loading {
  box-sizing: border-box;
  height: 34px;
  margin: 0 auto;
  position: relative;
  width: 34px;

  .child {
    height: 50%;
    left: 50%;
    margin-left: -8px;
    margin-top: -8px;
    position: absolute;
    top: 50%;
    width: 50%;

    &:before {
      background-color: #fff;
      border-radius: 100%;
      content: '';
      display: block;
      height: 15%;
      margin: 0 auto;
      width: 15%;
      -webkit-animation: loadingBounceDelay 1.2s infinite ease-in-out both;
              animation: loadingBounceDelay 1.2s infinite ease-in-out both;
    }
  }

  .loading2 {
    -webkit-transform: rotate(30deg);
        -ms-transform: rotate(30deg);
            transform: rotate(30deg);
  }
  .loading3 {
    -webkit-transform: rotate(60deg);
        -ms-transform: rotate(60deg);
            transform: rotate(60deg);
  }
  .loading4 {
    -webkit-transform: rotate(90deg);
        -ms-transform: rotate(90deg);
            transform: rotate(90deg);
  }
  .loading5 {
    -webkit-transform: rotate(120deg);
        -ms-transform: rotate(120deg);
            transform: rotate(120deg);
  }
  .loading6 {
    -webkit-transform: rotate(150deg);
        -ms-transform: rotate(150deg);
            transform: rotate(150deg);
  }
  .loading7 {
    -webkit-transform: rotate(180deg);
        -ms-transform: rotate(180deg);
            transform: rotate(180deg);
  }
  .loading8 {
    -webkit-transform: rotate(210deg);
        -ms-transform: rotate(210deg);
            transform: rotate(210deg);
  }
  .loading9 {
    -webkit-transform: rotate(240deg);
        -ms-transform: rotate(240deg);
            transform: rotate(240deg);
  }
  .loading10 {
    -webkit-transform: rotate(270deg);
        -ms-transform: rotate(270deg);
            transform: rotate(270deg);
  }
  .loading11 {
    -webkit-transform: rotate(300deg);
        -ms-transform: rotate(300deg);
            transform: rotate(300deg);
  }
  .loading12 {
    -webkit-transform: rotate(330deg);
        -ms-transform: rotate(330deg);
            transform: rotate(330deg);
  }
  .loading2:before {
    -webkit-animation-delay: -1.1s;
            animation-delay: -1.1s;
  }
  .loading3:before {
    -webkit-animation-delay: -1s;
            animation-delay: -1s;
  }
  .loading4:before {
    -webkit-animation-delay: -0.9s;
            animation-delay: -0.9s;
  }
  .loading5:before {
    -webkit-animation-delay: -0.8s;
            animation-delay: -0.8s;
  }
  .loading6:before {
    -webkit-animation-delay: -0.7s;
            animation-delay: -0.7s;
  }
  .loading7:before {
    -webkit-animation-delay: -0.6s;
            animation-delay: -0.6s;
  }
  .loading8:before {
    -webkit-animation-delay: -0.5s;
            animation-delay: -0.5s;
  }
  .loading9:before {
    -webkit-animation-delay: -0.4s;
            animation-delay: -0.4s;
  }
  .loading10:before {
    -webkit-animation-delay: -0.3s;
            animation-delay: -0.3s;
  }
  .loading11:before {
    -webkit-animation-delay: -0.2s;
            animation-delay: -0.2s;
  }
  .loading12:before {
    -webkit-animation-delay: -0.1s;
            animation-delay: -0.1s;
  }
}

@-webkit-keyframes loadingBounceDelay {
  0%, 80%, 100% {
    -webkit-transform: scale(0);
            transform: scale(0);
  } 40% {
    -webkit-transform: scale(1);
            transform: scale(1);
  }
}

@keyframes loadingBounceDelay {
  0%, 80%, 100% {
    -webkit-transform: scale(0);
            transform: scale(0);
  } 40% {
    -webkit-transform: scale(1);
            transform: scale(1);
  }
}
</style>
