<template>
  <div>
    <u-table
      :data="gridData == null ? [] : gridData"
      :striped="false"
      :loading="isLoading"
      :paginated="gridData == null ? false : pageAble != false"
      :per-page="gridPage"
      :checkable="checkable"
      :checked-rows.sync="checkedRows"
      :multi-header="multiHeader"
      :add-data="addData"
      :custom-row-key="keyCol"
      :selected.sync="selectedRow"
      :one-check="oneCheck"
      :backend-pagination="asyncData"
      :backend-sorting="asyncData"
      :total="asyncData ? total : ''"
      :current-page.sync="currentPage"
      class="e-table"
      @discardrow="discardRow"
      @select="(row) => {this.$emit('select', row)}"
      @dblclick="(row) => {this.$emit('dblclick', row)}"
      @check="(checkedList) => {this.$emit('check', checkedList)}"
      @page-change="onPageChange"
      @sort="onSort"
    >
      <template v-slot:addrow="{ row }">
        <u-table-column
          v-for="(column, colIndex) in headers"
          :key="colIndex"
          :field="column.field"
          :label="column.label"
          :sortable="column.sortable != false && column.fieldType != 'img'"
          :visible="column.visible != false"
          :numeric="column.numeric"
          :righted="column.righted"
          :centered="column.centered"
          :header-class="column.headerClass"
          :col="column.col"
          :group-label="column.groupLabel"
          :width="column.width"
          :add="!column.add"
        >
          <span
            v-if="!column.add"
          />
          <span v-else-if="column.fieldType == 'img'">
            <b-upload
              v-model="row[column.field].file"
              class="td-upload"
              drag-drop
              @input="fileAdd(row, column.field)"
            >
              <img :src="row[column.field].url">
            </b-upload>
          </span>
          <span
            v-else-if="
              column.fieldType == 'textbox' ||
                column.fieldType == 'autocomplete' ||
                column.fieldType == 'textarea'
            "
          >
            <input
              v-model="row[column.field]"
              class="input grid-text"
              type="text"
            >
          </span>
          <span v-else-if="column.fieldType == 'combobox'">
            <b-select
              v-model="row[column.field]"
              expanded
              class="grid-text"
            >
              <option
                v-for="option in column.comboData"
                :key="option.value"
                :value="option.value"
              >
                {{ option.description }}
              </option>
            </b-select>
          </span>
          <span
            v-else-if="column.fieldType == 'datetime'"
          >
            <date-picker
              v-model="row[column.field]"
              expanded
              class="grid-text"
              :name="column.field"
              :today-btn-show="true"
              @selectedDate="(param) => {row[column.field] = param.value}"
            />
          </span>
          <div
            v-else-if="column.fieldType == 'numberinput'"
            style="display:flex; justify-content: flex-end;"
          >
            <span
              v-if="!focusNumberInput(row)"
              class="grid-text"
              style="overflow: hidden;"
            >
              {{
                row[column.field]
                  ? Number(row[column.field]).toLocaleString()
                  : 0
              }}
            </span>
            <b-numberinput
              v-if="focusNumberInput(row)"
              v-model="row[column.field]"
              :step="column.step"
              :min="column.min"
              :max="column.max"
              class="grid-text"
              size="is-small"
              type="button"
              @keyup.native="checkNumberkey($event, column.field, row)"
              @keydown.native="preventExponential"
              @input="setNumberParam($event, column.field, row)"
            />
          </div>
          <div
            v-else-if="column.fieldType == 'popup'"
            @click="openPopup(column.field, row)"
          >
            <span class="grid-text">
              {{ row[column.field] }}
            </span>
          </div>
        </u-table-column>
      </template>
      <template v-slot="{ row }">
        <u-table-column
          v-for="(column, colIndex) in headers"
          :key="colIndex"
          :field="column.field"
          :label="column.label"
          :sortable="column.sortable != false && column.fieldType != 'img'"
          :visible="column.visible != false"
          :numeric="column.numeric"
          :righted="column.righted"
          :centered="column.centered"
          :header-class="column.headerClass"
          :editable="column.editable"
          :col="column.col"
          :group-label="column.groupLabel"
          :width="column.width"
          :searchable="column.filter"
        >
          <div
            v-if="column.fieldType == 'img'"
            class="img-cell"
            :class="{'upload-cell': (row[column.field].url ? false : true)}"
          >
            <img
              v-if="row[column.field].url"
              :src="row[column.field].url"
            >
            <button
              v-if="row[column.field].url"
              class="delete is-small img-del"
              type="button"
              @click="deleteFile(row[column.field])"
            />
            <b-upload
              v-else
              v-model="row[column.field].file"
              class="td-upload"
              drag-drop
              @input="fileAdd(row, column.field)"
            >
              <img>
            </b-upload>
          </div>
          <span
            v-else-if="
              column.editable &&
                (column.fieldType == 'textbox' ||
                  column.fieldType == 'autocomplete' ||
                  column.fieldType == 'textarea')
            "
          >
            <input
              v-model="row[column.field]"
              class="input grid-text"
              type="text"
            >
          </span>
          <span
            v-else-if="column.fieldType == 'combobox'"
          >
            <b-select
              v-model="row[column.field]"
              expanded
              class="grid-text"
              :disabled="column.editable ? false : true"
            >
              <option
                v-for="option in column.comboData"
                :key="option.value"
                :value="option.value"
              >
                {{ option.description }}
              </option>
            </b-select>
          </span>
          <span
            v-else-if="column.editable && column.fieldType == 'datetime'"
          >
            <date-picker
              v-model="row[column.field]"
              expanded
              class="grid-text"
              :name="column.field"
              :today-btn-show="true"
              :init-date="new Date(row[column.field])"
              @selectedDate="(param) => {row[column.field] = param.value}"
            />
          </span>
          <div
            v-else-if="column.editable && column.fieldType == 'numberinput'"
            style="display:flex; justify-content: flex-end;"
          >
            <span
              v-if="!focusNumberInput(row)"
              class="grid-text"
              style="overflow: hidden;"
            >
              {{
                row[column.field]
                  ? Number(row[column.field]).toLocaleString()
                  : 0
              }}
            </span>
            <b-numberinput
              v-if="focusNumberInput(row)"
              v-model="row[column.field]"
              :step="column.step"
              :min="column.min"
              :max="column.max"
              class="grid-text"
              size="is-small"
              type="button"
              @keyup.native="checkNumberkey($event, column.field, row)"
              @keydown.native="preventExponential"
              @input="setNumberParam($event, column.field, row)"
            />
          </div>
          <div
            v-else-if="column.editable && column.fieldType == 'popup'"
            @click="openPopup(column.field, row)"
          >
            <span class="grid-text">
              {{ row[column.field] }}
            </span>
          </div>
          <span
            v-else-if="!column.numeric"
            class="grid-text"
          >
            {{ row[column.field] }}
          </span>
          <span
            v-else
            class="grid-text"
          >
            {{
              row[column.field]
                ? Number(row[column.field]).toLocaleString()
                : 0
            }}
          </span>
        </u-table-column>
      </template>
      <template v-slot:bottom-left>
        <slot name="bottom-lt" />
      </template>
      <template v-slot:empty>
        <section class="section">
          <div class="content has-text-grey has-text-centered">
            <p>
              <b-icon
                icon="frown"
                size="is-large"
              />
            </p>
            <p>데이터가 없습니다.</p>
          </div>
        </section>
      </template>
    </u-table>
  </div>
