<template>
  <div
    v-scroll="scroll"
    class="simple-grid"
    :class="{
      'simple-grid--full-height': fullHeight,
      'simple-grid--with-footer': withFooter,
      'simple-grid--border': border,
    }"
  >
    <div
      v-if="fixedFields.length > 0 || showRowId"
      ref="left"
      class="simple-grid__left"
    >
      <div class="simple-grid__head">
        <div
          v-if="showRowId"
          class="simple-grid__field simple-grid__field--first"
        ></div>
        <div
          v-for="field in fixedFields"
          :key="field.id"
          class="simple-grid__field"
        >
          <i
            class="simple-grid__field-icon"
            :class="fieldTypes[field.type].iconClass"
          ></i>
          {{ field.name }}
        </div>
      </div>
      <div class="simple-grid__body">
        <div
          v-for="row in rows"
          :key="row.id"
          class="simple-grid__row"
          :class="{
            'simple-grid__row--hover':
              showHoveredRow && currentHoveredRow === row.id,
            'simple-grid__row--disabled':
              !multiple && selectedRows.includes(row.id),
            'simple-grid__row--checked':
              multiple && selectedRows.includes(row.id),
          }"
          @click="$emit('row-click', row)"
          @mouseover="currentHoveredRow = row.id"
          @mouseleave="currentHoveredRow = null"
        >
          <div
            v-if="showRowId"
            class="simple-grid__cell simple-grid__cell--first"
          >
            {{ row.id }}
            <div
              v-if="multiple"
              v-show="
                currentHoveredRow === row.id || selectedRows.includes(row.id)
              "
              class="simple-grid__cell-checkbox"
            >
              <Checkbox :checked="selectedRows.includes(row.id)"></Checkbox>
            </div>
          </div>
          <div
            v-for="field in fixedFields"
            :key="field.id"
            class="simple-grid__cell"
          >
            <SimpleGridField :field="field" :row="row" />
          </div>
        </div>
        <div
          v-if="canAddRow"
          class="simple-grid__row"
          :class="{
            'simple-grid__row--hover': showHoveredRow && addRowHover,
          }"
          @mouseover="addRowHover = true"
          @mouseleave="addRowHover = false"
          @click="$emit('add-row')"
        >
          <a
            class="simple-grid__cell simple-grid__cell--single simple-grid__add-row"
          >
            <i class="iconoir-plus" />
          </a>
        </div>
        <div v-if="withFooter" class="simple-grid__foot">
          <slot name="footLeft"></slot>
        </div>
      </div>
    </div>
    <div class="simple-grid__right-scrollbar-wrapper">
      <Scrollbars
        ref="scrollbars"
        horizontal="getHorizontalScrollbarElement"
        @horizontal="horizontalScroll"
      ></Scrollbars>
      <div ref="right" class="simple-grid__right-wrapper">
        <div class="simple-grid__right">
          <div class="simple-grid__head">
            <div
              v-for="field in fields"
              :key="field.id"
              class="simple-grid__field"
            >
              <i
                class="simple-grid__field-icon"
                :class="fieldTypes[field.type].iconClass"
              ></i>
              {{ field.name }}
            </div>
          </div>
          <div class="simple-grid__body">
            <div
              v-for="row in rows"
              :key="row.id"
              class="simple-grid__row"
              :class="{
                'simple-grid__row--hover':
                  showHoveredRow && currentHoveredRow === row.id,
                'simple-grid__row--disabled':
                  !multiple && selectedRows.includes(row.id),
                'simple-grid__row--checked':
                  multiple && selectedRows.includes(row.id),
              }"
              @click="$emit('row-click', row)"
              @mouseover="currentHoveredRow = row.id"
              @mouseleave="currentHoveredRow = null"
            >
              <div
                v-for="field in fields"
                :key="field.id"
                class="simple-grid__cell"
              >
                <SimpleGridField :field="field" :row="row" />
              </div>
            </div>
            <div
              v-if="canAddRow"
              class="simple-grid__row"
              :class="{
                'simple-grid__row--hover': showHoveredRow && addRowHover,
              }"
              @mouseover="addRowHover = true"
              @mouseleave="addRowHover = false"
              @click="$emit('add-row')"
            >
              <div class="simple-grid__cell simple-grid__cell--single"></div>
            </div>
            <div v-if="withFooter" class="simple-grid__foot"></div>
          </div>
        </div>
      </div>
      <div v-if="withFooter" class="simple-grid__right-wrapper-footer"></div>
    </div>
  </div>
