<template>
  <div
    :class="[
      componentClass,
      getComponentFormatTypeClass,
      {
        'c-focus': inputFocus,
        'c-readonly': readonly,
        'c-disabled': isDisabled,
        'c-autofocus': autofocus
      },
      componentErrorClass,
      componentInfoClass,
      lookupPlacement,
      componentWarningClass,
      (isRequired && 'c-required')
    ]"
    @focusin="componentFocusin"
    @focusout="componentFocusout"
  >
    <div>
      <label
        class="label"
        v-if="showLabel && isLabel && labelLocation == 'left'"
        v-bind:style="{ width: getLabelWidth }"
        :for="componentId"
        >{{ label }}</label>
      <div class="edit">
        <input v-if="!isMultiLine"
          :class="['input', getFormatTypeClass]"
          :id="componentId"
          :value="dataFieldValue"
          :placeholder="getPlaceholderValue"
          :type="getType"
          :name="name"
          :disabled="isDisabled"
          :readonly="readonly"
          :indeterminate.prop="isIndeterminate"
          :checked="isCheckedValue"
          v-on:input="onValueInput"
          v-on:keydown="onKeyDown"
          v-on:keyup="onKeyUp"
          v-on:focus="onFocus"
          v-on:blur="onBlur"
          tabindex="0"
          ref="input"
          :autocomplete="autocomplete"
          :autofocus="autofocus"
        />
        <textarea v-if="isMultiLine"
          :class="['input', getFormatTypeClass]"
          :id="componentId"
          :value="dataFieldValue"
          :placeholder="getPlaceholderValue"
          :type="getType"
          :name="name"
          :disabled="isDisabled"
          :readonly="readonly"
          v-on:input="onValueInput"
          v-on:keydown="onKeyDown"
          v-on:keyup="onKeyUp"
          v-on:focus="onFocus"
          v-on:blur="onBlur"
          tabindex="0"
          ref="input"
          :autocomplete="autocomplete"
          :autofocus="autofocus"
        />
        <label
          v-if="getType == 'checkbox'"
          :for="componentId"
          class="c-checkbox"
        ></label>
        <i
          class="btn-clear"
          v-if="hasClear"
          tabindex="-1"
          ref="btnClear"
          v-on:click="clearDataFieldValue"
          >&#xE907;</i
        >
        <i
          class="btn-refresh"
          v-if="hasRefresh"
          tabindex="-1"
          ref="btnRefresh"
          v-on:click="refreshData"
          >&#xE911;</i
        >
        <i
          class="btn-dropdown"
          v-if="hasLookup && !lookupVisible"
          tabindex="-1"
          v-on:click="displayLookup"
          >&#xE904;</i
        >
        <i
          class="btn-dropup"
          v-if="hasLookup && showDropDown && lookupVisible"
          tabindex="-1"
          v-on:click="hideLookup"
          >&#xE904;</i
        >
        <i
          class="c-btn-calendar"
          v-if="hasCalendar && !calendarVisible"
          tabindex="-1"
          v-on:click="displayCalendar"
        />
        <i
          class="c-btn-calendar"
          v-if="hasCalendar && calendarVisible"
          tabindex="-1"
          v-on:click="hideCalendar"
        />
      </div>
      <label
        class="label suffix-label"
        v-if="dataFieldIdent4SuffixLabel != null"
        v-bind:style="{ width: getSuffixLabelWidth }"
        :for="componentId"
        >{{ suffixLabel }}</label>
      <label
        class="label"
        v-if="showLabel && isLabel && labelLocation == 'right'"
        v-bind:style="{ width: getLabelWidth }"
        :for="componentId"
        >{{ label }}</label>
      <div
        class="c-whereList"
        v-if="hasLookup && whereList && whereList.length > 0"
      >
        <div
          class="c-whereList-item"
          v-for="rowWhere in whereList"
          :key="rowWhere[dataFieldIdent]"
        >
          <div class="c-whereList-item-label">
            {{ rowWhere[dataFieldIdent] }}
          </div>
          <i
            class="c-whereList-item-btn-close"
            v-on:click="
              deleteWhereListItem(rowWhere)
            "
            >&#xE907;</i
          >
        </div>
      </div>
    </div>
    <div
      class="c-lookup"
      v-if="hasLookup"
      v-bind:class="{ 'c-list-visible': lookupVisible , 'c-lookup-focus': lookupFocus}"
      :style="{ width: getLookupListWidth, height: lookupHeight }"
      ref="lookupCont"
    >
      <c-lookup
        :appWindowIdent="appWindowIdentLookup"
        v-if="hasLookup && lookupVisible"
        tabindex="1"
        ref="lookup"
      ></c-lookup>
    </div>
    <div class="c-calendar" v-if="hasCalendar && calendarVisible">
      <div class="c-header">
        <div class="c-btn-prev" tabindex="-1" v-on:click="monthLeft" />
        <div class="c-m-y">{{ month }} {{ year }}</div>
        <div class="c-btn-next" tabindex="-1" v-on:click="monthRight" />
      </div>
      <table cellspacing="0">
        <colgroup>
          <col v-for="n in 7" :key="n" />
        </colgroup>
        <thead>
          <tr>
            <td v-for="wd in 7" :key="wd">
              {{ weekdays[wd - 1] }}
            </td>
          </tr>
        </thead>
        <tbody>
          <tr v-for="r in 6" :key="r">
            <td
              v-for="c in 7"
              :key="c"
              :class="[
                'c-day',
                getCalendarDayClass(r, c),
                getCalendarDayOutOfRangeClass(r, c)
              ]"
              tabindex="3"
              v-on:click="setDate(getDate(r, c))"
            >
              {{ getDay(r, c) }}
            </td>
          </tr>
        </tbody>
      </table>
    </div>
    <div
      v-if="infoMessageText != null && infoMessageText != ''"
      class="c-info-txt"
    >{{ infoMessageText }}</div>
    <div
      v-if="warningMessageText != null && warningMessageText != ''"
      class="c-warning-txt"
    >{{ warningMessageText }}</div>
    <div
      v-if="errorMessageText != null && errorMessageText != ''"
      class="c-error-txt"
    >{{ errorMessageText }}</div>
  </div>