</template>

<script>
import Table from '../table/Table.vue';
import TableColumn from '../table/TableColumn.vue';

export default {
  components: {
    uTable: Table,
    uTableColumn: TableColumn,
  },
  props: {
    headers: Array,
    gridData: Array,
    gridPage: {
      type: Number,
      default: 50,
    },
    pageAble: {
      type: Boolean,
      default: true,
    },
    isLoading: Boolean,
    serviceName: String,
    methodName: String,
    eventInfo: String,
    checkable: {
      type: Boolean,
      default: false,
    },
    multiHeader: {
      type: Boolean,
      default: false,
    },
    basicRow: Object,
    popupSelect: Array,
    oneCheck: Boolean,
    importData: Array,
    asyncData: Boolean,
    total: Number,
    initCheckedRows: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {
      keyCol: '',
      checkedRows: [],
      selectedRow: {},
      addData: [],
      isImg: false,
      imgCol: [],
      insertFiles: {},
      deleteFiles: [],
      page: 1,
      currentP: 1,
      sortField: '',
      sortOrder: '',
    };
  },
  watch: {
    eventInfo(newVal) {
      switch (newVal) {
        case 'update':
          this.updateRows();
          break;
        case 'delete':
          this.deleteRows();
          break;
        case 'add':
          this.addRow();
          break;
        case 'discard':
          this.discardRow(this.selectedRow);
          break;
        case 'insert':
          this.insertRows();
          break;
        case 'startProcess':
          this.startProcess();
          break;
        case 'holdProcess':
          this.holdProcess();
          break;
        case 'finishProcess':
          this.finishProcess();
          break;
        case 'resetCurrentPage':
          this.resetCurrentPage();
          break;
        default:
          break;
      }
    },
    popupSelect(newVal) {
      this.changeSelectRow(newVal);
    },
    importData(newVal) {
      const importData = JSON.parse(JSON.stringify(newVal));
      this.addData = this.addData.concat(importData);
      importData.forEach((row) => {
        this.checkedRows.push(row);
      });
    },
    gridData(newVal) {
      if (this.isImg) {
        newVal.forEach((row, index) => {
          this.imgCol.forEach((col) => {
            if (row[col].url != null) {
              newVal[index][col].url = this.setFile(row[col].url, row[`${col}_typ`]);
            }
          });
        });
      }
    },
    initCheckedRows(newVal) {
      this.checkedRows = newVal;
    },
  },
  mounted() {
    this.init();
  },
  methods: {
    init() {
      this.setCombo();
      this.setKeyCol();
    },
    focusNumberInput(row) {
      if (row[`${this.keyCol}`] === this.selectedRow[`${this.keyCol}`]) {
        return true;
      }
      return false;
    },
    resetRows() {
      this.checkedRows = [];
      this.insertFiles = {};
      this.deleteFiles = [];
    },
    changeSelectRow(newVal) {
      newVal.forEach((val) => {
        const { key } = val;
        const { value } = val;
        if (key) {
          this.selectedRow[key] = value;
        }
      });
    },
    openPopup(field, row) {
      this.selectedRow = row;
      this.$emit(`popup-${field}`, row);
    },
    setCombo() {
      const tmp = this._props.headers;
      const servicePath = `/${this._props.serviceName}/${this._props.methodName}`;
      tmp.map((combo) => {
        if (combo.fieldType === 'combobox') {
          const param = { where: combo.where };
          this.$service.read(servicePath, param).then(({ data }) => {
            combo.comboData = data;
          });
        }
      });
    },
    setKeyCol() {
      this._props.headers.forEach((e) => {
        if (e.group === 'key') {
          this.keyCol = e.field;
        }
        if (e.fieldType === 'img') {
          this.imgCol.push(e.field);
          this.isImg = true;
        }
      });
    },
    addRow() {
      const row = JSON.parse(JSON.stringify(this.basicRow));
      if (this.addData.length === 0) {
        this.checkedRows = [];
      }
      this.addData.push(row);
      this.checkedRows.push(row);
      this.$emit('reset');
    },
    discardRow(row) {
      if (row.flag === 'ADD') {
        const indexAdd = this.addData.indexOf(row);
        this.addData.splice(indexAdd, 1);
        const indexCheck = this.checkedRows.indexOf(row);
        this.checkedRows.splice(indexCheck, 1);
      }
      this.$emit('reset');
    },
    setInsertImg(row) {
      const keycol = this.keyCol;
      this.imgCol.forEach((col) => {
        const key = `${row[keycol]},${col}`;
        if (row[col].file != null) {
          this.insertFiles[key] = row[col].file;
        }
      });
    },
    setDeleteImg(row, flag) {
      const keycol = this.keyCol;
      this.imgCol.forEach((col) => {
        const key = `${col}_no`;
        if (flag === 'del') {
          this.deleteFiles.push(Number(row[key]));
        } else if (flag === 'upd') {
          if (row[key] != null && row[col].no == null) {
            this.deleteFiles.push(Number(row[key]));
          }
        }
      });
    },
    insertRows() {
      const temp = [];
      this.checkedRows.forEach((row) => {
        if (this.isImg && row.flag === 'ADD') {
          this.setInsertImg(row);
        }
        temp.push(JSON.parse(JSON.stringify(row)));
      });
      if (this.isImg) {
        this.$emit('getImage', this.insertFiles);
      }
      this.$emit('insert', JSON.parse(JSON.stringify(temp)));
      this.resetRows();
      this.addData = [];
    },
    updateRows() {
      const temp = [];
      this.checkedRows.forEach((row) => {
        if (row.flag !== 'ADD') {
          temp.push(JSON.parse(JSON.stringify(row)));
        }
        if (this.isImg && row.flag !== 'ADD') {
          this.setInsertImg(row);
          this.setDeleteImg(row, 'upd');
        }
      });
      if (this.isImg) {
        this.$emit('getImage', this.insertFiles);
        this.$emit('delImage', this.deleteFiles);
      }
      this.$emit('update', JSON.parse(JSON.stringify(temp)));
      this.resetRows();
    },
    deleteRows() {
      const temp = [];
      this.checkedRows.forEach((row) => {
        if (row.flag !== 'ADD') {
          temp.push(JSON.parse(JSON.stringify(row)));
        }
        if (this.isImg && row.flag !== 'ADD') {
          this.setDeleteImg(row, 'del');
        }
      });
      if (this.isImg) {
        this.$emit('delImage', this.deleteFiles);
      }
      this.$emit('delete', JSON.parse(JSON.stringify(temp)));
      this.resetRows();
    },
    checkNumberkey(e, field, row) {
      if (!(e.keyCode >= 48 && e.keyCode <= 57)
        && !(e.keyCode >= 96 && e.keyCode <= 105)
        && !(e.keyCode === 8 || e.keyCode === 13)
        && !(e.keyCode === 37 || e.keyCode === 39)) {
        if (row.flag === 'ADD') {
          const index = this.addData.indexOf(row);
          e.target.value = this.addData[index][field];
        } else {
          const index = this.gridData.indexOf(row);
          e.target.value = this.gridData[index][field];
        }
      }
    },
    preventExponential(e) {
      if (e.keyCode === 69) {
        e.preventDefault();
      }
    },
    setNumberParam(e, field, row) {
      if (row.flag === 'ADD') {
        const index = this.addData.indexOf(row);
        if (typeof e === 'number') {
          this.addData[index][field] = e;
        }
      } else {
        const index = this.gridData.indexOf(row);
        if (typeof e === 'number') {
          this.gridData[index][field] = e;
        }
      }
    },
    startProcess() {
      const temp = [];
      this.checkedRows.forEach((row) => {
        if (row.flag !== 'ADD') {
          temp.push(JSON.parse(JSON.stringify(row)));
        }
      });
      this.$emit('update', JSON.parse(JSON.stringify(temp)));
      this.resetRows();
    },
    holdProcess() {
      const temp = [];
      this.checkedRows.forEach((row) => {
        if (row.flag !== 'ADD') {
          temp.push(JSON.parse(JSON.stringify(row)));
        }
      });
      this.$emit('update', JSON.parse(JSON.stringify(temp)));
      this.resetRows();
    },
    finishProcess() {
      const temp = [];
      this.checkedRows.forEach((row) => {
        if (row.flag !== 'ADD') {
          temp.push(JSON.parse(JSON.stringify(row)));
        }
      });
      this.$emit('update', JSON.parse(JSON.stringify(temp)));
      this.resetRows();
    },
    fileAdd(row, filed) {
      if (!row[filed].file.type.startsWith('image')) {
        this.$buefy.dialog.alert({
          message: '이미지 파일이 아닙니다.',
          type: 'is-danger',
        });
        return;
      }
      if (row[filed].file.size > 3 * 1024 * 1024) {
        this.$buefy.dialog.alert({
          message: '파일 하나 최대 크기 초과(3MB)',
          type: 'is-danger',
        });
        row[filed].file = null;
        return;
      }
      const blob = new Blob([row[filed].file], { type: row[filed].file.type });
      const url = URL.createObjectURL(blob);
      row[filed].url = url;
    },
    setFile(target, typ) {
      // byte배열 String을 blob로 변환
      const str = target.replace(/[[\]]|(\s*)/g, '');
      const arr = str.split(',');
      for (let i = 0; i < arr.length; i++) {
        arr[i] = Number(arr[i]);
      }
      const bytes = new Uint8Array(arr);
      const blob = new Blob([bytes], { type: typ });
      // 변환된 blobURL 생성
      const url = URL.createObjectURL(blob);
      return url;
    },
    deleteFile(row) {
      row.no = null;
      row.url = null;
    },
    onPageChange(page) {
      this.page = page;
      this.$emit('asyncData', this.page, this._props.gridPage, this.sortField, this.sortOrder);
    },
    onSort(field, order) {
      this.sortField = field;
      this.sortOrder = order;
      this.$emit('asyncData', this.page, this._props.gridPage, this.sortField, this.sortOrder);
    },
    resetCurrentPage() {
      this.currentPage = 1;
    },
  },
};
</script>

