<template>
    <j-datatable @data-provider="provide"
                 :paginate="true"
                 :per-page="perPage"
                 :page-sizes="pageSizes"
                 :debounce="debounce"
                 :bordered="bordered"
                 :striped="striped"
                 :narrow="narrow"
                 :hoverable="hoverable"
                 :canSearch="canSearch"
                 :debug="debug"
                 :mobileCards="mobileCards"
                 :height="height"
                 ref="table">
        <div slot="debug"
             v-if="debug">
            <template v-for="(c, i) in columns">
                <div :key="i">
                    {{c.field}}
                    <br />
                    header style: {{getHeaderStyle(c)}}
                    <br />
                    header align: {{c.headerAlign}}
                    <br />
                    cell style: {{getCellStyle(c)}}
                    <br />
                    cell align: {{c.cellAlign}}
                    <br />
                    sort dir: {{c.asc ? 'Ascending' : 'Descending'}}
                </div>
            </template>
        </div>
        <slot slot="actions"
              name="actions"></slot>
        <span is="j-tr"
              slot="header">
            <template v-for="(c, i) in columns">
                <span is="j-th"
                      :key="i"
                      scope="col"
                      :style="getHeaderStyle(c)"
                      :class="c.headerClass"
                      v-if="isVoid(c.visible) || c.visible"
                      :dir="getHeaderDir(c)">
                    <slot :name="`${c.field}_header`"
                          v-bind:col="c">
                        <div v-if="isVoid(c.sortable) || c.sortable"
                             class="d-flex align-items-center"
                             style="cursor: pointer;"
                             @click="changeSort(c)">
                            <div class="flex-grow-1"
                                 style="vertical-align: middle">
                                <slot :name="`${c.field}_header_text`"
                                      v-bind:column="c"
                                      v-bind:header="c.header">{{c.header}}</slot>
                            </div>
                            <div class="w-auto"
                                 style="vertical-align: middle">
                                <span class="mdi mdi-18px"
                                      style="width: 18px"
                                      :class="getSortIconClass(c)"
                                      :style="getSortIconStyle(c)">
                                </span>
                                <span style="width: 8px">
                                    {{getSortNumber(c)}}
                                </span>
                            </div>
                        </div>
                        <div v-else>
                            <slot :name="`${c.field}_header_text`"
                                  v-bind:column="c"
                                  v-bind:header="c.header">{{c.header}}</slot>
                        </div>
                    </slot>
                </span>
            </template>
        </span>
        <span is="j-tr"
              slot-scope="a"
              :key="a.index">
            <template v-for="(c, i) in columns">
                <span is="j-td"
                      :key="i"
                      :data-label="c.header"
                      :style="getCellStyle(c)"
                      :class="c.cellClass"
                      v-if="isVoid(c.visible) || c.visible">
                    <!-- :dir="getCellDir(c)" -->
                    <slot :name="c.field"
                          v-bind:row="a.row"
                          v-bind:value="a.row[c.field]"></slot>
                </span>
            </template>
        </span>
    </j-datatable>
</template>