</template>

<script>
const props = {
  lookupListWidth: {
    type: String,
    default: null
  },
  showLabel: {
    type: Boolean,
    default: true
  },
  labelLocation: {
    type: String,
    default: 'left'
  },
  labelWidth: {
    type: String,
    default: '150px'
  },
  dataFieldIdent4SuffixLabel: {
    type: String,
    default: null
  },
  suffixLabelWidth: {
    type: String,
    default: '20px'
  },
  formatType: {
    type: String,
    default: 'none'
  },
  name: {
    type: String,
    default: null
  },
  dataFieldIdent: {
    type: String,
    default: null
  },
  valueChecked: {
    type: Number,
    default: 1
  },
  valueUnChecked: {
    type: Number,
    default: 0
  },
  indeterminate: {
    type: Boolean,
    default: false
  },
  showLookup: {
    type: Boolean,
    default: true
  },
  showRefresh: {
    type: Boolean,
    default: false
  },
  showDropDown: {
    type: Boolean,
    default: true
  },
  showClear: {
    type: Boolean,
    default: true
  },
  type: {
    type: String,
    default: null
  },
  isRequired: {
    type: Boolean,
    default: false
  },
  isMultiLine: {
    type: Boolean,
    default: false
  },
  autocomplete:{
    type: String,
    default: 'off'
  },
  disabled:{
    type: Boolean,
    default: false
  },
  readonly: {
    type: Boolean,
    default: false
  },
  autofocus: {
    type: Boolean,
    default: false
  },  
  oncfTrigger: {
    type: String,
    default: 'timeout'
  },
  lookupTimeout: {
    type: Number,
    default: 650
  },
  oncfTimeout: {
    type: Number,
    default: 400
  },
  lookupMinHeight: {
    type: Number,
    default: 200
  },
  selectAllTextOnFocus: {
    type: Boolean,
    default: false
  },
  lookupOpenKind: {
    type: String,
    default: null
  }
}

import base from './c-base'
import controlUtils from '../classes/controlUtils'
import stringUtils from '../classes/stringUtils'
import { mapActions, mapGetters } from 'vuex'
import moment from 'moment'