<style>
@media screen and (min-width: 1023px){
 .grid-text > .datepicker > .dropdown.is-mobile-modal > .dropdown-menu {
    position: fixed!important;
    width: calc(100vw - 100px);
    max-width: 460px;
    max-height: calc(100vh - 120px);
    top: 40%!important;
    left: 50%!important;
    bottom: auto!important;
    right: auto!important;
    -webkit-transform: translate3d(-50%,-25%,0);
    transform: translate3d(-50%,-25%,0);
    white-space: normal;
    overflow-y: auto;
    z-index: 50 !important;
  }
 .grid-text > .datepicker > .dropdown.is-mobile-modal
  > .dropdown-menu > div.dropdown-content > div.dropdown-item {
    position: unset;
  }
  .grid-text > .datepicker > .dropdown.is-mobile-modal > .dropdown-menu {
    border: solid 1px hsl(0, 0%, 75%);
  }
}
@media screen and (min-width: 768px) {
  .e-table > div > .table {
    table-layout: fixed;
  }
  .e-table > div.table-wrapper {
    overflow-x: auto;
  }
  .e-table > div > .table td{
    padding: 0 0.7em;
  }
  .e-table > div > .table td.checkbox-cell,
  .e-table > div > .table th.checkbox-cell {
    text-align: center;
  }
  th {
    justify-content: center;
  }
  span.grid-text,
  input.grid-text,
  div.grid-text > span.select {
    font-size: 0.7rem;
  }
  div.grid-text > div.datepicker > div.dropdown > div > div.control > .is-small.input,
  div.b-numberinput > div.control > input {
    font-size: 0.7rem !important;
  }
  .b-checkbox.checkbox input[type=checkbox]+.check {
    width: 1em;
    height: 1em;
  }
  div.th-wrap {
    font-size: 0.8rem;
  }
}
tr.add-row > td.add-disable {
  background-color: hsl(0, 0%, 95%);
}
.e-table > .table-wrapper > .table > thead {
  background-color: hsl(0, 0%, 96%);
  border-top: solid 1px hsl(0, 0%, 75%);
}
.b-table .table tr.is-selected .checkbox input + .check {
  border-color: #7a7a7a;
}
.b-table .table tr.is-selected .checkbox input:checked+.check {
  background-color: #0a0a0a;
}
.e-table > .table-wrapper > .table > thead > tr > th {
  border: solid 1px hsl(0, 0%, 75%);
}
.e-table > .table-wrapper > .table > thead > tr > th:hover {
  border: solid 1px hsl(0, 0%, 75%);
}
.e-table > .table-wrapper > .table > tbody > tr > td {
  border: solid 1px hsl(0, 0%, 86%);
}
.e-table > .table-wrapper > .table > tbody > tr > td:not(.checkbox-cell) {
  padding: 0;
}
.input.grid-text,
div.grid-text,
div.grid-text > span.select,
div.grid-text > span.select > select,
div.grid-text > div.datepicker,
div.grid-text > div.datepicker > div.dropdown,
div.grid-text > div.datepicker > div.dropdown > div > div.control,
div.grid-text > div.datepicker > div.dropdown > div > div.control > input,
div.grid-text > div.control > input {
  height: 100%;
}
.input.grid-text,
div.grid-text > span.select > select,
div.grid-text > div.datepicker > div.dropdown > div > div.control > input,
div.grid-text > div.control > input {
  border: none;
  box-shadow: none;
  background: transparent;
}
div.grid-text > div.datepicker > div.dropdown > div > div.control > .is-small.input,
div.b-numberinput > div.control > input {
  font-size: 1rem;
}
.b-numberinput input[type=number] {
  text-align: end;
}
div.b-numberinput > div.control {
  margin-right: 0 !important;
}
div.b-numberinput > p.control {
  display: none;
}
span.grid-text {
  padding: 0 0.75em;
}
th.is-sortable > .th-wrap > span {
  display: none;
}
th.is-current-sort > .th-wrap > span {
  display: inherit;
}
.b-checkbox.checkbox .control-label {
  padding-left: 0;
}
.img-cell {
  position: relative;
  padding: calc(0.5em - 1px) calc(0.75em - 1px);
}
.upload-cell {
  height: 100%;
  padding: 0 !important;
}
.td-upload {
  width: 100%;
  height: 100%;
}
.td-upload > div,
.td-upload > input {
  width: 100%;
  border: none !important;
}
.img-del {
  position: absolute;
  right: 0;
  opacity: 0;
}
.img-del:hover {
  opacity: 1;
}
.pagination-link {
  text-decoration: none !important;
}
.pagination-link.is-current {
  background-color: #af191e;
  border-color: #af191e;
  color: #fff !important;
  text-decoration: none !important;
}
@media screen and (min-width: 768px) {
  .e-table > div > .table td{
    height: 30px;
  }
}
@media screen and (max-width: 768px) {
  .b-table .table-wrapper.has-mobile-cards thead {
    display: none;
  }
  .b-table .table-wrapper.has-mobile-cards tfoot th {
    border: 0;
    display: inherit;
  }
  .b-table .table-wrapper.has-mobile-cards tr {
    box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1);
    max-width: 100%;
    position: relative;
    display: block;
  }
  .b-table .table-wrapper.has-mobile-cards tr td {
    border: 0;
    display: inherit;
  }
  .b-table .table-wrapper.has-mobile-cards tr td:last-child {
    border-bottom: 0;
  }
  .b-table .table-wrapper.has-mobile-cards tr:not(:last-child) {
    margin-bottom: 1rem;
  }
  .b-table .table-wrapper.has-mobile-cards tr:not([class*="is-"]) {
    background: inherit;
  }
  .b-table .table-wrapper.has-mobile-cards tr:not([class*="is-"]):hover {
    background-color: inherit;
  }
  .b-table .table-wrapper.has-mobile-cards tr.detail {
    margin-top: -1rem;
  }
  .b-table
    .table-wrapper.has-mobile-cards
    tr:not(.detail):not(.is-empty):not(.table-footer)
    td {
    display: flex;
    width: auto;
    justify-content: space-between;
    text-align: right;
    border-bottom: 1px solid whitesmoke;
  }
  .b-table
    .table-wrapper.has-mobile-cards
    tr:not(.detail):not(.is-empty):not(.table-footer)
    td:before {
    content: attr(data-label);
    font-weight: 600;
    padding-right: 0.5em;
    text-align: left;
  }
  .e-table > .table-wrapper > .table > tbody > tr > td {
    border: solid 1px #f5f5f5;
  }
  .e-table > .table-wrapper > .table > tbody > tr > td:not(.checkbox-cell) {
    padding: 0.5em;
  }
  .input.grid-text,
  div.grid-text > div.control > input,
  div.grid-text > div.datepicker > div.dropdown > div > div.control > input {
    text-align: end;
  }
  span.grid-text {
    align-self: center;
  }
}
</style>
