<template>
  <div v-bind:class="[componentClass]" v-on:keyup="onKeyUp" tabindex="0">
    <div class="c-settings-content" v-if="settingsVisible">
      <div class="c-settings-tabs">
        <div
          class="c-settings-tab"
          :class="{ 'c-active': settingsTabSelected === 1 }"
          v-on:click="settingsTabSelected = 1"
        >Układ danych</div>
        <div
          class="c-settings-tab"
          :class="{ 'c-active': settingsTabSelected === 2 }"
          v-on:click="settingsTabSelected = 2"
        >Eksporty</div>
      </div>
      <div class="c-settings-btn-close" v-on:click="settingsVisibleChange">Zamknij</div>
      <div class="c-settings-layout-area" v-if="settingsTabSelected === 1">
        <div class="c-settings-cols">
          <div>
            <div>Kolumny</div>
            <div
              class="c-btn c-settings-action"
              title="Zaznacz wszystko"
              v-on:click="setColFieldsVisibilityAll($event, 1)"
            >&#xe921;</div>
            <div
              class="c-btn c-settings-action"
              title="Odznacz wszystko"
              v-on:click="setColFieldsVisibilityAll($event, 0)"
            >&#xe920;</div>
            <div
              class="c-btn c-settings-action"
              title="Odwróć zaznaczenie"
              v-on:click="reverseColFieldsVisibility()"
            >&#xe922;</div>
            <div
              class="c-btn c-up-btn"
              v-on:click="colFieldUp()"
              v-bind:class="{ 'c-inactive': isFirstColField }"
            >&#xe91c;</div>
            <div
              class="c-btn"
              v-on:click="colFieldDown()"
              v-bind:class="{ 'c-inactive': isLastColField }"
            >&#xe91b;</div>
          </div>
          <div class="c-settings-list" @dragover.prevent @drop.prevent="colFieldDropOnList">
            <div
              v-for="colField in colFields"
              :key="colField.dataFieldIdent"
              draggable="true"
              :class="{ 'c-active': colField === currentColField }"
              @click="onClickColField($event, colField)"
              @dragstart="colFieldDragStart($event, colField)"
              @dragend="colFieldDragEnd"
              @drop.prevent.stop="colFieldDrop($event, colField)"
            >
              <input
                type="checkbox"
                :id="colField.dataFieldIdent"
                :checked="colField.isVisible"
                v-on:change="onColFieldVisibleChange($event, colField)"
              />
              <label class="c-checkbox" :for="colField.dataFieldIdent" />
              <div>{{ colField.dataFieldColTranslatedDesc }}</div>
            </div>
          </div>
        </div>
        <div class="c-settings-actions-vertical">
          <div
            class="c-right-btn c-btn"
            v-on:click="addSortColField()"
            v-bind:class="{ 'c-inactive': isSortColFieldExists }"
          >&#xe919;</div>
          <div
            class="c-left-btn c-btn"
            v-on:click="removeSortColField()"
            v-bind:class="{ 'c-inactive': sortColFields.length <= 0 }"
          >&#xe91a;</div>
        </div>
        <div class="c-settings-sortings">
          <div>
            <div>Sortowanie</div>
            <div
              class="c-up-btn c-btn"
              v-on:click="sortColFieldUp()"
              v-bind:class="{ 'c-inactive': isFirstSortColField }"
            >&#xe91c;</div>
            <div
              class="c-down-btn c-btn"
              v-on:click="sortColFieldDown()"
              v-bind:class="{ 'c-inactive': isLastSortColField }"
            >&#xe91b;</div>
          </div>
          <div class="c-settings-list" @dragover.prevent @drop.prevent="sortColFieldDropOnList">
            <div
              v-for="colField in sortColFields"
              :key="colField.dataFieldIdent"
              draggable="true"
              :class="{ 'c-active': colField === currentSortColField }"
              @click="onClickSortColField($event, colField)"
              @dragstart="sortColFieldDragStart($event, colField)"
              @dragend="sortColFieldDragEnd"
              @drop.prevent.stop="sortColFieldDrop($event, colField)"
            >
              <div>{{ colField.dataFieldColTranslatedDesc }}</div>
              <div
                class="c-btn c-sorting-button"
                v-if="colField.isDesc === 0"
                @click="setSortColFieldDesc($event, colField)"
              >&#xe91c;</div>
              <div
                class="c-btn c-sorting-button"
                v-else
                @click="setSortColFieldAsc($event, colField)"
              >&#xe91b;</div>
            </div>
          </div>
        </div>
      </div>
      <div class="c-settings-exports-area" v-if="settingsTabSelected === 2">
        <div class="c-settings-export">
          <c-btna
            style="width: 180px;"
            :appWindowIdent="appWindowIdent"
            :dataSetIdent="dataSetIdent"
            actionIdent="exportXLSX"
          />
        </div>
      </div>
      <div class="c-settings-footer">
        <div class="c-settings-btn-refresh c-btna ManageU" v-on:click="clear">Wyczyść</div>
        <div class="c-settings-btn-refresh c-btna ManageI" v-on:click="refresh">Odśwież</div>
        <div class="c-settings-btn-refresh c-btna ManageD" v-on:click="settingsVisibleChange">Zamknij</div>
      </div>
    </div>
    <div
      class="c-header"
      v-if="showHeaders"
      @drop.prevent="colFieldDropOnHeader"
      @dragover.prevent
    >
      <div
        v-if="showRowCheck || additionalInfo"
        class="c-settings"
        :style="{ width: rowsHeadersWidth  + 'px' }"
        @drop.prevent.stop="colFieldDropOnFirst"
      >
        <div v-if="showRowCheck" :style="{'width': rowHeaderDefWidth + 'px', 'margin-left': rowsHeadersWidth - rowHeaderDefWidth + 'px'}">
          <input type="checkbox" v-on:change="onSelectedRowHeaderValueChange" :id="componentId" />
          <label class="c-checkbox" :for="componentId" />
        </div>
      </div>
      <div class="c-cols-headers" ref="scrolledLeft">
        <table cellspacing="0">
          <colgroup>
            <col
              v-for="colField in visibleColFields"
              :key="colField.dataFieldIdent"
              :style="{ width: colField.width + 'px' }"
            />
          </colgroup>
          <thead>
            <tr v-for="n in 1" :key="n">
              <th
                v-for="(colField, i) in visibleColFields"
                :key="colField.dataFieldIdent"
                draggable="true"
                @click.exact="colFieldClick($event, getColField(colField.dataFieldIdent), getSortColField(colField.dataFieldIdent))"
                @click.shift="colFieldShiftClick($event, getColField(colField.dataFieldIdent), getSortColField(colField.dataFieldIdent))"
                @dragstart="colFieldDragStart($event, getColField(colField.dataFieldIdent))"
                @dragend="colFieldDragEnd"
                @drop.prevent.stop="colFieldDrop($event, getColField(colField.dataFieldIdent))"
                :class="[{'c-first-header': i === 0, 'c-last-header': i === visibleColFields.length - 1}, (colField.headerSlotName != null ? 'c-slot-' + colField.headerSlotName : null)]"
              >
                <div
                  v-if="i === 0 && showSettings"
                  class="c-settings-btn"
                  :style="{ height: colFieldsMaxHeight + 'px' }"
                  v-on:click.stop="settingsVisibleChange"
                >&#xe91f;</div>
                <div class="c-header-container">
                  <slot
                    v-if="colField.headerSlotName"
                    :name="colField.headerSlotName"
                    v-bind:value="colField"
                  >
                    Missing slot
                    <code>{{ colField.headerSlotName }}</code>
                  </slot>
                  <div v-else>{{ colField.dataFieldColTranslatedDesc }}</div>
                  <div
                    class="c-column-sorting"
                    v-if="getSortColFieldIsDesc(colField.dataFieldIdent) === 0"
                  >
                    <div>&#xe91e;</div>
                    {{ getSortColFieldOrd(colField.dataFieldIdent) }}
                  </div>
                  <div
                    class="c-column-sorting"
                    v-if="getSortColFieldIsDesc(colField.dataFieldIdent) === 1"
                  >
                    <div>&#xe91d;</div>
                    {{ getSortColFieldOrd(colField.dataFieldIdent) }}
                  </div>
                </div>
                <div
                  class="dragger"
                  :key="i"
                  @mousedown.prevent="resizeHeaderMouseDown($event, i)"
                  @click.stop
                  :style="{ height: colFieldsMaxHeight + 'px' }"
                />
              </th>
              <th class="c-top-right-dz"></th>
            </tr>
          </thead>
        </table>
      </div>
    </div>
    <div class="c-rows" v-if="state === 1 && !rowsIsEmpty">
      <div
        class="c-rows-headers"
        v-if="showRowCheck || additionalInfo"
        ref="scrolledTop"
        :style="{width: rowsHeadersWidth + 'px','min-width': rowsHeadersWidth + 'px'}"
      >
        <table cellspacing="0">
          <tbody>
            <template v-for="(row, rowIndex) in rows">
              <tr 
                :key="rowIndex"
                :class="{'c-additional-info-exp': additionalInfo && row._showAdditionalInfo === 1, 'c-active': row === currentRow }"
                v-on:click="onClickRow(row)"
              >
                <td
                  v-if="additionalInfo"
                  class="c-show-additional-info"
                  :style="{ width: rowHeaderDefWidth + 'px', height: rowColFieldsMaxHeight + 'px' }"
                >
                  <button
                    class="c-additional-info-btn" 
                    :class="{'c-show': row._showAdditionalInfo === 1}"
                    @click="showAdditionalInfo($event, row)"
                  >
                  </button>
                </td>
                <td
                  v-if="showRowCheck"
                  v-bind:class="['c-select-row', { 'c-active': row === currentRow }]"
                  :style="{ width: rowHeaderDefWidth + 'px', height: rowColFieldsMaxHeight + 'px' }"
                >
                  <c-rowcheck
                    :appWindowIdent="appWindowIdent"
                    :dataSetIdent="dataSetIdent"
                    :rowIndex="rowIndex"
                    :row="row"
                  ></c-rowcheck>
                </td>
              </tr>
              <tr
                v-if="additionalInfo && row && row._showAdditionalInfo === 1 && $scopedSlots.additionalInfo"
                :key="rowIndex + 'addInfo'"
                class="c-additional-info"
                :style="{height: row._additionalInfoHeight + 'px' }"
              >
                <td/>
              </tr>
            </template>
            <tr class="c-bootom-left-dz"></tr>
          </tbody>
        </table>
      </div>
      <div class="c-rows-data" @scroll="handleScroll" v-if="state === 1 && !rowsIsEmpty" ref="rowsData">
        <div
          class="c-rows-data-background"
          :style="{'padding-top': virtDataTop + 'px','padding-left': virtDataLeft + 'px','min-width': virtDataWidth + 'px','min-height': virtDataHeight + 'px'}"
        >
          <table cellspacing="0">
            <colgroup>
              <col
                v-for="colField in visibleColFields"
                :key="colField.key"
                :style="{ width: colField.width + 'px' }"
              />
            </colgroup>
            <tbody>
              <template v-for="(row, rowIndex) in virtRowsCount" >
                <tr
                  :key="rowIndex"
                  :style="{ height: rowColFieldsMaxHeight + 'px' }"
                  :class="{'c-additional-info-exp': additionalInfo && rows[rowShift + rowIndex]._showAdditionalInfo === 1, 'c-active': rows[rowShift + rowIndex] == currentRow}"
                >
                  <td
                    v-for="colField in visibleColFields"
                    :key="colField.key"
                    v-bind:class="[getFormatTypeClass(colField.formatType),{ 'c-active': rows[rowShift + rowIndex] == currentRow },
                      (colField.slotName != null ? 'c-slot-' + colField.slotName : null)]"
                    v-on:click="onClickRow(rows[rowShift + rowIndex])"
                    v-on:dblclick="onDblClickRow(row)"
                  >
                    <slot
                      v-if="colField.slotName"
                      :name="colField.slotName"
                      v-bind:row="rows[rowShift + rowIndex]"
                    />
                    <template v-else>
                      {{formatValue(rows[rowShift + rowIndex][colField.dataFieldIdent],colField.formatType)}}
                    </template>
                  </td>
                </tr>
                <tr
                  v-if="additionalInfo && rows[rowShift + rowIndex]._showAdditionalInfo === 1 && $scopedSlots.additionalInfo"
                  :key="rowIndex + 'addInfo'"
                  class="c-additional-info"
                >
                  <td :colspan="visibleColFields.length">
                    <slot
                      name="additionalInfo"
                      :row="rows[rowShift + rowIndex]"
                    />
                  </td>
                </tr>
              </template>
            </tbody>
          </table>
        </div>
      </div>
       <div
        class="c-rows-footers"
        v-if="rowFooterAction"
        ref="scrolledTop"
        :style="{width: 0 + 'px','min-width': 0 + 'px'}"
      >
        <table cellspacing="0">
          <tbody>
            <tr 
              v-for="(row, rowIndex) in rows" :key="row.key" 
              :class="{'c-additional-info-exp': additionalInfo && rows[rowShift + rowIndex]._showAdditionalInfo === 1, 'c-active': rows[rowShift + rowIndex] == currentRow}"
            >
              <td
                v-bind:class="['c-select-row', { 'c-active': row === currentRow }]"
                :style="{ width: 23 + 'px', height: rowColFieldsMaxHeight + 'px' }"
              >
                <c-btna
                  class="c-btn-row-footer-action"
                  :appWindowIdent="appWindowIdent"
                  :dataSetIdent="dataSetIdent"
                  :action-ident="rowFooterAction"
                  source-kind="rows"
                  :row="row"
                  :showLabel="false"
                ></c-btna>
              </td>
            </tr>
            <tr class="c-bootom-left-dz"></tr>
          </tbody>
        </table>
      </div>
    </div>
    <div 
      class="c-aggrs" 
      v-if="state === 1 && hasAggrFields4Display" 
      :style="{ height: aggrsDefHeight + 'px', 'margin-top': -aggrsDefHeight - rowsScrollBarHeight + 'px', 'margin-right': rowsScrollBarWidth + 'px', 'margin-bottom': rowsScrollBarHeight + 'px'}"
      ref="aggrs"
    >
      <table cellspacing="0">
        <colgroup>
          <col
            v-for="colField in visibleColFields"
            :key="colField.key"
            :style="{ width: colField.width + 'px'}"
          />
        </colgroup>
        <tfoot class="c-aggrs-footer">
          <tr
            :style="{ height: aggrsDefHeight + 'px' }"
          >
            <td
              v-for="colField in visibleColFields"
              :key="colField.key"
              :class="{ 'c-aggr': getAggrField(colField.dataFieldIdent) != null }"
            > 
              <template v-if="getAggrField(colField.dataFieldIdent) != null" >
                <span>{{ getAggrField(colField.dataFieldIdent).aggrTranslatedDesc }}</span>
                <span>{{ aggregates[colField.dataFieldIdent] }}</span>
              </template>
            </td>
            <th class="c-top-right-dz"></th>
          </tr>
        </tfoot>
      </table>
    </div>
    <div v-if="state === 0 && showDataProgress" v-bind:class="[{ 'c-progress': true }]">
      <slot v-if="$scopedSlots.progress" name="progress"></slot>
      <template v-else>
        <c-data-progress></c-data-progress>
      </template>
    </div>
    <div v-if="state === -1" v-bind:class="[{ 'c-errors': true }]">
      <slot v-if="$scopedSlots.errors" name="errors"></slot>
      <template v-else>
        <c-data-errors></c-data-errors>
      </template>
    </div>
    <div v-if="state === 1 && rowsIsEmpty && showDataEmpty" v-bind:class="[{ 'c-empty': true }]">
      <slot v-if="$scopedSlots.empty" name="empty"></slot>
      <template v-else>
        <c-data-empty></c-data-empty>
      </template>
    </div>
    <div class="c-status-bar" v-if="(state === 1 || state === 0) && !rowsIsEmpty && showStatusBar">
      <div class="c-settings" v-if="showSettings" :style="{ width: settingsWidth + 'px' }">
        <div class="c-settings-btn" v-on:click="settingsVisibleChange">&#xe913;</div>
      </div>
      <c-layouts-manager 
        v-if="showLayoutsManager"
        :appWindowIdent="appWindowIdent"
        :dataSetIdent="dataSetIdent"
      />
      <a
        v-if="showFullScreen"
        class="c-newtab"
        target="_blank"
        title="Otwórz w nowym oknie"
        :href="getFullPathHref"
        :style="{ width: rowsHeadersWidth + 'px' }"
      >&#xe989;</a>
      <c-pager
        v-if="showPager"
        class="c-pager-rows"
        :appWindowIdent="appWindowIdent"
        :dataSetIdent="dataSetIdent"
        :kind="pagerSettings ? pagerSettings.kind : 'determinate'"
        :sourceKind="pagerSettings ? pagerSettings.sourceKind : 'rows'"
        :labelCount="pagerSettings ? pagerSettings.labelCount : 'wierszy'"
        :btnsCnt="pagerSettings ? pagerSettings.btnsCnt : undefined"
        :showFirstPageButton="pagerSettings ? pagerSettings.showFirstPageButton : undefined"
        :showLastPageButton="pagerSettings ? pagerSettings.showLastPageButton : undefined"
        :showPreviousPageButton="pagerSettings ? pagerSettings.showPreviousPageButton : undefined"
        :showNextPageButton="pagerSettings ? pagerSettings.showNextPageButton : undefined"
        :previousPageButtonLabel="pagerSettings ? pagerSettings.previousPageButtonLabel : undefined"
        :nextPageButtonLabel="pagerSettings ? pagerSettings.nextPageButtonLabel : undefined"
        :showPagesCnt="pagerSettings ? pagerSettings.showPagesCnt : undefined"
        :showFirstPage="pagerSettings ? pagerSettings.showFirstPage : undefined"
        :scrollTopOnPageChange="pagerSettings ? pagerSettings.scrollTopOnPageChange : undefined"
      />
    </div>
  </div>
