<template>
  <section>
    <div class="box_scroll" :class="addCls">
      <table class="tbl_col_type cgrid" ref="customTable" :class="addTbCls" :style="applyTbStyle">
        <v-runtime-template :template="colsData"></v-runtime-template>
        <v-runtime-template :template="headerData"></v-runtime-template>
        <v-runtime-template :template="bodyData" @hook:updated="setEvents"></v-runtime-template>
      </table>
    </div>

    <v-runtime-template v-if="pagination == true" :template="pagingData"></v-runtime-template>
  </section>
</template>

<script>
import httpClient from '@/common/http-client';
import VRuntimeTemplate from 'v-runtime-template';
import '@/assets/js/script.js';

export default {
  name: 'customGrid',
  props: [
    'url', // 연동 url
    'initialRequest', // false일 시 초기 렌더링 시 백엔드에 요청 하지 않음. 이 경우 readData를 호출하여 그리드 데이터를 할당해 줘야 함
    'pagination', // 페이지 네비게이션 사용 여부
    'pagePerRows', // 페이지 당 개수
    'header', // 사용자정의 header가 있을 경우
    'columns', // 컬럼 정보
    'noDataStr', // 데이터가 없을 때
    'isCheckbox', // 기본 체크박스 그리드일 경우 true
    'addBodyAlign', // TOP, BOTTOM
    'addBodyTmplt', // 추가되는 html
    'addTableStyle', // 추가되는 그리드 style
    'addTbCls', // 추가되는 테이블 클래스
    'addCls', // 추가되는 클래스
    'totalItems', // 부모창에 표시할 총 컨텐츠 개수 변수 명 (더 좋은 방법 있으면 알려주세요.)
    'pageRange', // next or pre 이동할 페이지 단위
  ],
  components: {
    VRuntimeTemplate,
  },
  data() {
    return {
      getParams: {},

      applyTbStyle: 'table-layout: fixed;',
      prevCallOrderKey: '',
      callOrderKey: '',
      callOrderDesc: true,
      colsLen: 0,
      pageCount: 10,
      curPerPage: 5,
      currentIndex: 1,
      totalCount: 0,
      bodyList: [],

      events: [],
      colsData: '',
      headerData: '',
      bodyData: '',
      pagingData: '',
      nextPageRange: 1,
    };
  },
  created() {
    this.cleanData();
    if (this.initialRequest == true) {
      this.readData();
    }
  },
  watch: {
    pagePerRows() {
      this.currentIndex = 1;
      this.curPerPage = this.pagePerRows;
      this.readData();
    },
  },
  methods: {
    getData() {
      return this.bodyList;
    },
    cleanData() {
      if (typeof this.pagePerRows == undefined || this.pagePerRows == null) {
        this.curPerPage = 20;
      } else {
        this.curPerPage = this.pagePerRows;
      }

      if (typeof this.addTableStyle == undefined || this.addTableStyle == null) {
        this.applyTbStyle = 'table-layout: fixed;';
      } else {
        this.applyTbStyle = this.addTableStyle;
      }

      this.getParams = {};

      this.prevCallOrderKey = '';
      this.callOrderKey = '';
      this.callOrderDesc = true;
      this.colsLen = 0;
      this.currentIndex = 1;
      this.totalCount = 0;
      this.bodyList = [];

      this.events = [];
      this.colsData = '';
      this.headerData = '';
      this.bodyData = '';
      this.pagingData = '';
      this.nextPageRange = 1;
    },
    readData(isKeep) {
      if (typeof this.url != undefined && this.url != null && this.url != '') {
        if (isKeep == true) {
          // nothing
        } else {
          if (this.pagination == true) {
            this.getParams['pagePerRows'] = this.curPerPage;
            this.getParams['page'] = this.currentIndex;
          } else {
            delete this.getParams['pagePerRows'];
            delete this.getParams['page'];
          }
        }

        let colStr = this.makeColGroupView();
        let headerStr = this.makeHeaderView();
        let bodyStr = '';
        let pageStr = '';

        var vm = this;
        httpClient
          //.get(this.url, { params: this.getParams, headers: { 'Show-Layer': 'Yes' }})
          .post(this.url, this.getParams, { headers: { 'Show-Layer': 'Yes' } })
          .then((response) => {
            let resp = response.data;
            //if (resp != null && resp.result == true) {
            if (resp != null && resp.retCode == '0000') {
              let data = resp.data;
              //let conts = data.contents;
              let conts = data.list;
              vm.bodyList = conts;

              bodyStr = vm.makeBodyView();
              //this.$parent[this.totalItems] = data.pagination.totalCount;
              this.$parent[this.totalItems] = data.paging.totalCnt;

              /*if (vm.pagination == true) {
                vm.currentIndex = data.pagination.page == 0 ? 1 : data.pagination.page;
                vm.totalCount = data.pagination.totalCount;
                pageStr = vm.makePagingView();
              }*/
              if (vm.pagination == true) {
                vm.currentIndex = data.paging.page == 0 ? 1 : data.paging.page;
                vm.totalCount = data.paging.totalCnt;
                pageStr = vm.makePagingView();
                if (typeof this.pageRange != 'undefined') {
                  vm.nextPageRange = this.pageRange;
                }
              }
              // 조회결과 없음.
            } else if (resp != null && resp.retCode == '1004') {
              let data = resp.data;
              //let conts = data.contents;
              let conts = data.list;
              vm.bodyList = conts;

              bodyStr = vm.makeBodyView();
              this.$parent[this.totalItems] = 0;
            }

            vm.setTableView(colStr, headerStr, bodyStr, pageStr);
          })
          .catch((response) => {
            bodyStr = vm.makeBodyView();
            if (vm.pagination == true) {
              vm.currentIndex = 1;
              vm.totalCount = 0;
              pageStr = vm.makePagingView();
            }
            vm.setTableView(colStr, headerStr, bodyStr, pageStr);
          });
      }
    },
    reloadData() {
      this.movePage(1, true);
    },
    search(params, isKeep) {
      if (params == undefined || params == null) {
        params = {};
        this.currentIndex = 1;
        this.callOrderKey = '';
      }
      if (isKeep == undefined || isKeep == null || typeof isKeep != 'boolean') {
        isKeep = false;
        this.currentIndex = 1;
        this.callOrderKey = '';
      }

      this.getParams = {};
      this.getParams = params;
      this.readData(isKeep);
    },

    setTableView(colStr, headerStr, bodyStr, pageStr) {
      this.colsData = colStr;
      this.headerData = headerStr;
      this.bodyData = bodyStr;
      this.pagingData = pageStr;
    },
    setEvents() {
      for (var i = 0; i < this.events.length; i++) {
        let e = this.events[i];
        let cls = e.cls;
        let addCls = '';
        for (var c = 0; c < cls.getElement().classList.length; c++) {
          addCls += '.' + cls.getElement().classList[c];
        }

        if (addCls != '') {
          let selQuery = this.$refs.customTable.querySelectorAll(addCls);
          let key = e.key;
          if (selQuery.length > 0 && typeof selQuery[key] != undefined && selQuery[key] != null) {
            cls.addEvent(selQuery[key]);
          }
        }
      }
    },
    makeColGroupView() {
      this.colsLen = 0;
      let colGroup = '';
      colGroup += '<colgroup>';
      if (this.isCheckbox == true) {
        //colGroup += '<col style="width: 60px">';
        colGroup += '<col style="width: 4%">';
        this.colsLen++;
      }

      for (var i = 0; i < this.columns.length; i++) {
        let colData = this.columns[i];
        if (colData.hidden != undefined && colData.hidden == true) {
        } else {
          let cw = colData.width;
          if (typeof cw == undefined || cw == null || cw == '') {
            cw = '';
          } else if (Number(cw) > 0) {
            cw += 'px';
          }

          if (cw == '') {
            colGroup += '<col>';
          } else {
            colGroup += '<col style="width: ' + cw + '">';
          }
          this.colsLen++;
        }
      }

      colGroup += '</colgroup>';
      return colGroup;
    },
    makeHeaderView() {
      let skipHeader = [];
      let mustHeader = [];

      let tHead = '';
      tHead += '<thead>';

      if (this.header != undefined && this.header != null && this.header.length > 0) {
        tHead += '<tr>';
        let rLen = this.header.length + 1;
        if (this.isCheckbox == true) {
          tHead +=
            '<th scope="col" rowspan="' +
            rLen +
            '"><span class="custom_checkbox"><input type="checkbox" name="checkboxAll" @click="checkAll" id="checkboxAll"> <label for="checkboxAll"></label></span></th>';
        }

        for (var i = 0; i < this.header.length; i++) {
          let hDataList = this.header[i];
          for (var j = 0; j < hDataList.length; j++) {
            let hData = hDataList[j];

            let cdata = hData.childNames;
            let hStr = hData.header;
            if (typeof hStr == undefined || hStr == null) {
              hStr = '';
            }
            if (typeof cdata == undefined || cdata == null || cdata.length == 0) {
              tHead += '<th scope="col" rowspan="' + rLen + '">' + hStr + '</th>';
              skipHeader.push(hStr);
            } else {
              let cLen = cdata.length;
              let chId = 'thHeader' + i + '' + j;
              tHead +=
                '<th scope="colgroup" colspan="' + cLen + '" class="th_line" id="' + chId + '">' + hStr + '</th>';
              for (var k = 0; k < cLen; k++) {
                mustHeader.push(chId);
              }
            }
          }
        }

        tHead += '<tr>';
      } else {
        tHead += '<tr>';
        if (this.isCheckbox == true) {
          tHead +=
            '<th><span class="custom_checkbox"><input type="checkbox" name="checkboxAll" @click="checkAll" id="checkboxAll"> <label for="checkboxAll"></label></span></th>';
        }
      }

      let colIdx = 0;
      for (var i = 0; i < this.columns.length; i++) {
        let colData = this.columns[i];
        if (colData.hidden == true) {
        } else {
          let cheader = colData.header;
          let hd = '';
          if (cheader == undefined || cheader == null || cheader == '') {
            cheader = '';
          } else {
            if (skipHeader.length > 0 && skipHeader.includes(cheader)) {
              continue;
            }

            hd = '<th';
            if (mustHeader.length > 0) {
              let hs = mustHeader[colIdx];
              if (hs != undefined && hs != null) {
                hd += ' headers="' + hs + '" class="th_line"';
                colIdx++;
              }
            }

            if (colData.sort == true) {
              let orderKey = colData.name;
              let sortHd = ' class="sort_table">';
              sortHd += '<strong>';
              sortHd += cheader;
              sortHd +=
                '<a href="javascript:void(0);" class="btn_sort" @click="sortData(\'' + orderKey + '\')">정렬</a>';
              sortHd += '</strong>';
              hd += sortHd;
            } else {
              hd += '>' + cheader;
            }
          }

          tHead += hd + '</th>';
        }
      }

      tHead += '</tr></thead>';
      return tHead;
    },
    makeBodyView() {
      this.events = [];
      let tBody = '';
      tBody += '<tbody>';

      if (this.bodyList != undefined && this.bodyList != null && this.bodyList.length > 0) {
        if (this.addBodyAlign == 'TOP') {
          tBody += this.addBodyTmplt;
        }

        for (var b = 0; b < this.bodyList.length; b++) {
          let bData = this.bodyList[b];

          let trStr = '<tr>';
          if (this.isCheckbox == true) {
            trStr +=
              '<td><span class="custom_checkbox single"><input type="checkbox" name="checkbox" @click="check" id="checkbox' +
              b +
              '"> <label for="checkbox' +
              b +
              '"></label></span></td>';
          }

          let colIdx = 0;
          for (var i = 0; i < this.columns.length; i++) {
            let colData = this.columns[i];
            if (colData.hidden == true) continue;

            let cname = colData.name;
            let crenderer = colData.renderer;
            let formatter = colData.formatter;
            let cdefaultText = colData.defaultText;
            let align = colData.align;
            let csubtlb = colData.subtlb;
            let tooltipTextCol = colData.tooltipTextCol;

            let cls = colData.cls;
            if (cls == undefined || cls == null) {
              cls = '';
            }

            const customTd = document.createElement('td');
            customTd.className = cls;
            if (align == 'left' || align == 'right') {
              customTd.style.textAlign = align;
            }

            let cw = colData.width;
            if (cw == undefined || cw == null || cw == '') {
              cw = '';
            } else if (Number(cw) > 0) {
              cw += 'px';
            }

            bData['cgridwidth'] = cw;

            if (crenderer != undefined && crenderer != null) {
              let customCls = crenderer.type;
              bData['rowKey'] = b;

              let tdv = this.makeTdText(formatter, bData, cname, cdefaultText);

              bData['colValue'] = this.customReplaceStr(tdv);
              bData['colName'] = cname;
              if (crenderer.options != undefined && crenderer.options != null) {
                let opts = { options: crenderer.options };
                if (cname == undefined || cname == null || cname == '') {
                  bData['cgrido'] = opts;
                } else {
                  bData['cgrido' + cname] = opts;
                }
              }
              let initCls = new customCls(bData);
              let el = initCls.getElement();
              let oh = el.outerHTML;

              customTd.innerHTML = this.customReplaceStr(oh);

              this.events.push({ cls: initCls, key: b });
            } else if (csubtlb != undefined && csubtlb != null) {
              customTd.innerHTML = this.makeDoubleRowColumn(csubtlb, bData);
            } else {
              customTd.innerHTML = this.makeTooltip(
                bData,
                colData,
                this.makeTdText(formatter, bData, cname, cdefaultText)
              );
            }

            trStr += customTd.outerHTML;
            colIdx++;
          }

          trStr += '</tr>';
          tBody += trStr;
        }

        if (this.addBodyAlign == 'BOTTOM') {
          tBody += this.addBodyTmplt;
        }
      } else {
        tBody += '<tr><td colspan="' + this.colsLen + '" class="no_data">' + this.noDataStr + '</td></tr>';
      }

      tBody += '</tbody>';
      return tBody;
    },
    makeDoubleRowColumn(csubtlb, bData) {
      let rtnHtml = '<table><tbody>';

      for (var j = 0; j < csubtlb.length; j++) {
        rtnHtml += '<tr><td>';
        let subTlb = csubtlb[j];
        let subName = subTlb.name;
        let subDefaultText = subTlb.defaultText;
        let subFormater = subTlb.formatter;
        let tdv = this.makeTdText(subFormater, bData, subName, subDefaultText);
        rtnHtml += this.makeTooltip(bData, subTlb, tdv);
        rtnHtml += '</td></tr>';
      }

      rtnHtml += '</tbody></table>';

      return rtnHtml;
    },
    makeTdText(formatter, bData, cname, defaultText) {
      if (defaultText != undefined || defaultText != null) return defaultText;

      let tdv = bData[cname];
      if (formatter != undefined && formatter != null && typeof formatter === 'function') {
        tdv = formatter(bData);
        if (tdv == undefined || tdv == null) {
          tdv = bData[cname];
        }
      }
      if (tdv == undefined || tdv == null || tdv == '') {
        tdv = '-';
      }

      return tdv;
    },
    makeTooltip(bData, colData, tdv) {
      if (colData.tooltip == true && tdv != '' && tdv != '-') {
        let inHtml = this.customReplaceStr(tdv);
        let tArea = '<div class="tooltip_area';

        if (colData.tooltipAreaClass != null && colData.tooltipAreaClass != '') tArea += ' ' + colData.tooltipAreaClass;
        tArea += '">';

        tArea += '<div @mouseover="hoverTooltip" class="text_info ellipsis';

        if (colData.tooltipclass != null && colData.tooltipclass != '') tArea += ' ' + colData.tooltipclass;
        tArea += '" style="width:' + bData['cgridwidth'];
        tArea += '">';
        tArea += inHtml;
        tArea += '</div>';
        tArea += '<div class="box_text_tooltip text_absolute">';
        if (colData.tooltipTextCol != undefined && colData.tooltipTextCol != null && colData.tooltipTextCol != '') {
          if (
            bData[colData.tooltipTextCol] != undefined &&
            bData[colData.tooltipTextCol] != null &&
            bData[colData.tooltipTextCol] != ''
          ) {
            tArea += '<p>' + bData[colData.tooltipTextCol] + '</p>';
          } else {
            tArea += '<p>' + inHtml + '</p>';
          }
        } else {
          tArea += '<p>' + inHtml + '</p>';
        }
        tArea += '</div>';
        tArea += '</div>';

        return tArea;
      } else {
        return this.customReplaceStr(tdv);
      }
    },
    customReplaceStr(str) {
      if (str != undefined && str != null) {
        str = new String(str);
        str = str.replace(/{{/g, '{ { ');
        str = str.replace(/}}/g, ' } }');
      } else {
        str = '';
      }
      return str;
    },

    makePagingView() {
      let pData = '<div class="pagination">';

      let totalPage = Math.ceil(this.totalCount / this.curPerPage);
      if (totalPage < 1) {
        totalPage = 1;
      }
      let pageGroup = Math.ceil(this.currentIndex / this.pageCount);
      let last = pageGroup * this.pageCount;
      // let last = 1;
      if (last > totalPage) {
        last = totalPage;
      }

      let first = last - (this.pageCount - 1);
      if (first < 1) {
        first = 1;
      }
      // let prev = first - 1;
      let prev = parseInt(this.currentIndex) - this.nextPageRange;
      if (prev < 1) {
        prev = 1;
      }

      // let next = last + 1;
      let next = parseInt(this.currentIndex) + this.nextPageRange;

      if (next > totalPage) {
        next = totalPage;
      }

      pData += '<div class="arrow-btn">';
      pData += '<button href="javascript:void(0);" @click="movePage(1)" class="btn-first"></button>';
      pData += '<button href="javascript:void(0);" @click="movePage(' + prev + ')" class="btn-prev"></button>';
      pData += '</div>';
      pData += '<ul>';

      for (var i = first; i <= last; i++) {
        let actCls = '';
        if (i == this.currentIndex) {
          actCls = 'class="active"';
        }
        pData += '<li ' + actCls + '><a href="javascript:void(0);" @click="movePage(' + i + ')" >' + i + '</a></li>';
      }
      pData += '</ul>';
      pData += '<div class="arrow-btn">';
      pData += '<button @click="movePage(' + next + ')" class="btn-next"></button>';
      pData += '<button @click="movePage(' + totalPage + ')" class="btn-last"></button>';
      pData += '</div>';
      pData += '</div>';
      return pData;
    },
    movePage(idx, refresh) {
      if (refresh == undefined || refresh == null) {
        refresh = false;
      }
      if (idx != this.currentIndex || refresh == true) {
        this.currentIndex = idx;
        this.readData();
      }
    },

    checkedElementDatas() {
      let checkEls = this.checkEls();
      let checkDatas = [];
      for (var i = 0; i < checkEls.length; i++) {
        let c = checkEls[i];
        if (c.checked === true) {
          checkDatas.push(this.bodyList[i]);
        }
      }

      return checkDatas;
    },
    checkEls() {
      let checkEls = this.$refs.customTable.querySelectorAll("input[name='checkbox']");
      return checkEls;
    },
    check() {
      let checkEls = this.checkEls();
      let cnt = 0;
      for (var i = 0; i < checkEls.length; i++) {
        let c = checkEls[i];
        if (c.checked === true) {
          cnt++;
        }
      }

      let chkAll = this.$refs.customTable.querySelectorAll("input[name='checkboxAll']");
      let allCheck = false;
      if (this.bodyList.length == cnt) {
        allCheck = true;
      }

      for (var i = 0; i < chkAll.length; i++) {
        let c = chkAll[i];
        c.checked = allCheck;
      }
    },
    checkAll() {
      let checkEls = this.checkEls();
      for (var i = 0; i < checkEls.length; i++) {
        let c = checkEls[i];
        c.checked = event.target.checked;
      }
    },
    sortData(orderKey) {
      if (typeof orderKey != undefined && orderKey != null && orderKey != '') {
        this.currentIndex = 1;
        this.callOrderKey = orderKey;

        if (this.callOrderKey != null && this.callOrderKey != '') {
          if (this.prevCallOrderKey != this.callOrderKey) {
            this.callOrderDesc = true;
          } else {
            this.callOrderDesc = !this.callOrderDesc;
          }

          this.prevCallOrderKey = this.callOrderKey;
          let sort = this.callOrderKey;
          if (this.callOrderDesc == false) {
            sort += ' ASC';
          } else {
            sort += ' DESC';
          }

          this.getParams['sort'] = sort;
        } else {
          delete this.getParams['sort'];
        }

        this.readData();
      }
    },
    getPagination() {
      let rslt = {
        _currentPage: this.currentIndex,
        _options: {
          itemsPerPage: this.curPerPage,
          sort: this.getParams['sort'],
        },
      };

      return rslt;
    },
    hoverTooltip(event) {
      var myChild = event.target.querySelector('.box_text_tooltip');
      var rect = event.target.getBoundingClientRect();
      if (myChild != null) {
        myChild.style.top = rect.y + 20 + 'px';
      }
    },
  },
};
</script>

<style></style>
