<template>
      <div class="field is-grouped is-grouped-multiline pl-2" v-if="filters? filters.length>0 : false">
        <div class="control mr-5">
          <a class="button is-primary is-small has-text-white has-text-weight-bold" @click="updateData({filters: []})">
            <span class="fs-14">Xóa lọc</span>
          </a>
        </div>
        <div class="control pr-2 mr-5">
          <span class="icon-text">
            <SvgIcon v-bind="{name: 'sigma.svg', type: 'primary', size: 20}"></SvgIcon>
            <span class="fsb-18 has-text-primary">{{totalRows}}</span>
          </span>
        </div>
        <div class="control" v-for="(v,i) in filters" :key="i">
          <div class="tags has-addons is-marginless">
            <a class="tag is-primary has-text-white is-marginless" @click="showCondition(v)">{{v.label.indexOf('>')>=0? $stripHtml(v.label,30) : v.label}}</a>
            <a class="tag is-delete is-marginless has-text-black-bis" @click="removeFilter(i)"></a>
          </div>
          <span class="help has-text-black-bis">
            {{v.sort? v.sort : (v.select? ('[' + (v.select.length>0? $stripHtml(v.select[0],20) : '') + '...&#931;' + v.select.length + ']') :
            (v.condition))}}</span>
        </div>
      </div>
    <div class="table-container mb-0" ref="container" id="docid">
    <table class="table is-fullwidth is-bordered is-narrow is-hoverable" :style="tableStyle">
    <thead>
      <tr>
      <th v-for="(field,i) in displayFields" :key="i" :style="field.headerStyle">
      <div @click="showField(field)" :style="field.dropStyle">
        <a v-if="field.label.indexOf('<')<0">{{field.label}}</a>
        <a v-else>
          <component :is="dynamicComponent(field.label)" :row="v" @clickevent="clickEvent($event, v, field)" />
        </a>
      </div>
      </th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(v,i) in displayData" :key="i">
        <td 
          v-for="(field, j) in displayFields" 
          :key="j" 
          :id="field.name" 
          :style="v[`${field.name}color`]"
          style="
            overflow: hidden;
            text-overflow: ellipsis;
          "
          @dblclick="doubleClick(field, v)">
          <component :is="dynamicComponent(field.template)" :row="v" v-if="field.template" @clickevent="clickEvent($event, v, field)" />
          <span v-else>{{ v[field.name] }}</span>
        </td>
      </tr>
    </tbody>
    </table>
    <DatatablePagination
      v-bind="{ data: data, perPage: perPage }"
      @changepage="changePage"
      v-if="showPaging"
    ></DatatablePagination>
  </div>
  <Modal
    @close="close"
    @selected="doSelect"
    @confirm="confirmRemove"
    v-bind="showmodal"
    v-if="showmodal"
  ></Modal>
