<template>
  <ul v-bind:class="[componentClass]" v-on:keydown="onKeyDown" tabindex="0">
    <li
      v-if="state === 0 && showDataProgress"
      v-bind:class="[slotClasses, slotSubClass, { 'c-progress': true }]"
    >
      <slot v-if="$scopedSlots.progress" name="progress"></slot>
      <template v-else>
        <c-data-progress></c-data-progress>
      </template>
    </li>
    <li v-if="state === -1" v-bind:class="[slotClasses, slotSubClass, { 'c-errors': true }]">
      <slot v-if="$scopedSlots.errors" name="errors"></slot>
      <template v-else>
        <c-data-errors></c-data-errors>
      </template>
    </li>
    <template v-if="isSlotItemRendered">
      <li
        v-for="(row, rowIndex) in rows"
        :key="rowIndex"
        v-on:click="onClickRow(row)"
        v-on:dblclick="onDblClickRow(row)"
        :ref="row == currentRow ? 'active' : undefined"
        :style="{ 'width': slotWidth + 'px'}"
        v-bind:class="[
          slotClasses,
          slotSubClass,
          { 'c-active': row == currentRow },
          { 'c-selected': isSelected(row) }
        ]"
      >
        <c-rowcheck
          v-if="showRowCheck"
          :appWindowIdent="appWindowIdent"
          :dataSetIdent="dataSetIdent"
          :rowIndex="rowIndex"
          :row="row"
        ></c-rowcheck>
        <slot v-bind:name="slotName" v-bind:row="row" v-bind:where="where" ></slot>
      </li>
    </template>
    <li
      v-if="state === 1 && rowsIsEmpty && showDataEmpty"
      v-bind:class="[slotClasses, slotSubClass, { 'c-empty': true }]"
    >
      <slot v-if="$scopedSlots.empty" name="empty"></slot>
      <template v-else>
        <c-data-empty></c-data-empty>
      </template>
    </li>
  </ul>
</template>

<script>
import base from "./c-base"
import { mapGetters, mapActions } from "vuex"
import cRowcheck from "./c-rowcheck"
import cDataProgress from "./c-data-progress"
import cDataErrors from "./c-data-errors"
import cDataEmpty from "./c-data-empty"