<script>
import loc from './j-datatable-server.resx';
import { i18n } from "../../localization/vue-i18n";
import { getOpacityCss } from "libj-core";
import maxBy from 'lodash.maxby';
import sortBy from 'lodash.sortby';
export default {
    i18n: i18n(loc),
    props: {
        perPage: {
            type: Number,
            default: 10
        },
        pageSizes: {
            type: Array,
            default() {
                return [5, 10, 15, 20, 25, 40, 50];
            }
        },
        debounce: {
            type: Number,
            default: 1000
        },
        bordered: {
            type: Boolean,
            default: true,
        },
        striped: {
            type: Boolean,
            default: true,
        },
        narrow: {
            type: Boolean,
            default: true,
        },
        hoverable: {
            type: Boolean,
            default: true,
        },
        canSearch: {
            type: Boolean,
            default: true
        },
        debug: {
            type: Boolean,
            default: false
        },
        mobileCards: {
            type: Boolean,
            default: true
        },
        height: {
            type: String,
            default: null
        },
        //array of { 
        //  header, 
        //  field,
        //  visible, 
        //  headerStyle, 
        //  headerClass, 
        //  headerAlign: 'left, right, center',
        //  cellStyle, 
        //  cellClass,
        //  cellAlign: 'left, right, center',
        //  sortable,
        //  sortField: 'sort column or property', defaults to "field"
        // }
        cols: {
            type: Array,
            default() {
                return [];
            }
        },
        // object of type {field: '', asc: null or true or false}
        defaultSort: {
            type: Object,
            default() {
                return null;
            }
        },
        requestOnMount: {
            type: Boolean,
            default: true
        }
    },
    data() {
        return {
            columns: []
        };
    },
    mounted() {
        this.updateColumnsFromCols();
        if (this.requestOnMount) {
            this.$nextTick(() => {
                this.$refs.table.refresh();
            });
        }
    },
    methods: {
        isVoid(a) {
            return a === undefined || a === null
        },
        //public methods.................................................
        refresh() {
            this.$refs.table.refresh();
        },
        changePage(value) {
            this.$refs.table.changePage(value);
        },
        getRows() {
            return this.$refs.table.getRows();
        },
        updateRow(row, index) {
            return this.$refs.table.updateRow(row, index);
        },
        addRow(row) {
            return this.$refs.table.addRow(row);
        },
        deleteRow(index) {
            return this.$refs.table.deleteRow(index);
        },
        //private methods.................................................
        provide(eventArgs) {
            const { request, response, callback } = eventArgs;
            const { page, search, pageLength } = request;
            if (page <= 0) {
                this.$toast.show({
                    color: 'error',
                    message: this.$t('CannotShowAllRows')
                });
                response.rows = [];
                response.totalRows = 0;
                callback(eventArgs);
            } else {
                this.$emit('data-provider', {
                    search: search,
                    page: page,
                    rowsPerPage: pageLength,
                    sorts: this.getSorts(),
                    callback: (rows, totalRows) => {
                        response.rows = rows === undefined || rows === null ? [] : rows;
                        response.totalRows = totalRows === undefined || totalRows === null ? 0 : totalRows;
                        callback(eventArgs);
                    }
                });
            }
        },
        getSorts() {
            var k = this.columns.filter(a => a.sort.number > 0);
            k = sortBy(k, a => a.sort.number);
            return k.map(a => {
                return {
                    column: this.getSortField(a),
                    ascending: a.sort.dir === 'asc'
                };
            });
        },
        getSortField(c) {
            return c.sortField === undefined || c.sortField === null ? c.field : c.sortField;
        },
        getSortNumber(c) {
            return c.sort.number === 0 ? '' : c.sort.number;
        },
        getSortIconClass(c) {
            if (c.sort.dir === 'none') {
                return 'mdi-arrow-down';
            }
            if (c.sort.dir === 'asc') {
                return 'mdi-arrow-down';
            }
            if (c.sort.dir === 'desc') {
                return 'mdi-arrow-up';
            }
            return 'mdi-arrow-down';
        },
        getSortIconStyle(c) {
            if (c.sort.dir === 'none') {
                return getOpacityCss(0.2);
            }
            if (c.sort.dir === 'asc') {
                return getOpacityCss(1);
            }
            if (c.sort.dir === 'desc') {
                return getOpacityCss(1);
            }
            return getOpacityCss(0.01);
        },
        changeSort(c) {
            if (c.sort.dir === 'asc') {
                c.sort.dir = 'desc';
            } else if (c.sort.dir === 'desc') {
                c.sort.dir = 'none';
                //decrement bigger numbers
                this.columns.filter(a => a.sort.number > c.sort.number)
                    .forEach(a => {
                        a.sort.number--;
                    });
                c.sort.number = 0;
            } else if (c.sort.dir === 'none') {
                c.sort.dir = 'asc';
                //get max number
                var number;
                var lastCol = maxBy(this.columns, a => a.sort.number);
                if (lastCol === undefined || lastCol === null || lastCol.length === 0) {
                    number = 1;
                } else {
                    number = lastCol.sort.number + 1;
                }
                c.sort.number = number;
            }
            this.changePage(1);
        },
        updateColumnsFromCols() {
            this.columns.splice(0, this.columns.length);
            this.cols.forEach(a => {
                var x = Object.assign({}, a);
                x.sort = {
                    dir: 'none',   //'asc', 'desc', 'none'
                    number: 0      //0, Number
                };
                if (!(a.visible === false || a.sortable === false)) {
                    var ds = this.defaultSort;
                    if (ds !== undefined && ds !== null && ds.field !== undefined && ds.field !== null &&
                        ds.field.length > 0 && ds.asc !== undefined && ds.asc !== null &&
                        ds.field === this.getSortField(a)) {
                        x.sort.dir = ds.asc ? 'asc' : 'desc';
                        x.sort.number = 1;
                    }
                }
                this.columns.push(x);
            });
        },
        getHeaderDir(c) {
            if (c.headerAlign === 'right') {
                return 'rtl';
            }
            if (c.headerAlign === 'left') {
                return 'ltr';
            }
            return '';
        },
        getHeaderStyle(c) {
            var res = '';
            if (c.headerStyle !== undefined && c.headerStyle !== null) {
                res = `${c.headerStyle};`;
            }
            if ((c.headerAlign === 'right' || c.headerAlign === 'left' || c.headerAlign === 'center') &&
                res.indexOf('text-align') < 0) {
                res = `${res}text-align:${c.headerAlign} !important;`;
            }
            return res;
        },
        // getCellDir(c) {
        //     if (c.cellAlign === 'right') {
        //         return 'rtl';
        //     }
        //     if (c.cellAlign === 'left') {
        //         return 'ltr';
        //     }
        //     return '';
        // },
        getCellStyle(c) {
            var res = '';
            if (c.cellStyle !== undefined && c.cellStyle !== null) {
                res = `${c.cellStyle};`;
            }
            if ((c.cellAlign === 'right' || c.cellAlign === 'left' || c.cellAlign === 'center') &&
                res.indexOf('text-align') < 0) {
                res = `${res}text-align:${c.cellAlign} !important;`;
            }
            return res;
        }
    },
    watch: {
        cols: {
            handler() {
                this.updateColumnsFromCols();
                this.changePage(1);
            },
            deep: true
        }
    }
}
</script>