</template>

<script>
import { mapGetters, mapActions } from "vuex"
import controlUtils from "../classes/controlUtils"
import base from "./c-base"
import cBtna from './c-btna'
import cRowcheck from './c-rowcheck'
import cPager from './c-pager'
import cDataProgress from './c-data-progress'
import cDataErrors from './c-data-errors'
import cDataEmpty from './c-data-empty'
import cLayoutsManager from './c-layouts-manager'
import Vue from 'vue'
import vuescroll from 'vue-scroll'
 
Vue.use(vuescroll)

export default {
  extends: base,
  components: {
    'c-btna': cBtna,
    'c-rowcheck': cRowcheck,
    'c-pager': cPager,
    'c-data-progress': cDataProgress,
    'c-data-errors': cDataErrors,
    'c-data-empty': cDataEmpty,
    'c-layouts-manager': cLayoutsManager
  },
  props: {
    appWindowIdent: {
      type: String,
      default: null
    },
    dataSetIdent: {
      type: String,
      default: null
    },
    showDataProgress: {
      type: Boolean,
      default: true
    },
    showDataEmpty: {
      type: Boolean,
      default: true
    },
    showSettings: {
      type: Boolean,
      default: true
    },
    showRowCheck: {
      type: Boolean,
      default: true
    },
    showFullScreen:{
      type: Boolean,
      default: true
    },
    showStatusBar:{
      type: Boolean,
      default: true
    },
    showPager:{
      type: Boolean,
      default: true
    },
    showLayoutsManager:{
      type: Boolean,
      default: true
    },
    pagerSettings:{
      type: Object,
      default: null
    },
    showHeaders:{
      type: Boolean,
      default: true
    },
    defaultLayoutIdent:{
      type: String,
      default: null
    },
    rowFooterAction:{
      type: String,
      default: null
    },
    useVirtualization: {
      type: Boolean,
      default: false
    },
    additionalInfo: {
      type: Boolean,
      default: false
    },
    changePageOnScroll: {
      type: Boolean,
      default: false
    }
  },
  data: function() {
    return {
      componentClass: "c-grid",
      settingsVisible: false,
      scrollTop: 0,
      scrollLeft: 0,
      rowColFieldsMaxHeight: 26,
      colFieldsMaxHeight: 30,
      selectedRow: [],
      resizingColumnIndex: -1,
      draggingColField: null,
      draggingSortColField: null,
      settingsTabSelected: 1,
      rowHeaderDefWidth: 35,
      aggrsDefHeight: 25,
      rowsScrollBarWidth: 0,
      rowsScrollBarHeight: 0
    };
  },
  created: function() {
    this.rowColFieldsMaxHeight = this.getDataSetRowColFieldsMaxHeight(this.dataSet);
    this.colFieldsMaxHeight = this.getDataSetColFieldsMaxHeight(this.dataSet);
    if (this.defaultLayoutIdent)
      this.setDataSetLayoutIdent({
        dataSet: this.dataSet,
        layoutIdent: this.defaultLayoutIdent
      })
  },
  mounted: function() {
    this.$nextTick(() => {
      this.clientHeight = this.$el.clientHeight;
      this.clientWidth = this.$el.clientWidth;
    });
    window.addEventListener("resize", this.handleResize);
    this.rowsScrollBarWidth = this.getScrollBarWidth(this.$refs.rowsData) - 1
    this.rowsScrollBarHeight = this.getScrollBarHeight(this.$refs.rowsData) - 1
  },
  updated: function(){
    this.rowsScrollBarWidth = this.getScrollBarWidth(this.$refs.rowsData) - 1
    this.rowsScrollBarHeight = this.getScrollBarHeight(this.$refs.rowsData) - 1
  },
  beforeDestroy: function() {
    window.removeEventListener("resize", this.handleResize);
  },
  watch: {
    state: function() {
      this.resetScrolls();
    },
    scrollTop: function(val, oldVal) {
      let o = this.$refs.scrolledTop;
      if(!o)
        return
      if (!this.changePageOnScroll){
        this.$nextTick(() => {
          this.clientHeight = o.clientHeight
          o.scrollTop = val
        })
        return
      }
      let goPageNoPrev = o.scrollTop === 0 && val < oldVal;
      let goPageNoNext =
        o.scrollHeight - o.offsetHeight - val < 10 &&
        val > oldVal &&
        this.pageNo < this.pagesCount;
      this.$nextTick(() => {
        if (!goPageNoNext && !goPageNoPrev) {
          this.clientHeight = o.clientHeight
          o.scrollTop = val
        }
        if (goPageNoNext) {
          let payloadPageOperation = {
            appWindowIdent: this.appWindowIdent,
            dataSet: this.dataSet
          };
          this.setDataSetPageNoNext(payloadPageOperation);
        }
        if (goPageNoPrev) {
          let payloadPageOperation = {
            appWindowIdent: this.appWindowIdent,
            dataSet: this.dataSet
          };
          if (this.pageNo > 1) {
            this.setDataSetPageNoPrev(payloadPageOperation);
          }
        }
      });
    },
    scrollLeft: function(val) {
      let o = this.$refs.scrolledLeft
      let a = this.$refs.aggrs
      if(!o)
        return
      this.$nextTick(() => {
        this.clientWidth = o.clientWidth
        o.scrollLeft = val
        if (a)
          a.scrollLeft = val
      });
    },
    defaultLayoutIdent: function(val){
      if (!val || val === this.layoutIdent)
        return
      this.setDataSetLayoutIdent({
        dataSet: this.dataSet,
        layoutIdent: val
      })
    }
  },
  computed: {
    ...mapGetters("csAppWindowsUtils", [
      "getDataSetBusy",
      "getDataSetRows",
      "getFullPathHref",
      "getDataSetColFieldsMaxHeight",
      "getDataSetRowColFieldsMaxHeight",
      "getDataSetSortColFields",
      "getDataSetSortIdent",
      "getDataSetSort",
      "getCurrentColField",
      "getCurrentSortColField",
      "getCurrentColFieldIndex",
      "getCurrentSortColFieldIndex"
    ]),
    rowShift: function() {
      return this.useVirtualization ? Math.floor(this.scrollTop / this.rowColFieldsMaxHeight) : 0;
    },
    rowMinVisible: function() {
      return this.useVirtualization ? Math.floor(this.scrollTop / this.rowColFieldsMaxHeight) + 1 : 1;
    },
    rowMaxVisible: function() {
      let result = Math.ceil(
        (this.clientHeight + 78 + this.scrollTop) / this.rowColFieldsMaxHeight
      );
      return result <= this.rows.length && this.useVirtualization ? result : this.rows.length;
    },
    virtRowsCount: function() {
      return this.useVirtualization ? this.rowMaxVisible - this.rowMinVisible + 1 : this.rows.length 
    },
    colShift: function() {
      return Math.floor(this.scrollLeft / this.rowsWidth);
    },
    virtColsCount: function() {
      let result = this.useVirtualization ? Math.ceil(this.clientWidth / this.rowsWidth) : this.visibleColFields.length
      return result <= this.visibleColFields.length
        ? result
        : this.visibleColFields.length;
    },
    colMinVisible: function() {
      return Math.floor(this.scrollLeft / this.rowsWidth) + 1;
    },
    colMaxVisible: function() {
      return Math.ceil((this.clientWidth + this.scrollLeft) / this.rowsWidth);
    },
    virtDataWidth: function() {
      let width = 60;
      this.visibleColFields.forEach(colField => {
        width += colField.width;
      });
      return width;
    },
    virtDataHeight: function() {
      return this.rows.length * this.colFieldsMaxHeight + 78 + (this.hasAggrFields4Display ? (this.aggrsDefHeight + this.rowsScrollBarHeight) : 0);
    },
    virtDataTop: function() {
      return this.useVirtualization ? (this.rowMinVisible - 1) * this.rowColFieldsMaxHeight : 0
    },
    virtDataLeft: function() {
      return this.useVirtualization ? (this.colMinVisible - 1) * this.rowsWidth : 0
    },
    sortColFields: function() {
      return this.getDataSetSortColFields(this.dataSet);
    },
    dataSetSort: function() {
      return this.getDataSetSort(
        this.dataSet,
        this.getDataSetSortIdent(this.dataSet)
      );
    },
    isSortColFieldExists: function() {
      return this.sortColFields.find(
        item => item.dataFieldIdent === this.currentColField.dataFieldIdent
      )
        ? true
        : false;
    },
    currentColField: function() {
      return this.getCurrentColField(this.dataSet);
    },
    currentColFieldIndex: function() {
      return this.getCurrentColFieldIndex(this.dataSet);
    },
    currentSortColFieldIndex: function() {
      return this.getCurrentSortColFieldIndex(this.dataSet);
    },
    currentSortColField: function() {
      return this.getCurrentSortColField(this.dataSet);
    },
    isFirstColField: function() {
      return this.currentColFieldIndex === 0;
    },
    isFirstSortColField: function() {
      return (
        !this.currentSortColField ||
        (this.currentSortColField && this.currentSortColField.ord === 1)
      );
    },
    isLastColField: function() {
      return this.currentColFieldIndex === this.colFields.length -1
    },
    isLastSortColField: function() {
      return (
        !this.currentSortColField ||
        this.currentSortColField.ord === this.sortColFields.length
      );
    },
    rowsHeadersWidth: function() {
      let result = this.showRowCheck ? this.rowHeaderDefWidth : 0
      result += this.additionalInfo ? this.rowHeaderDefWidth : 0
      return result
    },
    settingsWidth: function(){
      return this.rowsHeadersWidth ? this.rowsHeadersWidth : this.rowHeaderDefWidth
    },
    aggrFields4Display: function(){
      return this.aggrFields && this.aggrFields.length > 1 ? this.aggrFields.slice(1) : []
    },
    hasAggrFields4Display: function(){
      return this.aggrFields4Display.length > 0
    }
  },
  methods: {
    ...mapActions("csAppWindowsUtils", [
      "setDataSetPrevRow",
      "setDataSetNextRow",
      "setLookupDefSelection",
      "setDataSetPageNoNext",
      "setDataSetPageNoPrev",
      "setDataSetVisibleColFieldAttr",
      "setColFieldOrd",
      "setColFieldVisibility",
      "addSortColFieldToSortIdent",
      "deleteSortColField",
      "setSortColFieldOrd",
      "setSortColFieldsIsDesc",
      "setCurrentColField",
      "setCurrentSortColField",
      "deleteAllSortColFields",
      "setDataSetLayoutIdent",
      "deleteAllSelectedRow",
      "addAllSelectedRow"
    ]),
    onSelectedRowHeaderValueChange: function(evt) {
      if (!evt.target.checked) {
        this.deleteAllSelectedRow({ 
          appWindowIdent: this.appWindowIdent,
          dataSetIdent: this.dataSetIdent
        })
      } else this.addAllSelectedRow({
        appWindowIdent: this.appWindowIdent,
        dataSetIdent: this.dataSetIdent
      })
    },
    handleScroll: function(evt) {
      this.scrollTop = evt.target.scrollTop;
      this.scrollLeft = evt.target.scrollLeft;
    },
    handleResize: function() {
      this.clientHeight = this.$el.clientHeight;
      this.clientWidth = this.$el.clientWidth;
      this.rowsScrollBarWidth = this.getScrollBarWidth(this.$refs.rowsData) - 1
      this.rowsScrollBarHeight = this.getScrollBarHeight(this.$refs.rowsData) - 1
    },
    settingsVisibleChange: function() {
      this.settingsVisible = this.settingsVisible ? false : true;
    },
    getFormatTypeClass: function(formatType) {
      return controlUtils.checkFormatType(formatType).formatTypeClass;
    },
    onClickRow: function(row) {
      this.setDataSetCurrentRow({ dataSet: this.dataSet, row: row });
    },
    onDblClickRow: async function(row) {
      await this.setDataSetCurrentRow({ dataSet: this.dataSet, row: row });
      await this.setLookupDefSelection({ appWindowIdent: this.appWindowIdent });
    },
    onKeyUp: 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 });
      }
    },
    resetScrolls: function() {
      this.scrollTop = 0;
      this.scrollLeft = 0;
    },
    resizeHeaderMouseDown: function(e, i) {
      this.resizingColumnIndex = i;
      this.setDataSetVisibleColFieldAttr({
        dataSet: this.dataSet,
        colFieldIndex: i,
        attr: {
          isResizing: true
        }
      });
      document.addEventListener("mousemove", this.resizeHeaderMouseMove);
      document.addEventListener("mouseup", this.resizeHeaderMouseUp);
    },
    resizeHeaderMouseMove: function(e) {
      let i = this.resizingColumnIndex;
      if (i != -1 && this.visibleColFields[i].isResizing) {
        let widthComputed =
          this.visibleColFields[i].width + parseInt(e.movementX);
        widthComputed = widthComputed <= 30 ? 30 : widthComputed;
        this.setDataSetVisibleColFieldAttr({
          dataSet: this.dataSet,
          colFieldIndex: i,
          attr: {
            width: widthComputed
          }
        });
      }
    },
    resizeHeaderMouseUp: function() {
      this.resizingColumnIndex = -1;
      for (let i = 0; i < this.visibleColFields.length; i++) {
        this.setDataSetVisibleColFieldAttr({
          dataSet: this.dataSet,
          colFieldIndex: i,
          attr: {
            isResizing: false
          }
        });
      }
      document.removeEventListener("mousemove", this.resizeHeaderMouseMove);
      document.removeEventListener("mouseup", this.resizeHeaderMouseUp);
    },
    setColFieldOrder: function(colField, colFieldNew) {
      let payload = {
        dataSet: this.dataSet,
        colField: colField,
        colFieldNew: colFieldNew,
        setCurrent: true
      };
      this.setColFieldOrd(payload)
    },
    setSortColFieldOrder: function(sortColField, sortColFieldNew) {
      let payload = {
        dataSet: this.dataSet,
        sortColField: sortColField,
        sortColFieldNew: sortColFieldNew,
        setCurrent: true
      };
      this.setSortColFieldOrd(payload);
    },
    onColFieldVisibleChange: function(event, colField) {
      let isVisible = event.target.checked ? 1 : 0;
      let payload = {
        colField: colField,
        isVisible: isVisible,
        layout: this.layout,
        dataSet: this.dataSet
      };
      this.setColFieldVisibility(payload);
    },
    colFieldUp: function() {
      if (this.currentColFieldIndex > 0)
        this.setColFieldOrder(
          this.currentColField,
          this.colFields[this.currentColFieldIndex - 1]
        )
    },
    colFieldDown: function() {
      if (this.currentColField.ord < this.colFields.length)
        this.setColFieldOrder(
          this.currentColField,
          this.colFields[this.currentColFieldIndex + 1]
        )
    },
    sortColFieldUp: function() {
      this.setSortColFieldOrder(
        this.currentSortColField,
        this.sortColFields[this.currentSortColFieldIndex - 1]
      );
    },
    sortColFieldDown: function() {
      this.setSortColFieldOrder(
        this.currentSortColField,
        this.sortColFields[this.currentSortColFieldIndex + 1]
      );
    },
    onClickColField: function(event, colField) {
      this.setCurrentColField({ dataSet: this.dataSet, colField: colField });
    },
    onClickSortColField: function(event, sortColField) {
      this.setCurrentSortColField({
        dataSet: this.dataSet,
        sortColField: sortColField
      });
    },
    setColFieldsVisibilityAll: function(event, isVisible) {
      let layout = this.layout
      let dataSet = this.dataSet
      this.colFields.forEach(colField => {
        this.setColFieldVisibility({ colField, isVisible, layout, dataSet });
      });
    },
    reverseColFieldsVisibility: function() {
      this.colFields.forEach(colField => {
        this.setColFieldVisibility({
          colField: colField,
          isVisible: colField.isVisible === 1 ? 0 : 1,
          layout: this.layout,
          dataSet: this.dataSet
        });
      });
    },
    addSortColField: function() {
      if (this.isSortColFieldExists) return;
      this.addSortColFieldToSortIdent({
        dataSet: this.dataSet,
        colField: this.currentColField
      });
      let selectedColFieldIndex = this.getCurrentColField(this.dataSet).ord;
      if (selectedColFieldIndex < this.sortColFields.length)
        this.setCurrentColField({
          dataSet: this.dataSet,
          colField: this.colFields[selectedColFieldIndex]
        });
    },
    removeSortColField: function() {
      if (this.sortColFields.length <= 0) return;
      this.deleteSortColField({
        dataSet: this.dataSet,
        sortColField: this.currentSortColField
      });
    },
    setSortColFieldAsc: function(event, sortColField) {
      this.setSortColFieldsIsDesc({dataSet: this.dataSet, sortColField: sortColField, isDesc: 0});
    },
    setSortColFieldDesc: function(event, sortColField) {
      this.setSortColFieldsIsDesc({dataSet: this.dataSet, sortColField: sortColField, isDesc: 1});
    },
    getColField: function(dataFieldIdent) {
      return this.colFields.find(
        item => item.dataFieldIdent === dataFieldIdent
      );
    },
    getSortColField: function(dataFieldIdent) {
      if(this.sortColFields != null) {
        let index = this.getSortColFieldIndex(dataFieldIdent)
        return index > -1 ? this.sortColFields[index] : null
      }
    },
    getSortColFieldIndex: function(dataFieldIdent) {
      if(this.sortColFields != null) {
        return this.sortColFields.findIndex(
          item => item.dataFieldIdent === dataFieldIdent
        );
      }
    },
    getSortColFieldIsDesc: function(dataFieldIdent) {
      let colField = this.getSortColField(dataFieldIdent);
      return colField ? colField.isDesc : null;
    },
    getSortColFieldOrd: function(dataFieldIdent) {
      return this.getSortColFieldIndex(dataFieldIdent) + 1
    },
    colFieldDragStart: function($e, colField) {
      $e.dataTransfer.setData("text", "anything");
      this.draggingColField = colField;
      this.setCurrentColField({ dataSet: this.dataSet, colField: colField });
    },
    colFieldDrop: function(event, colField) {
      if (this.draggingColField){
        this.setColFieldOrder(this.draggingColField, colField)
      }
      if (this.draggingSortColField) this.removeSortColField();
    },
    colFieldDragEnd: function() {
      this.draggingColField = null;
    },
    colFieldDropOnList: function(event) {
      if (this.draggingColField) {
        let offset = Math.ceil((event.layerY - 5) / 30);
        offset =
          offset > this.colFields.length - 1 ? this.colFields.length - 1 : offset;
        this.setColFieldOrder(this.draggingColField, this.colFields[offset]);
      }
      if (this.draggingSortColField) this.removeSortColField();
    },
    sortColFieldDragStart: function($e, sortColField) {
      $e.dataTransfer.setData("text", "anything");
      this.draggingSortColField = sortColField;
      this.setCurrentSortColField({
        dataSet: this.dataSet,
        sortColField: sortColField
      });
    },
    sortColFieldDrop: function(event, sortColField) {
      if (this.draggingSortColField)
        this.setSortColFieldOrder(this.draggingSortColField, sortColField);
      if (this.draggingColField && !this.isSortColFieldExists) {
        this.addSortColField();
        this.setSortColFieldOrder(this.currentSortColField, sortColField);
      }
    },
    sortColFieldDragEnd: function() {
      this.draggingSortColField = null;
    },
    sortColFieldDropOnList: function(event) {
      let offset = Math.ceil((event.layerY - 5) / 30);
      if (this.draggingSortColField) {
        offset =
          offset > this.sortColFields.length - 1
            ? this.sortColFields.length - 1
            : offset;
        this.setSortColFieldOrder(this.draggingSortColField, this.sortColFields[offset]);
      }
      if (this.draggingColField && !this.isSortColFieldExists) {
        this.addSortColField();
        offset =
          offset > this.sortColFields.length
            ? this.sortColFields.length
            : offset;
        this.setSortColFieldOrder(this.currentSortColField, this.sortColFields[offset]);
      }
    },
    colFieldDropOnHeader: function() {
      if (this.draggingColField) {
        this.setColFieldOrder(this.draggingColField, this.colFields[this.colFields.length - 1]);
      }
    },
    colFieldDropOnFirst: function() {
      if (this.draggingColField) {
        this.setColFieldOrder(this.draggingColField, this.colFields[0]);
      }
    },
    colFieldClick: function(event, colField, sortColField) {
      let isDesc = sortColField ? sortColField.isDesc : -1;
      this.deleteAllSortColFields({ dataSet: this.dataSet });
      if (isDesc === -1) {
        this.setCurrentColField({ dataSet: this.dataSet, colField: colField });
        this.addSortColField();
      } else if (isDesc === 0) {
        this.setCurrentColField({ dataSet: this.dataSet, colField: colField });
        this.addSortColField();
        this.setSortColFieldsIsDesc({
          dataSet: this.dataSet,
          sortColField: this.currentSortColField,
          isDesc: 1
        });
      }
      this.refresh();
    },
    colFieldShiftClick: function(event, colField, sortColField) {
      let isDesc = sortColField ? sortColField.isDesc : -1;
      if (isDesc === -1) {
        this.setCurrentColField({ dataSet: this.dataSet, colField: colField });
        this.addSortColField();
      } else if (isDesc === 0) {
        this.setCurrentSortColField({
          dataSet: this.dataSet,
          sortColField: sortColField
        });
        this.setSortColFieldsIsDesc({
          dataSet: this.dataSet,
          sortColField: this.currentSortColField,
          isDesc: 1
        });
      } else if (isDesc === 1) {
        this.setCurrentSortColField({
          dataSet: this.dataSet,
          sortColField: sortColField
        });
        this.removeSortColField();
      }
      this.refresh();
    },
    showAdditionalInfo: function(ev, row) {
      let payload = {
        sourceKind: this.sourceKind,
        appWindowIdent: this.appWindowIdent, 
        dataSet: this.dataSet,
        row: row,
        pivotCol: this.pivotCol, 
        pivotRow: this.pivotRow, 
        pivotRowKey: this.pivotRowKey, 
        dataFieldIdent: '_showAdditionalInfo',
        dataFieldValue: row._showAdditionalInfo === 1 ? 0 : 1
      }
      this.setDataSetFieldValue(payload)
    },
    getAggrField: function(dataFieldIdent){
      return this.aggrFields4Display.find(i => i.dataFieldIdent === dataFieldIdent)
    }
  }
};
</script>