export default {
  extends: base,
  components: {
    "c-rowcheck": cRowcheck,
    "c-data-progress": cDataProgress,
    "c-data-errors": cDataErrors,
    "c-data-empty": cDataEmpty
  },
  data: function() {
    return {
      componentClass: "c-list",
      slotWidth: null
    }
  },
  props: {
    slotNameAppWindowIdent: {
      type: String,
      default: null
    },
    slotNameDataSetIdent: {
      type: String,
      default: null
    },
    slotNameSourceKind: {
      type: String,
      default: null
    },
    slotNameDataFieldIdent: {
      type: String,
      default: null
    },
    slotClasses: {
      type: String,
      default: null
    },
    slotSubClassPrefix: {
      type: String,
      default: null
    },
    slotOptimalWidth: {
      type: Number,
      default: null
    },
    addSlotSubClass: {
      type: Boolean,
      default: false
    },
    showRowCheck: {
      type: Boolean,
      default: true
    },
    setLookupOnClick: {
      type: Boolean,
      default: false
    },
    hideWhenRowsCountLower: {
      type: Number,
      default: -1
    },
    showDataProgress: {
      type: Boolean,
      default: true
    },
    showDataEmpty: {
      type: Boolean,
      default: true
    }
  },
  computed: {
    ...mapGetters("csAppWindowsUtils", [
      "getDataSet",
      "getDataSetIdentDataFieldValue"
    ]),
    slotName: function() {
      return (
        this.getDataSetIdentDataFieldValue(
          this.slotNameAppWindowIdent,
          this.slotNameDataSetIdent,
          this.slotNameSourceKind,
          this.slotNameDataFieldIdent
        ) || "item"
      )
    },
    slotSubClass: function() {
      return this.addSlotSubClass && this.slotSubClassPrefix
        ? this.slotSubClassPrefix + this.slotName
        : null
    },
    forceFocus: function() {
      return this.dataSet ? this.dataSet.forceFocus : false
    },
    currentRowIndex: function(){
      return this.dataSet ? this.dataSet.currentRowIndex : -1
    },
    isSlotItemRendered: function() {
      return (
        this.state === 1
        && !this.rowsIsEmpty
        && (this.rowsCount > 0 ? this.rowsCount : this.dataSet.rows.length) >= this.hideWhenRowsCountLower
      )
    }
  },
  methods: {
    ...mapActions("csAppWindowsUtils", [
      "setDataSetPrevRow",
      "setDataSetNextRow",
      "setLookupDefSelection",
      "setDataSetForceFocus"
    ]),
    onClickRow: async function(row) {
      await this.setDataSetCurrentRow({
        appWindowIdent: this.appWindowIdent,
        dataSet: this.dataSet,
        row: row
      })
      if (this.setLookupOnClick)
        await this.setLookupDefSelection({
          appWindowIdent: this.appWindowIdent
        })
    },
    onDblClickRow: async function(row) {
      await this.setDataSetCurrentRow({
        appWindowIdent: this.appWindowIdent,
        dataSet: this.dataSet,
        row: row
      })
      await this.setLookupDefSelection({ appWindowIdent: this.appWindowIdent })
    },
    onKeyDown: function(evt) {
      if (evt.key === "ArrowDown") {
        this.setDataSetNextRow(this.dataSet)
      }
      if (evt.key === "ArrowUp") {
        this.setDataSetPrevRow(this.dataSet)
      }
      if (evt.key === "Enter") {
        this.setLookupDefSelection({ appWindowIdent: this.appWindowIdent })
      }
    },
    handleResize: function() {
      let w = this.$el.clientWidth
      let a = w / this.slotOptimalWidth
      let f = Math.floor(a) 
      if (f == 0) this.slotWidth = w
      if (f >= 1.00) this.slotWidth = w / f
    },
    isSelected: function (row) {
      return this.dataSet.keyFieldsIdents &&
       this.dataSet.keyFieldsIdents.length > 0 && 
       this.dataSet.selectedRows.find(item => {
        let result = true
        this.dataSet.keyFieldsIdents.forEach(keyField => {
          result = result && row[keyField.dataFieldIdent] === item[keyField.dataFieldIdent]
        })
        return result
        }) ? true : false
    }
  },
  watch: {
    currentRowIndex: function(val, oldval) {
      if(!this.isSlotItemRendered)
        return
      if (!this.$refs.active || !this.$refs.active[0])
        return
      let oldItem = this.$refs.active[0]
      let containerDomRect = this.$el.getBoundingClientRect()
      if (val > oldval) {
        let item = oldItem.nextElementSibling
        if (item != null) {
          let itemDomRect = item.getBoundingClientRect()
          let scrollTopDelta = itemDomRect.bottom > containerDomRect.bottom ? itemDomRect.bottom - containerDomRect.bottom : 0
          this.$el.scrollTop += scrollTopDelta
          let scrollLeftDelta = itemDomRect.right > containerDomRect.right ? itemDomRect.right - containerDomRect.right : 0
          this.$el.scrollLeft += scrollLeftDelta
        }
      }
      else {
        let item = oldItem.previousElementSibling
        if (item != null) {
          let itemDomRect = item.getBoundingClientRect()
          let itemOutlineWidth = parseFloat(getComputedStyle(item).outlineWidth)
          let scrollTopDelta = itemDomRect.top < containerDomRect.top ? itemDomRect.top - containerDomRect.top - itemOutlineWidth : 0
          this.$el.scrollTop += scrollTopDelta
          let scrollLeftDelta = itemDomRect.left < containerDomRect.left ? itemDomRect.left - containerDomRect.left - itemOutlineWidth: 0
          this.$el.scrollLeft += scrollLeftDelta
        }
      }
    }
  },
  mounted: function() {
    if(this.slotOptimalWidth) {
      window.addEventListener('resize', this.handleResize)
      this.handleResize()
    }
  },
  beforeDestroy: function() {
    if(this.slotOptimalWidth) {
      window.removeEventListener('resize', this.handleResize)
    }
  }
}
</script>