</template>

<script>
import SimpleGridField from './SimpleGridField'
import _ from 'lodash'
export default {
  name: 'SimpleGrid',
  components: { SimpleGridField },
  props: {
    rows: {
      type: Array,
      required: true,
    },
    fixedFields: {
      type: Array,
      required: false,
      default: () => [],
    },
    fields: {
      type: Array,
      required: true,
    },
    selectedRows: {
      type: Array,
      required: false,
      default: () => [],
    },
    showHoveredRow: {
      type: Boolean,
      required: false,
      default: false,
    },
    canAddRow: {
      type: Boolean,
      required: false,
      default: false,
    },
    showRowId: {
      type: Boolean,
      required: false,
      default: false,
    },
    fullHeight: {
      type: Boolean,
      required: false,
      default: false,
    },
    withFooter: {
      type: Boolean,
      required: false,
      default: false,
    },
    border: {
      type: Boolean,
      required: false,
      default: false,
    },
    multiple: {
      type: Boolean,
      required: false,
      default: false,
    },
  },
  data() {
    return { addRowHover: false, currentHoveredRow: null }
  },
  computed: {
    fieldTypes() {
      return this.$registry.getAll('field')
    },
  },
  mounted() {
    const keydownEvent = (event) => {
      if (
        // If we allow row hovering, we also want to allow keyboard navigation.
        this.showHoveredRow &&
        // Check if the user has hit either of the keys we care about. If not,
        // ignore.
        (event.key === 'ArrowUp' || event.key === 'ArrowDown')
      ) {
        // Prevent scrolling up and down while pressing the up and down key.
        event.stopPropagation()
        event.preventDefault()
        this.handleUpAndDownArrowPress(event)
      }
      // Allow the Enter key to select the value that is currently being hovered
      // over.
      if (
        this.showHoveredRow &&
        this.currentHoveredRow &&
        event.key === 'Enter'
      ) {
        event.preventDefault()
        event.stopPropagation()
        const row = this.rows.find((row) => row.id === this.currentHoveredRow)
        if (row) {
          this.$emit('row-click', row)
        }
      }
    }
    document.body.addEventListener('keydown', keydownEvent)
    this.$once('hide', () => {
      document.body.removeEventListener('keydown', keydownEvent)
    })
  },
  methods: {
    getHorizontalScrollbarElement() {
      return this.$refs.right
    },
    /**
     * Event that is called when the users does any form of scrolling on the whole grid
     * surface.
     */
    scroll(pixelY, pixelX) {
      const left = this.$refs.right.scrollLeft + pixelX
      this.horizontalScroll(left)
      this.$refs.scrollbars.update()
      return pixelY !== 0
    },
    horizontalScroll(left) {
      this.$refs.right.scrollLeft = left
    },
    handleUpAndDownArrowPress(event) {
      const isArrowUp = event.key === 'ArrowUp'
      let index = this.rows.findIndex((item) =>
        _.isEqual(item.id, this.currentHoveredRow)
      )
      if (index === -1) {
        // Selects the first or last row if no row was hovered before.
        index = isArrowUp ? this.rows.length - 1 : 0
      } else {
        // Selects the previous or next row if a row was in hover state before.
        index = isArrowUp ? index - 1 : index + 1
      }
      const next = this.rows[index]
      if (next) {
        this.currentHoveredRow = next.id
      }
    },
  },
}
</script>