</template>
<script setup>
import { createApp } from "vue/dist/vue.esm-bundler.js";
import { ref, defineComponent } from "vue";
import { useStore } from "~/stores/index";
const emit = defineEmits(["edit", "insert", "dataevent"]);
const {
  $calc,
  $calculate,
  $calculateData,
  $copy,
  $deleterow,
  $empty,
  $find,
  $getEditRights,
  $formatNumber,
  $multiSort,
  $remove,
  $stripHtml,
  $unique,
} = useNuxtApp();
const store = useStore();
var props = defineProps({
  pagename: String,
});
function dynamicComponent(htmlString) {
  return defineComponent({
    template: htmlString,
    props: {
      row: {
        type: Object,
        default: () => ({}),
      },
    },
  });
}
var timer = undefined;
var showPaging = ref(false);
var totalRows = ref(0);
var currentPage = 1;
var displayFields = ref([]);
var displayData = [];
var pagedata = store[props.pagename];
var tablesetting = $copy(pagedata.tablesetting || store.tablesetting);
var perPage = Number($find(tablesetting, { code: "per-page" }, "detail")) || 20;
var filters = $copy(pagedata.filters || []);
var currentField;
var filterData = [];
var currentsetting;
var scrollbar;
var fields;
var currentRow;
var data = $copy(pagedata.data);
var showmodal = ref();
watch(
  () => store[props.pagename],
  (newVal, oldVal) => {
    updateChange();
  }
);
function updateChange() {
  pagedata = store[props.pagename];
  if (!pagedata.update) return;
  if (pagedata.update.data) data = $copy(pagedata.update.data);
  if (pagedata.update.filters) {
    doFilter(pagedata.update.filters);
    updateShow();
    return; //exit
  }
  if (filters.length > 0) doFilter(filters);
  if (pagedata.update.fields || pagedata.update.data) updateShow();
}
const updateShow = function (full_data) {
  // allowed JS expressions - should return a boolean
  const allowedFns = {
    '$getEditRights()': $getEditRights,
  };
  const arr = pagedata.fields.filter(({ show }) => { 
    if (typeof show === 'boolean') return show;
    else {
      // show is a string
      if (show === 'true') return true; 
      if (show === 'false') return false;
      return allowedFns[show]?.() || false;
    }
  });
  if (full_data === false) displayData = $copy(data);
  else
    displayData = $copy(
      data.filter(
        (ele, index) =>
          index >= (currentPage - 1) * perPage && index < currentPage * perPage
      )
    );
  displayData.map((v) => {
    arr.map((x) => (v[`${x.name}color`] = getStyle(x, v)));
  });
  arr.map((v) => {
    v.headerStyle = getSettingStyle("header", v);
    v.dropStyle = getSettingStyle("dropdown", v);
  });
  displayFields.value = arr;
  showPagination();
};
function confirmRemove() {
  $deleterow(pagedata.api.name, currentRow.id, props.pagename, true);
}
const clickEvent = function (event, row, field) {
  let name = typeof event === "string" ? event : event.name;
  let data = typeof event === "string" ? event : event.data;
  if (name === "remove") {
    currentRow = row;
    showmodal.value = {
      component: `dialog/Confirm`,
      vbind: { content: "Bạn có muốn xóa bản ghi này không?", duration: 10 },
      title: "Xác nhận",
      width: "500px",
      height: "100px",
    };
  }
  emit(name, row, field, data);
};
const showField = async function (field) {
  if (pagedata.contextMenu === false || field.menu === "no") return;
  currentField = field;
  filterData = $unique(pagedata.data, [field.name]);
  //let doc = this.$refs[`th${field.name}`]
  //let width = (doc? doc.length>0 : false)? doc[0].getBoundingClientRect().width : 100
  let width = 100;
  if (pagedata.setting) currentsetting = $copy(pagedata.setting);
  showmodal.value = {
    vbind: {
      pagename: props.pagename,
      field: field,
      filters: filters,
      filterData: filterData,
      width: width,
    },
    component: "datatable/ContextMenu",
    title: field.name,
    width: "650px",
    height: "500px",
  }; //$stripHtml(field.label)
};
const getStyle = function (field, record) {
  var stop = false;
  let val = tablesetting.find((v) => v.code === "td-border")
    ? tablesetting.find((v) => v.code === "td-border").detail
    : "border: solid 1px rgb(44, 44, 44); ";
  val = val.indexOf(";") >= 0 ? val : val + ";";
  if (field.bgcolor ? !Array.isArray(field.bgcolor) : false) {
    val += ` background-color:${field.bgcolor}; `;
  } else if (field.bgcolor ? Array.isArray(field.bgcolor) : false) {
    field.bgcolor.map((v) => {
      if (v.type === "search") {
        if (
          record[field.name] && !stop
            ? record[field.name].toLowerCase().indexOf(v.keyword.toLowerCase()) >= 0
            : false
        ) {
          val += ` background-color:${v.color}; `;
          stop = true;
        }
      } else {
        let res = $calculate(record, v.tags, v.expression);
        if (res.success && res.value && !stop) {
          val += ` background-color:${v.color}; `;
          stop = true;
        }
      }
    });
  }
  stop = false;
  if (field.color ? !Array.isArray(field.color) : false) {
    val += ` color:${field.color}; `;
  } else if (field.color ? Array.isArray(field.color) : false) {
    field.color.map((v) => {
      if (v.type === "search") {
        if (
          record[field.name] && !stop
            ? record[field.name].toLowerCase().indexOf(v.keyword.toLowerCase()) >= 0
            : false
        ) {
          val += ` color:${v.color}; `;
          stop = true;
        }
      } else {
        let res = $calculate(record, v.tags, v.expression);
        if (res.success && res.value && !stop) {
          val += ` color:${v.color}; `;
          stop = true;
        }
      }
    });
  }
  stop = false;
  if (field.textsize ? !Array.isArray(field.textsize) : false) {
    val += ` font-size:${field.textsize}px; `;
  } else if (field.textsize ? Array.isArray(field.textsize) : false) {
    field.textsize.map((v) => {
      if (v.type === "search") {
        if (
          record[field.name] && !stop
            ? record[field.name].toLowerCase().indexOf(v.keyword.toLowerCase()) >= 0
            : false
        ) {
          val += ` font-size:${v.size}px; `;
          stop = true;
        }
      } else {
        let res = $calculate(record, v.tags, v.expression);
        if (res.success && res.value && !stop) {
          val += ` font-size:${v.size}px; `;
          stop = true;
        }
      }
    });
  } else
    val += ` font-size:${
      tablesetting.find((v) => v.code === "table-font-size").detail
    }px;`;
  if (field.textalign) val += ` text-align:${field.textalign}; `;
  if (field.minwidth) val += ` min-width:${field.minwidth}px; `;
  if (field.maxwidth) val += ` max-width:${field.maxwidth}px; `;
  return val;
};
const getSettingStyle = function (name, field) {
  let value = "";
  if (name === "container") {
    value =
      "min-height:" +
      tablesetting.find((v) => v.code === "container-height").detail +
      "rem; ";
  } else if (name === "table") {
    value +=
      "background-color:" +
      tablesetting.find((v) => v.code === "table-background").detail +
      "; ";
    value +=
      "font-size:" +
      tablesetting.find((v) => v.code === "table-font-size").detail +
      "px;";
    value +=
      "color:" + tablesetting.find((v) => v.code === "table-font-color").detail + "; ";
  } else if (name === "header") {
    value +=
      "background-color:" +
      tablesetting.find((v) => v.code === "header-background").detail +
      "; ";
    if (field.minwidth) value += " min-width: " + field.minwidth + "px; ";
    if (field.maxwidth) value += " max-width: " + field.maxwidth + "px; ";
  } else if (name === "menu") {
    let arg = tablesetting.find((v) => v.code === "menu-width").detail;
    arg = field ? (field.menuwidth ? field.menuwidth : arg) : arg;
    value += "width:" + arg + "rem; ";
    value +=
      "min-height:" +
      tablesetting.find((v) => v.code === "menu-min-height").detail +
      "rem; ";
    value +=
      "max-height:" +
      tablesetting.find((v) => v.code === "menu-max-height").detail +
      "rem; ";
    value += "overflow:auto; ";
  } else if (name === "dropdown") {
    value +=
      "font-size:" +
      tablesetting.find((v) => v.code === "header-font-size").detail +
      "px; ";
    let found = filters.find((v) => v.name === field.name);
    found
      ? (value +=
          "color:" +
          tablesetting.find((v) => v.code === "header-filter-color").detail +
          "; ")
      : (value +=
          "color:" +
          tablesetting.find((v) => v.code === "header-font-color").detail +
          "; ");
  }
  return value;
};
function changePage(page) {
  currentPage = page;
  updateShow();
}
const showPagination = function () {
  showPaging.value = pagedata.pagination === false ? false : true;
  totalRows.value = data.length;
  if (showPaging.value && pagedata.api) {
    if (pagedata.api.full_data === false) totalRows.value = pagedata.api.total_rows;
    showPaging.value = totalRows.value > perPage;
  }
};
const close = function () {
  showmodal.value = undefined;
};
const frontendFilter = function (newVal) {
  let checkValid = function (name, x, filter) {
    if ($empty(x[name])) return false;
    else {
      let text = "";
      filter.map((y, k) => {
        text += `${
          k > 0 ? (filter[k - 1].operator === "and" ? " &&" : " ||") : ""
        } ${$formatNumber(x[name])} 
              ${
                y.condition === "=" ? "==" : y.condition === "<>" ? "!==" : y.condition
              } ${$formatNumber(y.value)}`;
      });
      return $calc(text);
    }
  };
  newVal = $copy(newVal);
  var data = $copy(pagedata.data);
  newVal
    .filter((m) => m.select || m.filter)
    .map((v) => {
      if (v.select) {
        data = data.filter(
          (x) =>
            v.select.findIndex((y) => ($empty(y) ? $empty(x[v.name]) : y === x[v.name])) >
            -1
        );
      } else if (v.filter) {
        data = data.filter((x) => checkValid(v.name, x, v.filter));
      }
    });
  let sort = {};
  let format = {};
  let list = filters.filter((x) => x.sort);
  list.map((v) => {
    sort[v.name] = v.sort === "az" ? "asc" : "desc";
    format[v.name] = v.format;
  });
  return list.length > 0 ? $multiSort(data, sort, format) : data;
};
const backendFilter = function (newVal) {};
const doFilter = function (newVal, nonset) {
  if (currentPage > 1 && nonset !== true) currentPage = 1;
  if (pagedata.api.full_data) {
    data = frontendFilter(newVal);
    pagedata.dataFilter = $copy(data);
    store.commit(props.pagename, pagedata);
    emit("changedata", newVal);
  } else {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => backendFilter(newVal), 200);
  }
  pagedata.filters = newVal;
  store.commit(props.pagename, pagedata);
  emit("changefilter", newVal ? newVal.length > 0 : false);
};
const doSelect = function (value) {
  showmodal.value = undefined;
  let field = currentField;
  let found = filters.find((v) => v.name === field.name);
  if (found) {
    !found.select ? (found.select = []) : false;
    let idx = found.select.findIndex((x) => x === value);
    idx >= 0 ? $remove(found.select, idx) : found.select.push(value);
    if (found.select.length === 0) {
      idx = filters.findIndex((v) => v.name === field.name);
      if (idx >= 0) $remove(filters, idx);
    }
  } else {
    filters.push({
      name: field.name,
      label: field.label,
      select: [value],
      format: field.format,
    });
  }
  doFilter(filters);
  updateShow();
};
const doubleScroll = function (element) {
  var _scrollbar = document.createElement("div");
  _scrollbar.appendChild(document.createElement("div"));
  _scrollbar.style.overflow = "auto";
  _scrollbar.style.overflowY = "hidden";
  _scrollbar.firstChild.style.width = element.scrollWidth + "px";
  _scrollbar.firstChild.style.height = "1px";
  _scrollbar.firstChild.appendChild(document.createTextNode("\xA0"));
  var running = false;
  _scrollbar.onscroll = function () {
    if (running) {
      running = false;
      return;
    }
    running = true;
    element.scrollLeft = _scrollbar.scrollLeft;
  };
  element.onscroll = function () {
    if (running) {
      running = false;
      return;
    }
    running = true;
    _scrollbar.scrollLeft = element.scrollLeft;
  };
  element.parentNode.insertBefore(scrollbar, element);
  _scrollbar.scrollLeft = element.scrollLeft;
  scrollbar = _scrollbar;
};
const removeFilter = function (i) {
  $remove(filters, i);
  doFilter(filters);
  updateShow();
};
const scrollbarVisible = function () {
  let element = this.$refs["container"];
  if (!element) return;
  let result = element.scrollWidth > element.clientWidth ? true : false;
  if (scrollbar) {
    element.parentNode.removeChild(scrollbar);
    scrollbar = undefined;
  }
  if (result) doubleScroll(element);
};
const updateData = async function (newVal) {
  if (newVal.columns) {
    //change attribute
    fields = $copy(newVal.columns);
    let _fields = fields.filter((v) => v.show);
    data.map((v) => {
      _fields.map((x) => (v[`${x.name}color`] = getStyle(x, v)));
    });
    return updateShow();
  }
  if (newVal.tablesetting) {
    tablesetting = newVal.tablesetting;
    perPage = $formatNumber(tablesetting.find((v) => v.code == "per-page").detail);
    currentPage = 1;
  }
  tablesetting = $copy(pagedata.tablesetting || gridsetting);
  if (tablesetting) {
    perPage = pagedata.perPage
      ? pagedata.perPage
      : Number(tablesetting.find((v) => v.code === "per-page").detail);
  }
  if (newVal.fields) {
    fields = $copy(newVal.fields);
  } else fields = $copy(pagedata.fields);
  if (newVal.data || newVal.fields) {
    let copy = $copy(newVal.data || data);
    this.data = $calculateData(copy, fields);
    let fields = fields.filter((v) => v.show);
    data.map((v) => {
      fields.map((x) => (v[`${x.name}color`] = getStyle(x, v)));
    });
  }
  if (newVal.filters) filters = $copy(newVal.filters);
  else if (pagedata.filters) filters = $copy(pagedata.filters);
  if (newVal.data || newVal.fields || newVal.filters) {
    let copy = $copy(filters);
    filters.map((v, i) => {
      let idx = $findIndex(fields, { name: v.name });
      let index = $findIndex(copy, { name: v.name });
      if (idx < 0 && index >= 0) $delete(copy, index);
      else if (idx >= 0 && index >= 0) copy[index].label = fields[idx].label;
    });
    filters = copy;
    doFilter(filters);
  }
  if (newVal.data || newVal.fields || newVal.filters || newVal.tablesetting) updateShow();
  if (newVal.data || newVal.fields) setTimeout(() => scrollbarVisible(), 100);
  if (newVal.highlight) setTimeout(() => highlight(newVal.highlight), 50);
};
const doubleClick = function (field, v) {
  currentField = field;
  doSelect(v[field.name]);
};
var tableStyle = getSettingStyle("table");
setTimeout(() => updateShow(), 200);
</script>
<style scoped>
:deep(.table tbody tr:hover td, .table tbody tr:hover th) {
  background-color: hsl(0, 0%, 78%);
  color: rgb(0, 0, 0);
}
</style>