export default {
  extends: base,
  data: function() {
    return {
      componentClass: 'c-edit',
      focusClass: null,
      lookupHeight: null,
      lookupPlacement: '',
      calendarVisible: false,
      date: null,
      months: null,
      weekdays: null,
      inputFocus: false, 
      lookupTimer: null,
      lookupFocus: false,
      componentFocus: false,
      componentFocusTimer: null,
      componentFocusTimeout: 50
    }
  },
  props,
  computed: {
    ...mapGetters('csAppWindowsUtils', [
      'getDataSetWhereList',
      'getDataSetRowsFieldValue'
    ]),
    hasClear: function() {
      return (
        (this.getType == null || this.getType == 'text') &&
        this.showClear === true &&
        (this.dataFieldValue !== null ||
          (this.whereList && this.whereList.length > 0))
      )
    },
    hasRefresh: function() {
      return (
        (this.getType == null || this.getType == 'text') &&
        this.showRefresh === true
      )
    },
    lookupDef: function() {
      return this.dataSet && this.showLookup && this.dataSet.lookupDefs
        ? this.dataSet.lookupDefs.find(
            item => item.dataFieldIdent === this.dataFieldIdent
          ) || null
        : null
    },
    lookupDataSetIdent: function(){
      return this.lookupDef && this.lookupDef.lookupSettersRefresh ? 
        this.lookupDef.lookupSettersRefresh[0].dataSetIdentFrom : 
        (
          this.lookupDef && this.lookupDef.lookupGettersRefresh ?
          this.lookupDef.lookupGettersRefresh[0].dataSetIdentTo : 
          null
        )
    },
    lookupAppWindowIdent: function(){
      return this.lookupDef && this.lookupDef.lookupSettersRefresh ? 
        this.lookupDef.lookupSettersRefresh[0].appWindowIdentFrom : 
        (
          this.lookupDef && this.lookupDef.lookupGettersRefresh ?
          this.lookupDef.lookupGettersRefresh[0].appWindowIdentTo : 
          null
        )
    },
    hasCalendar: function() {
      return this.formatType == 'calendar'
    },
    hasLookup: function() {
      return this.showLookup && this.lookupDef !== null ? true : false
    },
    appWindowIdentLookup: function() {
      return this.lookupDef !== null
        ? this.lookupDef.appWindowIdentLookup
        : null
    },
    appWindowIdentLookupDef: function() {
      return this.lookupDef !== null
        ? this.lookupDef.appWindowIdentLookupDef
        : null
    },
    lookupVisible: function() {
      if (this.sourceKind === 'rows')
        return this.lookupDef && this.lookupDef.lookupVisible && this.contextRow && this.contextRow._lookupVisible[this.lookupDef.appWindowIdentLookup]
      return this.lookupDef ? this.lookupDef.lookupVisible : false
    },
    label: function() {
      let result
      if (this.sourceKind == 'where') {
        result = this.labelLocation === 'none' ||
          this.whereFieldsIdentsDataField === null ||
          this.whereFieldsIdentsDataField === undefined
          ? null
          : this.whereFieldsIdentsDataField.dataFieldLabTranslatedDesc
      } else if (this.sourceKind == 'rows') {
        result = this.labelLocation === 'none' ||
          this.fieldsIdentsDataField === null ||
          this.fieldsIdentsDataField === undefined
          ? null
          : this.fieldsIdentsDataField.dataFieldLabTranslatedDesc
      }
      return result
    },
    suffixLabel: function() {
      if (this.dataFieldIdent4SuffixLabel == null) return
      return this.getDataSetRowsFieldValue(
          this.dataSet,
          this.dataFieldIdent4SuffixLabel,
          this.contextRow
        )
    },
    getPlaceholderValue: function() {
      let result
      if (this.sourceKind == 'where') {
        result = this.whereFieldsIdentsDataField?.dataFieldWatermarkTranslatedDesc
      } else if (this.sourceKind == 'rows') {
        result = this.fieldsIdentsDataField?.dataFieldWatermarkTranslatedDesc
      }
      return result
    },
    isLabel: function() {
      return this.label !== null && this.label !== undefined
    },
    isIndeterminate: function() {
      if (!this.indeterminate) {
        return false
      }
      if (
        this.dataFieldValue != this.valueChecked &&
        this.dataFieldValue != this.valueUnChecked
      ) {
        return true
      } else {
        return false
      }
    },
    isDisabled: function() {
      if (this.disabled)
        return true
      if ((this.state === 0 || this.state === 2) && this.sourceKind == 'rows')
        return true
      return false
    },
    isCheckedType: function() {
      return this.getType == 'checkbox'
    },
    isCheckedValue: function() {
      if (!this.isCheckedType) {
        return null
      }
      return this.dataFieldValue == this.valueChecked
    },
    getType: function() {
      if (this.type == null) {
        let formatType = controlUtils.checkFormatType(this.formatType)
        return formatType.type
      }
      return this.type
    },
    getComponentFormatTypeClass: function() {
      return this.getType != null ? 'c-' + this.getType : null
    },
    getFormatTypeClass: function() {
      return controlUtils.checkFormatType(this.formatType).formatTypeClass
    },
    getLabelWidth: function() {
      return this.labelWidth.includes('px')
        ? this.labelWidth
        : this.labelWidth + 'px'
    },
    getSuffixLabelWidth: function() {
      return this.suffixLabelWidth.includes('px') ? this.suffixLabelWidth : this.suffixLabelWidth + 'px'
    },
    getLookupListWidth: function() {
      return (
        this.lookupListWidth +
        (!isNaN(this.lookupListWidth - parseFloat(this.lookupListWidth))
          ? 'px'
          : '')
      )
    },
    year: function() {
      let date = new Date(this.date)
      return date.getUTCFullYear()
    },
    month: function() {
      let date = new Date(this.date)
      let month = date.getUTCMonth()
      return this.months[month]
    },
    whereList: function(){
      return this.getDataSetWhereList(this.dataSet, this.dataFieldIdent, this.sourceKind, this.contextRow)
    }
  },
  methods: {
    ...mapActions('csAppWindowsUtils', [
      'addAppWindow',
      'refreshDataSetDependence',
      'setLookupDefVisible',
      'clearDataSetsFromSetters',
      'deleteDataSetWhereListsItem',
      'deleteDataSetWhereListItem',
      'clearLookupDataSetsSelection',
      "setDataSetPrevRow",
      "setDataSetNextRow",
      "setLookupDefSelection",
      "addLookupWindow"
    ]),
    componentFocusin: function(){
      clearTimeout(this.componentFocusTimer)
      this.componentFocus = true
    },
    componentFocusout: function(){
      this.componentFocusTimer = setTimeout(()=>{
        this.componentFocus = false
        if (this.lookupDef && this.lookupDef.closeKind === 'onLostFocus'){
          let payload = {
            appWindowIdent: this.appWindowIdent,
            dataSetIdent: this.dataSetIdent,
            dataFieldIdent: this.dataFieldIdent,
            lookupVisible: false,
            row: this.sourceKind === "rows" ? this.contextRow : undefined
          }
          this.setLookupDefVisible(payload)
        }
      }, this.componentFocusTimeout)
    },
    onValueInput: async function(evt){
      let dataFieldValue = evt.target.value === '' ? null : (evt.target.valueAsNumber || evt.target.value)
      if (this.isCheckedType) {
        dataFieldValue = evt.target.checked
          ? this.valueChecked
          : this.valueUnChecked
      }
      if (dataFieldValue == null && this.hasLookup) {
        this.clearDataFieldValueInternall()
      }
      await this.setDataFieldValue({
        dataFieldIdent: this.dataFieldIdent,
        dataFieldValue: dataFieldValue,
        oncfTimeout: this.oncfTimeout,
        refreshLock: this.isCheckedType ? 0 : 1,
        onCFLock: stringUtils.isEqual(this.oncfTrigger, 'enter') ? 1 : 0
      })
      if (this.hasLookup) {
        this.setLookupVisible(true)
      }
    },
    setLookupVisible: function(visible, useTimeout = true) {
      clearTimeout(this.lookupTimer)
      let payload = null
      this.lookupFocus = false
      if (visible) {
        this.setLookupHeight()
        let payload = {
          appWindowIdent: this.appWindowIdentLookupDef,
          appWindowUniqIdent: this.appWindowIdentLookup,
          setActive: false,
          lookupDef: this.lookupDef,
          addRoutingData: false,
          path: null,
          row: this.sourceKind === "rows" ? this.contextRow : undefined,
          params: this.getAppWindowParams(this.appWindowIdent),
          showOnMainTabList: false
        }
        if (useTimeout)
          this.lookupTimer = setTimeout(() => {
            this.addLookupWindow(payload)
          }, this.lookupTimeout)
        else
          this.addLookupWindow(payload)
      }
      payload = {
        appWindowIdent: this.appWindowIdent,
        dataSetIdent: this.dataSetIdent,
        dataFieldIdent: this.dataFieldIdent,
        lookupVisible: visible,
        dataSet: this.dataSet,
        row: this.sourceKind === "rows" ? this.contextRow : undefined
      }
      this.setLookupDefVisible(payload)
    },
    onFocus: function() {
      this.inputFocus = true;
      if (this.hasLookup && this.lookupOpenKind === 'onFocus') this.setLookupVisible(true)
      if (this.getType !== 'checkbox' && this.selectAllTextOnFocus === true) {
        this.$refs.input.select(0, this.$refs.input.value.length);
      }
    },
    onBlur: function() {
      this.inputFocus = false
      this.lookupFocus = false
    },
    onKeyUp: async function(evt) {
      if (evt.key == 'Enter') {
        if (this.lookupFocus && this.hasLookup){
          this.lookupFocus = false
          await this.setLookupDefSelection({ appWindowIdent: this.lookupAppWindowIdent, dataSet: this.dataSet, row: this.contextRow })
          await this.setLookupVisible(false)
        }
        let dataFieldValue = evt.target.value === '' ? null : (evt.target.valueAsNumber || evt.target.value)
        if (this.isCheckedType) {
          dataFieldValue = evt.target.checked
            ? this.valueChecked
            : this.valueUnChecked
        }
        this.setDataFieldValue({
          dataFieldIdent: this.dataFieldIdent, 
          dataFieldValue: dataFieldValue,
          onCFLock: stringUtils.isEqual(this.oncfTrigger, 'enter') ? 0 : 1
        })
      }
    },
    onKeyDown: async function(evt) {
      if (evt.key === 'Escape' && this.hasLookup) {
        await this.setLookupVisible(false)
        return
      }
      if (evt.key === 'ArrowDown' && this.hasLookup) {
        if (this.lookupVisible) {
          let lookupDataSet = this.getDataSet(this.lookupAppWindowIdent, this.lookupDataSetIdent)
          if (!lookupDataSet)
            return
          if (this.lookupFocus){
            await this.setDataSetNextRow(lookupDataSet)
          }
          else{
            this.lookupFocus = true
          }
          return
        }
        if (!this.lookupVisible) {
          await this.setLookupVisible(true, false)
          return
        }
      }
      if (evt.key === 'ArrowUp' && this.hasLookup) {
        if (this.lookupVisible) {
          let lookupDataSet = this.getDataSet(this.lookupAppWindowIdent, this.lookupDataSetIdent)
          if (!lookupDataSet)
            return
          if (this.lookupFocus){
            await this.setDataSetPrevRow(lookupDataSet)
          }
          return
        }
      }
    },
    refreshData: function() {
      if (this.sourceKind == 'where') this.refresh()
      else {
        this.refreshDataSetDependence({
          appWindowIdent: this.appWindowIdent,
          parentDataSetIdent: this.dataSetIdent,
          refreshAggregates: 1
        })
      }
    },
    displayLookup: function() {
      this.setLookupVisible(true, false)
      this.$refs.input.focus()
    },
    hideLookup: function() {
      this.setLookupVisible(false)
    },
    displayCalendar: function() {
      this.date = this.dataFieldValue || Date.now()
      this.calendarVisible = true
    },
    hideCalendar: function() {
      this.calendarVisible = false
    },
    deleteWhereListItem: function(item) {
      this.deleteDataSetWhereListItem({
        appWindowIdent: this.appWindowIdent,
        dataSetIdent: this.dataSetIdent,
        dataFieldIdent: this.dataFieldIdent,
        dataFieldValue: item[this.dataFieldIdent],
        _keyFieldsValues : item._keyFieldsValues,
        sourceKind: this.sourceKind,
        row: this.contextRow
      })
    },
    clearDataFieldValue: function() {
      this.clearDataFieldValueInternall()
      this.setDataFieldValue({dataFieldIdent: this.dataFieldIdent, dataFieldValue: null})
      if (this.hasLookup) this.setLookupVisible(false)
      this.hideCalendar()
      this.$refs.input.focus()
      this.inputFocus = true
    },
    clearDataFieldValueInternall: function() {
      let payload = {
        appWindowIdent: this.appWindowIdent,
        dataSetIdent: this.dataSetIdent,
        dataFieldIdent: this.dataFieldIdent,
        sourceKind: this.sourceKind,
        row: this.contextRow
      }
      this.deleteDataSetWhereListsItem(payload)
      this.clearLookupDataSetsSelection(payload)
      this.clearDataSetsFromSetters(payload)
    },
    setLookupHeight: function() {
      let lookupHeightResult = null

      if (
        this.$el != null &&
        this.lookupDef !== null /*&& this.lookupDef.lookupVisible === true*/
      ) {
        let spaceBelow =
          window.innerHeight -
          this.$el.getBoundingClientRect().bottom -
          this.lookupMinHeight / 20

        if (spaceBelow > this.lookupMinHeight) {
          let lookupHeightTmp = Math.ceil(screen.height / 2)

          if (lookupHeightTmp > this.lookupMinHeight && lookupHeightTmp < spaceBelow)
            lookupHeightResult = lookupHeightTmp
          else lookupHeightResult = spaceBelow

          lookupHeightResult += 'px'
        }
      }
      this.lookupHeight = lookupHeightResult
      this.lookupPlacement = ''
      this.setLookupPlacement(this.$el)
    },
    isLookupVisible: function(cont){
      const { bottom: contBottom } = cont.getBoundingClientRect()
      const { bottom } = this.$el.getBoundingClientRect()
      return bottom + this.lookupMinHeight <= contBottom
    },
    setLookupPlacement: function(el){
      const lookup = this.$refs.lookupCont
      if (!lookup){
        this.lookupPlacement = ''
        return
      }
      let parent = el.parentElement
      if (parent == null){
        this.lookupPlacement = ''
        return
      }
      let pStyles = getComputedStyle(parent)
      if (pStyles.overflowY == 'visible')
        return this.setLookupPlacement(parent)
      else if (this.isLookupVisible(parent))
        return this.setLookupPlacement(parent)
      else
        this.lookupPlacement = 'c-lookup-top'
    },
    monthLeft: function() {
      let date = new Date(this.date)
      date.setMonth(date.getMonth() - 1)
      this.date = date
    },
    monthRight: function() {
      let date = new Date(this.date)
      date.setMonth(date.getMonth() + 1)
      this.date = date
    },
    getDate: function(r, c) {
      let day = (r - 1) * 7 + (c - 1)
      let date = new Date(this.date)
      date.setDate(1)
      let d = date.getDay()

      if (d == 0) {
        d = 6
      } else if (d >= 1) d = d - 1
      return moment(date)
        .add(day - d, 'days')
        .format('YYYY-MM-DD')
    },
    getDay: function(r, c) {
      return moment(this.getDate(r, c), 'YYYY-MM-DD').format('D')
    },
    setDate: function(dataFieldValue) {
      this.setDataFieldValue({dataFieldIdent: this.dataFieldIdent, dataFieldValue: dataFieldValue})
      this.hideCalendar()
    },
    getCalendarDayClass: function(r, c) {
      let date = this.getDate(r, c)
      if (date == moment(this.dataFieldValue).format('YYYY-MM-DD'))
        return 'c-set-value'
      if (date == moment().format('YYYY-MM-DD')) return 'c-today'
      let m = moment(date)
      if (m.diff(moment().format('YYYY-MM-DD')) < 0) return 'c-past'
      if (m.diff(moment().format('YYYY-MM-DD')) > 0) return 'c-future'
    },
    getCalendarDayOutOfRangeClass: function(r, c) {
      let date = this.getDate(r, c)
      if (new Date(date).getMonth() != new Date(this.date).getMonth())
        return 'c-outrange'
    }
  },
  created: function() {
    this.months = [
      'styczeń',
      'luty',
      'marzec',
      'kwiecień',
      'maj',
      'czerwiec',
      'lipiec',
      'sierpień',
      'wrzesień',
      'październik',
      'listopad',
      'grudzień'
    ]
    this.weekdays = ['Pn', 'Wt', 'Śr', 'Cz', 'Pt', 'So', 'N']
  }
}
</script>
