$(document).ready(function () {
    $.ajaxSetup({cache: false});

    //set locale of moment js
    moment.locale(AppLanugage.locale);

    //set locale for datepicker
    (function ($) {
        $.fn.datepicker.dates['custom'] = {
            days: AppLanugage.days,
            daysShort: AppLanugage.daysShort,
            daysMin: AppLanugage.daysMin,
            months: AppLanugage.months,
            monthsShort: AppLanugage.monthsShort,
            today: AppLanugage.today
        };
    }(jQuery));

    //set datepicker language

    $('body').on('click', '[data-act=ajax-modal]', function () {
        var data = {ajaxModal: 1},
                url = $(this).attr('data-action-url'),
                isLargeModal = $(this).attr('data-modal-lg'),
                isFullscreenModal = $(this).attr('data-modal-fullscreen'),
                isCloseModal = $(this).attr('data-modal-close'),
                title = $(this).attr('data-title');
        if (!url) {
            console.log('Ajax Modal: Set data-action-url!');
            return false;
        }
        if (title) {
            $("#ajaxModalTitle").html(title);
        } else {
            $("#ajaxModalTitle").html($("#ajaxModalTitle").attr('data-title'));
        }

        if ($(this).attr("data-post-hide-header")) {
            $("#ajaxModal .modal-header").addClass("hide");
            $("#ajaxModal .modal-footer").addClass("hide");
        } else {
            $("#ajaxModal .modal-header").removeClass("hide");
            $("#ajaxModal .modal-footer").removeClass("hide");
        }

        $("#ajaxModalContent").html($("#ajaxModalOriginalContent").html());
        $("#ajaxModalContent").find(".original-modal-body").removeClass("original-modal-body").addClass("modal-body");
        $("#ajaxModal").modal('show');
        $("#ajaxModal").find(".modal-dialog").removeClass("custom-modal-lg");
        $("#ajaxModal").find(".modal-dialog").removeClass("modal-fullscreen");
        $("#ajaxModal").removeClass("global-search-modal");

        $(this).each(function () {
            $.each(this.attributes, function () {
                if (this.specified && this.name.match("^data-post-")) {
                    var dataName = this.name.replace("data-post-", "");
                    data[dataName] = this.value;
                }
            });
        });
        ajaxModalXhr = $.ajax({
            url: url,
            data: data,
            cache: false,
            type: 'POST',
            success: function (response) {
                $("#ajaxModal").find(".modal-dialog").removeClass("mini-modal");
                if (isLargeModal === "1") {
                    $("#ajaxModal").find(".modal-dialog").addClass("custom-modal-lg");
                } else if (isFullscreenModal === "1") {
                    $("#ajaxModal").find(".modal-dialog").addClass("modal-fullscreen");
                }

                if (isCloseModal === "1") {
                    $("#ajaxModal").addClass("global-search-modal");
                }

                $("#ajaxModalContent").html(response);

                setSummernoteToAll(true);
                setModalScrollbar();

                feather.replace();
            },
            statusCode: {
                403: function () {
                    console.log("403: Session expired.");
                    location.reload();
                },
                404: function () {
                    $("#ajaxModalContent").find('.modal-body').html("");
                    appAlert.error("404: Page not found.", {container: '.modal-body', animate: false});
                }
            },
            error: function () {
                $("#ajaxModalContent").find('.modal-body').html("");
                appAlert.error("500: Internal Server Error.", {container: '.modal-body', animate: false});
            }
        });
        return false;
    });

    //abort ajax request on modal close.
    $('#ajaxModal').on('hidden.bs.modal', function (e) {
        ajaxModalXhr.abort();
        $("#ajaxModal").find(".modal-dialog").removeClass("modal-lg");
        $("#ajaxModal").find(".modal-dialog").addClass("modal-lg");

        $("#ajaxModalContent").html("");
    });

    //common ajax request
    $('body').on('click show.bs.dropdown', '[data-act=ajax-request]', function () {
        var data = {},
                $selector = $(this),
                url = $selector.attr('data-action-url'),
                removeOnSuccess = $selector.attr('data-remove-on-success'),
                removeOnClick = $selector.attr('data-remove-on-click'),
                fadeOutOnSuccess = $selector.attr('data-fade-out-on-success'),
                fadeOutOnClick = $selector.attr('data-fade-out-on-click'),
                inlineLoader = $selector.attr('data-inline-loader'),
                reloadOnSuccess = $selector.attr('data-reload-on-success'),
                showResponse = $selector.attr('data-show-response');

        var $target = "";
        if ($selector.attr('data-real-target')) {
            $target = $($selector.attr('data-real-target'));
        } else if ($selector.attr('data-closest-target')) {
            $target = $selector.closest($selector.attr('data-closest-target'));
        }

        if (!url) {
            console.log('Ajax Request: Set data-action-url!');
            return false;
        }

        //remove the target element
        if (removeOnClick && $(removeOnClick).length) {
            $(removeOnClick).remove();
        }

        //remove the target element with fade out effect
        if (fadeOutOnClick && $(fadeOutOnClick).length) {
            $(fadeOutOnClick).fadeOut(function () {
                $(this).remove();
            });
        }

        $selector.each(function () {
            $.each(this.attributes, function () {
                if (this.specified && this.name.match("^data-post-")) {
                    var dataName = this.name.replace("data-post-", "");
                    data[dataName] = this.value;
                }
            });
        });
        if (inlineLoader === "1") {
            $selector.addClass("spinning");
        } else {
            appLoader.show();
        }

        var ajaxOptions = {
            url: url,
            data: data,
            cache: false,
            type: 'POST',
            success: function (response) {
                if (inlineLoader === "1") {
                    $selector.removeClass("spinning");
                }


                if (showResponse && response) {
                    if (response.success) {
                        if (response.message) {
                            appAlert.success(response.message, {duration: 10000});
                        }

                        if (reloadOnSuccess) {
                            location.reload();
                        }
                    } else {
                        appAlert.error(response.message);
                    }
                } else if (reloadOnSuccess) {
                    location.reload();
                }

                //remove the target element
                if (removeOnSuccess && $(removeOnSuccess).length) {
                    $(removeOnSuccess).remove();
                }

                //remove the target element with fade out effect
                if (fadeOutOnSuccess && $(fadeOutOnSuccess).length) {
                    $(fadeOutOnSuccess).fadeOut(function () {
                        $(this).remove();
                    });
                }

                appLoader.hide();
                if ($target.length) {
                    if ($selector.attr("data-append")) {
                        $selector.remove();
                        $target.append(response);
                    } else {
                        $target.html(response);
                    }
                }
            },
            statusCode: {
                404: function () {
                    appLoader.hide();
                    appAlert.error("404: Page not found.");
                }
            },
            error: function () {
                appLoader.hide();
                appAlert.error("500: Internal Server Error.");
            }
        };

        if (showResponse) {
            ajaxOptions.dataType = 'json';
        }

        ajaxRequestXhr = $.ajax(ajaxOptions);

    });

    //bind ajax tab
    $('body').on('click', '[data-bs-toggle="ajax-tab"] a', function () {
        var $this = $(this),
                loadurl = $this.attr('href'),
                target = $this.attr('data-bs-target');
        if (!target)
            return false;

        if ($this.attr("data-reload")) {
            //remove data first if it's need to reload everytime
            $(target).html("");
        }

        if ($(target).html() === "" || $this.attr("data-reload")) {
            appLoader.show({container: target, css: "right:50%; bottom:auto;"});

            $.ajax({
                url: loadurl,
                cache: false,
                type: 'GET',
                success: function (response) {
                    $(target).html(response);
                    feather.replace();
                    selectLastlySelectedTab(target);
                },
                statusCode: {
                    403: function () {
                        console.log("403: Session expired.");
                        location.reload();
                    },
                    404: function () {
                        appLoader.hide();
                        appAlert.error("404: Page not found.");
                    }
                },
                error: function () {
                    appLoader.hide();
                    appAlert.error("500: Internal Server Error.");
                }
            });

//            $.get(loadurl, function (data, test, test2) {
//                $(target).html(data);
//                feather.replace();
//                selectLastlySelectedTab(target);
//            });
        }
        window.InstanceCollection = {}; //prevent same filter values from previous tables with same filters
        $this.tab('show');
        return false;
    });

    selectLastlySelectedTab();

    $('body').on('click', '[data-toggle="app-modal"]', function () {
        var sidebar = true;

        if ($(this).attr("data-sidebar") === "0") {
            sidebar = false;
        }

        appContentModal.init({url: $(this).attr("data-url"), sidebar: sidebar});
        return false;
    });




    //prepare common delete confimation
    var recordDeleteHandler = function (result, $target) {
        var callbackFunction = $target.attr("data-success-callback");

        if (callbackFunction && typeof window[callbackFunction] != 'undefined') {
            window[callbackFunction](result, $target);

            if (result.message) {
                appAlert.warning(result.message, {duration: 20000});
            }

        }
    };

    var linkDeleteConfirmationHandler = function (e) {
        deleteConfirmationHandler(e, recordDeleteHandler);
    };


    //bind the delete confimation modal which links are not in tables. because there is an another logic for datatable.
    $('body').on('click', 'a[data-action=delete-confirmation]:not(table a)', linkDeleteConfirmationHandler);

    var addCommentLink = function (event) {
        //modify comment link copied text on pasting
        var clipboardData = event.originalEvent.clipboardData.getData('text/plain');
        if (clipboardData.indexOf('/#comment') > -1) {
            //pasted comment link
            event.preventDefault();

            var splitClipboardData = clipboardData.split("/"),
                    splitClipboardDataCount = splitClipboardData.length,
                    commentId = splitClipboardData[splitClipboardDataCount - 1];

            if (!commentId) {
                //there has an extra / at last
                splitClipboardDataCount = splitClipboardDataCount - 1;
                commentId = splitClipboardData[splitClipboardDataCount - 1];
            }

            var splitCommentId = commentId.split("-");
            commentId = splitCommentId[1];

            var taskId = splitClipboardData[splitClipboardDataCount - 2];

            var newClipboardData = "#[" + taskId + "-" + commentId + "] (" + AppLanugage.comment + ") ";

            document.execCommand('insertText', false, newClipboardData);
        }
    };

    //normal input/textarea
    $('body').on('paste', 'input, textarea', function (e) {
        addCommentLink(e);
    });

    //summernote
    $('body').on('summernote.paste', function (e, ne) {
        addCommentLink(ne);
    });
});


function delayAction(callback, ms) {
    var timer = 0;
    return function () {
        var context = this, args = arguments;
        clearTimeout(timer);
        timer = setTimeout(function () {
            callback.apply(context, args);
        }, ms || 0);
    };
}



//select the lastly selected ajax-tab automatically if it exists user-wise
function selectLastlySelectedTab(target) {
    if (!target) {
        target = "";
    }

    $(target + " [data-bs-toggle='ajax-tab']").each(function () {
        var tabList = $(this).attr("id"),
                lastTab = getCookie("user_" + AppHelper.userId + "_" + tabList),
                $specificTab = $(this).find("[data-bs-target='" + lastTab + "']");

        if (lastTab && $specificTab.attr("data-bs-target")) {
            setTimeout(function () {
                $specificTab.trigger("click");
            }, 50);
        } else {
            //load first tab
            $(this).find("a").first().trigger("click");
        }
    });
}

//custom app form controller
(function ($) {
    $.fn.appForm = function (options) {

        var defaults = {
            ajaxSubmit: true,
            isModal: true,
            closeModalOnSuccess: true,
            dataType: "json",
            showLoader: true,
            onModalClose: function () {
            },
            onSuccess: function () {
            },
            onError: function () {
                return true;
            },
            onSubmit: function () {
            },
            onAjaxSuccess: function () {
            },
            beforeAjaxSubmit: function (data, self, options) {
            }
        };
        var settings = $.extend({}, defaults, options);
        this.each(function () {
            if (settings.ajaxSubmit) {
                validateForm($(this), function (form) {
                    settings.onSubmit();


                    if (settings.isModal) {
                        maskModal($("#ajaxModalContent").find(".modal-body"));
                    } else {
                        $(form).find('[type="submit"]').attr('disabled', 'disabled');
                    }

                    //set empty value to all textarea, if they are empty
                    if (AppHelper.settings.enableRichTextEditor === "1") {
                        $("textarea").each(function () {
                            var $instance = $(this);
                            if ($instance.attr("data-rich-text-editor")) {
                                if ($instance.val() === '<p><br></p>' || $instance.val() === "") {
                                    $instance.val('');
                                } else {
                                    $instance.val($instance.summernote('code'));
                                }
                            }
                        });
                    }

                    $(form).ajaxSubmit({
                        dataType: settings.dataType,
                        beforeSubmit: function (data, self, options) {

                            //Modified \assets\js\jquery-validation\jquery.form.js #1178.
                            //Added data  a.push({name: n, value: v, type: el.type, required: el.required, data: $(el).data()});

                            //to set the convertDateFormat with the input fields, we used the setDatePicker function.
                            //it is the easiest way to regognize the date fields.

                            $.each(data, function (index, obj) {
                                if (obj.data && obj.data.convertDateFormat && obj.value) {
                                    data[index]["value"] = convertDateToYMD(obj.value);
                                }
                            });

                            if (!settings.isModal && settings.showLoader) {
                                appLoader.show({container: form, css: "top:2%; right:46%;"});
                            }


                            settings.beforeAjaxSubmit(data, self, options);
                        },
                        success: function (result) {
                            settings.onAjaxSuccess(result);

                            if (result.success) {
                                settings.onSuccess(result);
                                if (settings.isModal && settings.closeModalOnSuccess) {
                                    closeAjaxModal(true);
                                }

                                //remove summernote from all existing summernote field
                                if (!settings.isModal) {
                                    $(form).find("textarea").each(function () {
                                        if ($(this).attr("data-rich-text-editor") && !$(this).attr("data-keep-rich-text-editor-after-submit")) {
                                            $(this).summernote('destroy');
                                        }
                                    });
                                }

                                appLoader.hide();
                            } else {
                                if (settings.onError(result)) {
                                    if (settings.isModal) {
                                        unmaskModal();
                                        if (result.message) {
                                            appAlert.error(result.message, {container: '.modal-body', animate: false});
                                        }
                                    } else if (result.message) {
                                        appAlert.error(result.message);
                                    }
                                }
                            }

                            $(form).find('[type="submit"]').removeAttr('disabled');
                        }
                    });
                });
            } else {
                validateForm($(this));
            }
        });
        /*
         * @form : the form we want to validate;
         * @customSubmit : execute custom js function insted of form submission. 
         * don't pass the 2nd parameter for regular form submission
         */

        function convertDateToYMD(date) {
            if (date) {
                var dateFormat = AppHelper.settings.dateFormat || "Y.m.d",
                        dateFormat = dateFormat.toLowerCase(),
                        separator = dateFormat.charAt("1"),
                        dateFormatArray = dateFormat.split(separator),
                        yearIndex = 0,
                        monthIndex = 1,
                        dayIndex = 2;

                if (dateFormatArray[1] === "y") {
                    yearIndex = 1;
                } else if (dateFormatArray[2] === "y") {
                    yearIndex = 2;
                }

                if (dateFormatArray[0] === "m") {
                    monthIndex = 0;
                } else if (dateFormatArray[2] === "m") {
                    monthIndex = 2;
                }

                if (dateFormatArray[0] === "d") {
                    dayIndex = 0;
                } else if (dateFormatArray[1] === "d") {
                    dayIndex = 1;
                }

                var dateValue = date.split(separator);

                return dateValue[yearIndex] + "-" + dateValue[monthIndex] + "-" + dateValue[dayIndex];
            }

        }

        function validateForm(form, customSubmit) {
            //add custom method
            $.validator.addMethod("greaterThanOrEqual",
                    function (value, element, params) {
                        var paramsVal = params;
                        if (params && (params.indexOf("#") === 0 || params.indexOf(".") === 0)) {
                            paramsVal = $(params).val();
                        }

                        if (typeof $(element).attr("data-rule-required") === 'undefined' && !value) {
                            return true;
                        }

                        if (!/Invalid|NaN/.test(new Date(convertDateToYMD(value)))) {
                            return !paramsVal || (new Date(convertDateToYMD(value)) >= new Date(convertDateToYMD(paramsVal)));
                        }
                        return isNaN(value) && isNaN(paramsVal)
                                || (Number(value) >= Number(paramsVal));
                    }, 'Must be greater than {0}.');

            //add custom method
            $.validator.addMethod("greaterThan",
                    function (value, element, params) {
                        var paramsVal = params;
                        if (params && (params.indexOf("#") === 0 || params.indexOf(".") === 0)) {
                            paramsVal = $(params).val();
                        }
                        if (!/Invalid|NaN/.test(new Number(value))) {
                            return new Number((value)) > new Number((paramsVal));
                        }
                        return isNaN(value) && isNaN(paramsVal)
                                || (Number(value) > Number(paramsVal));
                    }, 'Must be greater than.');

            //add custom method
            $.validator.addMethod("mustBeSameYear",
                    function (value, element, params) {
                        var paramsVal = params;
                        if (params && (params.indexOf("#") === 0 || params.indexOf(".") === 0)) {
                            paramsVal = $(params).val();
                        }
                        if (!/Invalid|NaN/.test(new Date(convertDateToYMD(value)))) {
                            var dateA = new Date(convertDateToYMD(value)), dateB = new Date(convertDateToYMD(paramsVal));
                            return (dateA && dateB && dateA.getFullYear() === dateB.getFullYear());
                        }
                    }, 'The year must be same for both dates.');

            $(form).validate({
                submitHandler: function (form) {
                    if (customSubmit) {
                        customSubmit(form);
                    } else {
                        return true;
                    }
                },
                highlight: function (element) {
                    $(element).closest('.form-group').addClass('has-error');
                },
                unhighlight: function (element) {
                    $(element).closest('.form-group').removeClass('has-error');
                },
                errorElement: 'span',
                errorClass: 'help-block',
                ignore: ":hidden:not(.validate-hidden)",
                errorPlacement: function (error, element) {
                    if (element.parent('.input-group').length) {
                        error.insertAfter(element.parent());
                    } else {
                        error.insertAfter(element);
                    }
                }
            });
            //handeling the hidden field validation like select2
            $(".validate-hidden").click(function () {
                $(this).closest('.form-group').removeClass('has-error').find(".help-block").hide();
            });
        }

        //show loadig mask on modal before form submission;
        function maskModal($maskTarget) {
            var padding = $maskTarget.height() - 80;
            if (padding > 0) {
                padding = Math.floor(padding / 2);
            }
            $maskTarget.after("<div class='modal-mask'><div class='circle-loader'></div></div>");
            //check scrollbar
            var height = $maskTarget.outerHeight();
            $('.modal-mask').css({"width": $maskTarget.width() + 22 + "px", "height": height + "px", "padding-top": padding + "px"});
            $maskTarget.closest('.modal-dialog').find('[type="submit"]').attr('disabled', 'disabled');
            $maskTarget.addClass("hide");
        }

        //remove loadig mask from modal
        function unmaskModal() {
            var $maskTarget = $(".modal-body").removeClass("hide");
            $maskTarget.closest('.modal-dialog').find('[type="submit"]').removeAttr('disabled');
            $maskTarget.removeClass("hide");
            $(".modal-mask").remove();
        }

        //colse ajax modal and show success check mark
        function closeAjaxModal(success) {
            if (success) {
                $(".modal-mask").html("<div class='circle-done'><i data-feather='check' stroke-width='5'></i></div>");
                setTimeout(function () {
                    $(".modal-mask").find('.circle-done').addClass('ok');
                }, 30);
            }
            setTimeout(function () {
                $(".modal-mask").remove();
                $("#ajaxModal").modal('toggle');
                settings.onModalClose();
            }, 1000);
        }


        this.closeModal = function () {
            closeAjaxModal(true);
        };

        return this;
    };
})(jQuery);

var getWeekRange = function (date) {
    //set first and last day of week
    if (!date)
        date = moment().format("YYYY-MM-DD");

    var dayOfWeek = moment(date).format("E"),
            diff = dayOfWeek - AppHelper.settings.firstDayOfWeek,
            range = {};

    if (diff < 7) {
        range.firstDateOfWeek = moment(date).subtract(diff, 'days').format("YYYY-MM-DD");
    } else {
        range.firstDateOfWeek = moment(date).format("YYYY-MM-DD");
    }

    if (diff < 0) {
        range.firstDateOfWeek = moment(range.firstDateOfWeek).subtract(7, 'days').format("YYYY-MM-DD");
    }

    range.lastDateOfWeek = moment(range.firstDateOfWeek).add(6, 'days').format("YYYY-MM-DD");
    return range;
};

var prepareDefaultFilters = function (settings) {

    var prepareDefaultDateRangeFilterParams = function (settings) {
        if (settings.dateRangeType === "daily") {
            settings.filterParams.start_date = moment().format(settings._inputDateFormat);
            settings.filterParams.end_date = settings.filterParams.start_date;
        } else if (settings.dateRangeType === "monthly") {
            var daysInMonth = moment().daysInMonth(),
                    yearMonth = moment().format("YYYY-MM");
            settings.filterParams.start_date = yearMonth + "-01";
            settings.filterParams.end_date = yearMonth + "-" + daysInMonth;
        } else if (settings.dateRangeType === "yearly") {
            var year = moment().format("YYYY");
            settings.filterParams.start_date = year + "-01-01";
            settings.filterParams.end_date = year + "-12-31";
        } else if (settings.dateRangeType === "weekly") {
            var range = getWeekRange();
            settings.filterParams.start_date = range.firstDateOfWeek;
            settings.filterParams.end_date = range.lastDateOfWeek;
        }
        return settings;
    };


    var prepareDefaultCheckBoxFilterParams = function (settings) {
        var values = [],
                name = "";
        $.each(settings.checkBoxes, function (index, option) {
            name = option.name;
            if (option.isChecked) {
                values.push(option.value);
            }
        });
        settings.filterParams[name] = values;
        return settings;
    };

    var prepareDefaultMultiSelectilterParams = function (settings) {

        $.each(settings.multiSelect, function (index, option) {
            var saveSelection = option.saveSelection,
                    selections = getCookie(option.name);

            var values = [];

            if (saveSelection && selections) {
                selections = selections.split("-");
                values = selections;
            } else {
                $.each(option.options, function (index, listOption) {
                    if (listOption.isChecked) {
                        values.push(listOption.value);
                    }
                });
            }

            settings.filterParams[option.name] = values;
        });

        return settings;
    };

    var prepareDefaultRadioFilterParams = function (settings) {
        $.each(settings.radioButtons, function (index, option) {
            if (option.isChecked) {
                settings.filterParams[option.name] = option.value;
            }
        });
        return settings;
    };

    var prepareDefaultDropdownFilterParams = function (settings) {
        $.each(settings.filterDropdown || [], function (index, dropdown) {
            $.each(dropdown.options, function (index, option) {
                if (option.isSelected) {
                    settings.filterParams[dropdown.name] = option.id;
                }
            });
        });
        return settings;
    };

    var prepareDefaultrSingleDatepickerFilterParams = function (settings) {
        $.each(settings.singleDatepicker || [], function (index, datepicker) {
            $.each(datepicker.options || [], function (index, option) {
                if (option.isSelected) {
                    settings.filterParams[datepicker.name] = option.value;
                }
            });
        });
        return settings;
    };


    var prepareDefaultrRngeDatepickerFilterParams = function (settings) {
        $.each(settings.rangeDatepicker || [], function (index, datepicker) {

            if (datepicker.startDate && datepicker.startDate.value) {
                settings.filterParams[datepicker.startDate.name] = datepicker.startDate.value;
            }

            if (datepicker.startDate && datepicker.endDate.value) {
                settings.filterParams[datepicker.endDate.name] = datepicker.endDate.value;
            }

        });
        return settings;
    };



    settings = prepareDefaultDateRangeFilterParams(settings);
    settings = prepareDefaultCheckBoxFilterParams(settings);
    settings = prepareDefaultMultiSelectilterParams(settings);
    settings = prepareDefaultRadioFilterParams(settings);
    settings = prepareDefaultDropdownFilterParams(settings);
    settings = prepareDefaultrSingleDatepickerFilterParams(settings);
    settings = prepareDefaultrRngeDatepickerFilterParams(settings);


    return settings;
};

var buildFilterDom = function (settings, $instanceWrapper, $instance) {


    var reloadInstance = function ($instance, settings) {

        if (!$instance)
            return false;

        if ($instance.is("table")) {
            $instance.appTable({reload: true, filterParams: settings.filterParams});
        } else {
            $instance.appFilters({reload: true, filterParams: settings.filterParams});
        }
    };


    //prepare search box
    if (settings.search && settings.search.show !== false) {
        var searchDom = '<div class="DTTT_container">'
                + '<input type="search" class="custom-filter-search" name="' + settings.search.name + '" placeholder="' + settings.customLanguage.searchPlaceholder + '">'
                + '</div>';
        $instanceWrapper.find(".custom-toolbar").append(searchDom);

        var wait;
        $instanceWrapper.find(".custom-filter-search").keyup(function () {
            appLoader.show();

            var $search = $(this);
            clearTimeout(wait);

            wait = setTimeout(function () {
                settings.filterParams[settings.search.name] = $search.val();
                reloadInstance($instance, settings);
            }, 700);


        });
    }

    var tableCollapseFilterTempId = getRandomAlphabet(5);

    //add a collapse panel button for mobile devices
    if (settings.isMobile) {

        $instanceWrapper.find(".custom-toolbar").addClass("clearfix");

        if (settings.dateRangeType || typeof settings.checkBoxes[0] !== 'undefined' || typeof settings.multiSelect[0] !== 'undefined' || typeof settings.radioButtons[0] !== 'undefined' || typeof settings.singleDatepicker[0] !== 'undefined' || typeof settings.rangeDatepicker[0] !== 'undefined' || typeof settings.filterDropdown[0] !== 'undefined') {

            var collapsePanelDom = "<div class='float-end'>\
                        <button title='" + AppLanugage.filters + "' class='dropdown-toggle btn btn-default mt0' data-bs-toggle='collapse' data-bs-target='#table-collapse-filter-" + tableCollapseFilterTempId + "' aria-expanded='false'><i data-feather='sliders' class='icon-18'></i></button>\
                    </div>\
                    <div id='table-collapse-filter-" + tableCollapseFilterTempId + "' class='navbar-collapse collapse w100p'></div>";

            $instanceWrapper.find(".custom-toolbar").append(collapsePanelDom);
        }
    }

    //bind refresh icon
    if (settings.reloadSelector && $(settings.reloadSelector).length) {
        $(settings.reloadSelector).click(function () {
            appLoader.show();
            reloadInstance($instance, settings);
        });
    }

    //append filter dom
    var appendFilterDom = function (dom) {
        if (settings.isMobile) {
            //append to collapse panel on mobile device
            $instanceWrapper.find("#table-collapse-filter-" + tableCollapseFilterTempId).append(dom);
        } else {
            $instanceWrapper.find(".custom-toolbar").append(dom);
        }
    };


    //build date wise filter selectors
    if (settings.dateRangeType) {
        var dateRangeFilterDom = '<div class="mr15 DTTT_container">'
                + '<button data-act="prev" class="btn btn-default date-range-selector"><i data-feather="chevron-left" class="icon"></i></button>'
                + '<button data-act="datepicker" class="btn btn-default" style="margin: -1px"></button>'
                + '<button data-act="next"  class="btn btn-default date-range-selector"><i data-feather="chevron-right" class="icon"></i></button>'
                + '</div>';

        appendFilterDom(dateRangeFilterDom);

        var $datepicker = $instanceWrapper.find("[data-act='datepicker']"),
                $dateRangeSelector = $instanceWrapper.find(".date-range-selector");

        //init single day selector
        if (settings.dateRangeType === "daily") {
            var initSingleDaySelectorText = function ($elector) {
                if (settings.filterParams.start_date === moment().format(settings._inputDateFormat)) {
                    $elector.html(settings.customLanguage.today);
                } else if (settings.filterParams.start_date === moment().subtract(1, 'days').format(settings._inputDateFormat)) {
                    $elector.html(settings.customLanguage.yesterday);
                } else if (settings.filterParams.start_date === moment().add(1, 'days').format(settings._inputDateFormat)) {
                    $elector.html(settings.customLanguage.tomorrow);
                } else {
                    $elector.html(moment(settings.filterParams.start_date).format("Do MMMM YYYY"));
                }
            };
            // prepareDefaultDateRangeFilterParams();
            initSingleDaySelectorText($datepicker);

            //bind the click events
            $datepicker.datepicker({
                format: settings._inputDateFormat,
                autoclose: true,
                todayHighlight: true,
                language: "custom"
            }).on('changeDate', function (e) {
                var date = moment(e.date).format(settings._inputDateFormat);
                settings.filterParams.start_date = date;
                settings.filterParams.end_date = date;
                initSingleDaySelectorText($datepicker);

                reloadInstance($instance, settings);

            });

            $dateRangeSelector.click(function () {
                var type = $(this).attr("data-act"), date = "";
                if (type === "next") {
                    date = moment(settings.filterParams.start_date).add(1, 'days').format(settings._inputDateFormat);
                } else if (type === "prev") {
                    date = moment(settings.filterParams.start_date).subtract(1, 'days').format(settings._inputDateFormat)
                }
                settings.filterParams.start_date = date;
                settings.filterParams.end_date = date;
                initSingleDaySelectorText($datepicker);
                reloadInstance($instance, settings);
            });
        }


        //init month selector
        if (settings.dateRangeType === "monthly") {
            var initMonthSelectorText = function ($elector) {
                $elector.html(moment(settings.filterParams.start_date).format("MMMM YYYY"));
            };

            //prepareDefaultDateRangeFilterParams();
            initMonthSelectorText($datepicker);

            //bind the click events
            $datepicker.datepicker({
                format: "YYYY-MM",
                viewMode: "months",
                minViewMode: "months",
                autoclose: true,
                language: "custom",
            }).on('changeDate', function (e) {
                var date = moment(e.date).format(settings._inputDateFormat);
                var daysInMonth = moment(date).daysInMonth(),
                        yearMonth = moment(date).format("YYYY-MM");
                settings.filterParams.start_date = yearMonth + "-01";
                settings.filterParams.end_date = yearMonth + "-" + daysInMonth;
                initMonthSelectorText($datepicker);
                reloadInstance($instance, settings);
            });

            $dateRangeSelector.click(function () {
                var type = $(this).attr("data-act"),
                        startDate = moment(settings.filterParams.start_date),
                        endDate = moment(settings.filterParams.end_date);
                if (type === "next") {
                    var nextMonth = startDate.add(1, 'months'),
                            daysInMonth = nextMonth.daysInMonth(),
                            yearMonth = nextMonth.format("YYYY-MM");

                    startDate = yearMonth + "-01";
                    endDate = yearMonth + "-" + daysInMonth;

                } else if (type === "prev") {
                    var lastMonth = startDate.subtract(1, 'months'),
                            daysInMonth = lastMonth.daysInMonth(),
                            yearMonth = lastMonth.format("YYYY-MM");

                    startDate = yearMonth + "-01";
                    endDate = yearMonth + "-" + daysInMonth;
                }

                settings.filterParams.start_date = startDate;
                settings.filterParams.end_date = endDate;

                initMonthSelectorText($datepicker);
                reloadInstance($instance, settings);
            });
        }

        //init year selector
        if (settings.dateRangeType === "yearly") {
            var inityearSelectorText = function ($elector) {
                $elector.html(moment(settings.filterParams.start_date).format("YYYY"));
            };
            // prepareDefaultDateRangeFilterParams();
            inityearSelectorText($datepicker);

            //bind the click events
            $datepicker.datepicker({
                format: "YYYY-MM",
                viewMode: "years",
                minViewMode: "years",
                autoclose: true,
                language: "custom"
            }).on('changeDate', function (e) {
                var date = moment(e.date).format(settings._inputDateFormat),
                        year = moment(date).format("YYYY");
                settings.filterParams.start_date = year + "-01-01";
                settings.filterParams.end_date = year + "-12-31";
                inityearSelectorText($datepicker);
                reloadInstance($instance, settings);
            });

            $dateRangeSelector.click(function () {
                var type = $(this).attr("data-act"),
                        startDate = moment(settings.filterParams.start_date),
                        endDate = moment(settings.filterParams.end_date);
                if (type === "next") {
                    startDate = startDate.add(1, 'years').format(settings._inputDateFormat);
                    endDate = endDate.add(1, 'years').format(settings._inputDateFormat);
                } else if (type === "prev") {
                    startDate = startDate.subtract(1, 'years').format(settings._inputDateFormat);
                    endDate = endDate.subtract(1, 'years').format(settings._inputDateFormat);
                }
                settings.filterParams.start_date = startDate;
                settings.filterParams.end_date = endDate;
                inityearSelectorText($datepicker);
                reloadInstance($instance, settings);
            });
        }

        //init week selector
        if (settings.dateRangeType === "weekly") {
            var initWeekSelectorText = function ($elector) {
                var from = moment(settings.filterParams.start_date).format("Do MMM"),
                        to = moment(settings.filterParams.end_date).format("Do MMM, YYYY");
                $datepicker.datepicker({
                    format: "YYYY-MM-DD",
                    autoclose: true,
                    calendarWeeks: true,
                    language: "custom",
                    weekStart: AppHelper.settings.firstDayOfWeek
                });
                $elector.html(from + " - " + to);
            };

            //prepareDefaultDateRangeFilterParams();
            initWeekSelectorText($datepicker);

            //bind the click events
            $dateRangeSelector.click(function () {
                var type = $(this).attr("data-act"),
                        startDate = moment(settings.filterParams.start_date),
                        endDate = moment(settings.filterParams.end_date);
                if (type === "next") {
                    startDate = startDate.add(7, 'days').format(settings._inputDateFormat);
                    endDate = endDate.add(7, 'days').format(settings._inputDateFormat);
                } else if (type === "prev") {
                    startDate = startDate.subtract(7, 'days').format(settings._inputDateFormat);
                    endDate = endDate.subtract(7, 'days').format(settings._inputDateFormat);
                }
                settings.filterParams.start_date = startDate;
                settings.filterParams.end_date = endDate;
                initWeekSelectorText($datepicker);
                reloadInstance($instance, settings);
            });

            $datepicker.datepicker({
                format: settings._inputDateFormat,
                autoclose: true,
                calendarWeeks: true,
                language: "custom",
                weekStart: AppHelper.settings.firstDayOfWeek
            }).on("show", function () {
                $(".datepicker").addClass("week-view");
                $(".datepicker-days").find(".active").siblings(".day").addClass("active");
            }).on('changeDate', function (e) {
                var range = getWeekRange(e.date);
                settings.filterParams.start_date = range.firstDateOfWeek;
                settings.filterParams.end_date = range.lastDateOfWeek;
                initWeekSelectorText($datepicker);
                reloadInstance($instance, settings);
            });
        }
    }




    //build checkbox filter
    if (typeof settings.checkBoxes[0] !== 'undefined') {
        var checkboxes = "", values = [], name = "";
        $.each(settings.checkBoxes, function (index, option) {
            var checked = "", active = "";
            name = option.name;
            if (option.isChecked) {
                checked = " checked";
                active = " active";
                values.push(option.value);
            }
            checkboxes += '<label class="btn btn-default mb0 ' + active + '">';
            checkboxes += '<input type="checkbox" name="' + option.name + '" value="' + option.value + '" autocomplete="off" ' + checked + '>' + option.text;
            checkboxes += '</label>';
        });
        settings.filterParams[name] = values;
        var checkboxDom = '<div class="mr15 DTTT_container">'
                + '<div class="btn-group filter" data-act="checkbox" data-toggle="buttons">'
                + checkboxes
                + '</div>'
                + '</div>';

        appendFilterDom(checkboxDom);

        var $checkbox = $instanceWrapper.find("[data-act='checkbox']");
        $checkbox.click(function () {
            var $selector = $(this);
            setTimeout(function () {
                var values = [],
                        name = "";
                $selector.parent().find("input:checkbox").each(function () {
                    name = $(this).attr("name");
                    if ($(this).is(":checked")) {
                        values.push($(this).val());
                        $(this).closest("label").addClass("active");
                    } else {
                        $(this).closest("label").removeClass("active");
                    }
                });
                settings.filterParams[name] = values;
                reloadInstance($instance, settings);
            });
        });
    }


    //build multiselect filter
    if (typeof settings.multiSelect[0] !== 'undefined') {

        $.each(settings.multiSelect, function (index, option) {

            var multiSelect = "", values = [],
                    saveSelection = option.saveSelection,
                    selections = getCookie(option.name);

            if (selections) {
                selections = selections.split("-");
            }

            $.each(option.options, function (index, listOption) {
                var active = "";

                if (
                        (saveSelection && selections && (selections.indexOf(listOption.value) > -1)) ||
                        (saveSelection && !selections && listOption.isChecked) ||
                        (!saveSelection && listOption.isChecked)
                        ) {
                    active = " active";
                    values.push(listOption.value);
                }
                //<li class=" list-group-item clickable toggle-table-column" data-column="1">ID</li>
                multiSelect += '<li class="list-group-item clickable ' + active + '" data-name="' + option.name + '" data-value="' + listOption.value + '">';
                multiSelect += listOption.text;
                multiSelect += '</li>';
            });


            multiSelect = "<div class='dropdown-menu'><ul class='list-group' data-act='multiselect'>" + multiSelect + "</ul></div>";

            settings.filterParams[option.name] = values;
            var multiSelectDom = '<div class="mr15 DTTT_container">'
                    + '<span class="dropdown inline-block filter-multi-select">'
                    + '<button class="btn btn-default dropdown-toggle caret " type="button" data-bs-toggle="dropdown" aria-expanded="true">' + option.text + ' </button>'
                    + multiSelect
                    + '</span>'
                    + '</div>';

            appendFilterDom(multiSelectDom);

            var $multiselect = $instanceWrapper.find("[data-name='" + option.name + "']");
            $multiselect.click(function () {
                var $selector = $(this);
                $selector.toggleClass("active");
                setTimeout(function () {
                    var values = [],
                            name = "";
                    $selector.parent().find("li").each(function () {
                        name = $(this).attr("data-name");
                        if ($(this).hasClass("active")) {
                            values.push($(this).attr("data-value"));
                        }
                    });

                    if (saveSelection) {
                        //save selected options to browser cookies
                        selections = values.join("-");
                        setCookie(option.name, selections);
                    }

                    settings.filterParams[name] = values;
                    reloadInstance($instance, settings);
                });
                return false;
            });

        });


    }




    //build radio button filter
    if (typeof settings.radioButtons[0] !== 'undefined') {
        var radiobuttons = "";
        $.each(settings.radioButtons, function (index, option) {
            var checked = "", active = "";
            if (option.isChecked) {
                checked = " checked";
                active = " active";
                settings.filterParams[option.name] = option.value;
            }
            radiobuttons += '<label class="btn btn-default mb0 ' + active + '">';
            radiobuttons += '<input type="radio" name="' + option.name + '" value="' + option.value + '" autocomplete="off" ' + checked + '>' + option.text;
            radiobuttons += '</label>';
        });
        var radioDom = '<div class="mr15 DTTT_container">'
                + '<div class="btn-group filter" data-act="radio" data-toggle="buttons">'
                + radiobuttons
                + '</div>'
                + '</div>';

        appendFilterDom(radioDom);

        var $radioButtons = $instanceWrapper.find("[data-act='radio'] input[type=radio]");


        $radioButtons.click(function () {

            var $selector = $(this);
            setTimeout(function () {
                $selector.closest("[data-act='radio']").find("input:radio").each(function () {
                    $(this).closest("label").removeClass("active");
                    if ($(this).is(":checked")) {
                        settings.filterParams[$(this).attr("name")] = $(this).val();
                        $(this).closest("label").addClass("active");
                    }
                });

                reloadInstance($instance, settings);

            });
        });
    }


    //build singleDatepicker filter
    if (typeof settings.singleDatepicker[0] !== 'undefined') {

        $.each(settings.singleDatepicker, function (index, datePicker) {

            var options = " ", value = "", selectedText = "";

            if (!datePicker.options)
                datePicker.options = [];

            //add custom datepicker selector
            datePicker.options.push({value: "show-date-picker", text: AppLanugage.custom});

            //prepare custom list
            $.each(datePicker.options, function (index, option) {
                var isSelected = "";
                if (option.isSelected) {
                    isSelected = "active";
                    value = option.value;
                    selectedText = option.text;
                }

                options += '<div class="list-group-item ' + isSelected + '" data-value="' + option.value + '">' + option.text + '</div>';
            });

            if (!selectedText) {
                selectedText = "- " + datePicker.defaultText + " -";
                options = '<div class="list-group-item active" data-value="">' + selectedText + '</div>' + options;
            }


            //set filter params
            if (datePicker.name) {
                settings.filterParams[datePicker.name] = value;
            }

            var reloadDatePickerFilter = function (date) {
                settings.filterParams[datePicker.name] = date;
                reloadInstance($instance, settings);
            };

            var getDatePickerText = function (text) {
                return text + "<span class='ml10 dropdown-toggle'></span>";
            };



            //prepare DOM
            var customList = '<div class="datepicker-custom-list list-group mb0">'
                    + options
                    + '</div>';

            var selectDom = '<div class="mr15 DTTT_container">'
                    + '<button name="' + datePicker.name + '" class="btn datepicker-custom-selector">'
                    + getDatePickerText(selectedText)
                    + '</button>'
                    + '</div>';

            appendFilterDom(selectDom);

            var $datePicker = $instanceWrapper.find("[name='" + datePicker.name + "']"),
                    showCustomRange = typeof datePicker.options[1] === 'undefined' ? false : true; //don't show custom range if options not > 1

            //init datepicker
            $datePicker.datepicker({
                format: settings._inputDateFormat,
                autoclose: true,
                todayHighlight: true,
                language: "custom",
                weekStart: AppHelper.settings.firstDayOfWeek,
                orientation: "bottom",
            }).on("show", function () {

                //has custom dates, show them otherwise show the datepicker
                if (showCustomRange) {
                    $(".datepicker-days, .datepicker-months, .datepicker-years, .datepicker-decades, .table-condensed").hide();
                    $(".datepicker-custom-list").show();
                    if (!$(".datepicker-custom-list").length) {
                        $(".datepicker").append(customList);

                        //bind click events
                        $(".datepicker .list-group-item").click(function () {
                            $(".datepicker .list-group-item").removeClass("active");
                            $(this).addClass("active");
                            var value = $(this).attr("data-value");
                            //show datepicker for custom date
                            if (value === "show-date-picker") {
                                $(".datepicker-custom-list, .datepicker-months, .datepicker-years, .datepicker-decades, .table-condensed").hide();
                                $(".datepicker-days, .table-condensed").show();
                            } else {
                                $(".datepicker").hide();

                                if (moment(value, settings._inputDateFormat).isValid()) {
                                    value = moment(value, settings._inputDateFormat).format(settings._inputDateFormat);
                                }

                                $datePicker.html(getDatePickerText($(this).html()));
                                reloadDatePickerFilter(value);
                            }
                        });
                    }
                }
            }).on('changeDate', function (e) {
                $datePicker.html(getDatePickerText(moment(e.date, settings._inputDateFormat).format("Do MMMM YYYY")));
                reloadDatePickerFilter(moment(e.date, settings._inputDateFormat).format(settings._inputDateFormat));
            });

        });
    }


    //build rangeDatepicker filter
    if (typeof settings.rangeDatepicker[0] !== 'undefined') {

        $.each(settings.rangeDatepicker, function (index, datePicker) {

            var startDate = datePicker.startDate || {},
                    endDate = datePicker.endDate || {},
                    showClearButton = datePicker.showClearButton ? true : false,
                    emptyText = '<i data-feather="calendar" class="icon-16"></i>',
                    startButtonText = startDate.value ? moment(startDate.value, settings._inputDateFormat).format("Do MMMM YYYY") : emptyText,
                    endButtonText = endDate.value ? moment(endDate.value, settings._inputDateFormat).format("Do MMMM YYYY") : emptyText;

            //set filter params
            settings.filterParams[startDate.name] = startDate.value;
            settings.filterParams[endDate.name] = endDate.value;

            var reloadDateRangeFilter = function (name, date) {
                settings.filterParams[name] = date;
                reloadInstance($instance, settings);
            };


            //prepare DOM
            var selectDom = '<div class="mr15 DTTT_container mb10">'
                    + '<div class="input-daterange input-group">'
                    + '<button class="btn btn-default form-control" name="' + startDate.name + '" data-date="' + startDate.value + '">' + startButtonText + '</button>'
                    + '<span class="input-group-addon">-</span>'
                    + '<button class="btn btn-default form-control" name="' + endDate.name + '" data-date="' + endDate.value + '">' + endButtonText + ''
                    + '</div>'
                    + '</div>';

            appendFilterDom(selectDom);

            var $datePicker = $instanceWrapper.find(".input-daterange"),
                    inputs = $datePicker.find('button').toArray();

            //init datepicker
            $datePicker.datepicker({
                format: "yyyy-mm-dd",
                autoclose: true,
                todayHighlight: true,
                language: "custom",
                weekStart: AppHelper.settings.firstDayOfWeek,
                orientation: "bottom",
                inputs: inputs
            }).on('changeDate', function (e) {
                var date = moment(e.date, settings._inputDateFormat).format(settings._inputDateFormat);

                //set save value if anyone is empty
                if (!settings.filterParams[startDate.name]) {
                    settings.filterParams[startDate.name] = date;
                }

                if (!settings.filterParams[endDate.name]) {
                    settings.filterParams[endDate.name] = date;
                }

                reloadDateRangeFilter($(e.target).attr("name"), date);

                //show button text
                $(inputs[0]).html(moment(settings.filterParams[startDate.name], settings._inputDateFormat).format("Do MMMM YYYY"));
                $(inputs[1]).html(moment(settings.filterParams[endDate.name], settings._inputDateFormat).format("Do MMMM YYYY"));

            }).on("show", function () {

                //show clear button
                if (showClearButton) {
                    $(".datepicker-clear-selection").show();
                    if (!$(".datepicker-clear-selection").length) {
                        $(".datepicker").append("<div class='datepicker-clear-selection p5 clickable text-center'>" + AppLanugage.clear + "</div>");

                        //bind click event for clear button
                        $(".datepicker .datepicker-clear-selection").click(function () {
                            settings.filterParams[startDate.name] = "";
                            reloadDateRangeFilter(endDate.name, "");

                            $(inputs[0]).html(emptyText);
                            $(inputs[1]).html(emptyText);
                            $(".datepicker").hide();
                        });
                    }
                }
            });

        });
    }


    //build dropdown filter
    if (typeof settings.filterDropdown[0] !== 'undefined') {
        var radiobuttons = "";
        $.each(settings.filterDropdown, function (index, dropdown) {

            var optons = "", selectedValue = "";

            var selectHtmlData = [];

            $.each(dropdown.options, function (index, option) {
                var isSelected = "";
                if (option.isSelected) {
                    isSelected = "selected";
                    selectedValue = option.id;
                }

                if (dropdown.showHtml) {
                    selectHtmlData.push({
                        id: option.id,
                        text: option.text
                    });
                } else {
                    optons += '<option ' + isSelected + ' value="' + option.id + '">' + option.text + '</option>';
                }
            });

            if (dropdown.name) {
                settings.filterParams[dropdown.name] = selectedValue;
            }

            var selectDomSelector = '<select class="' + dropdown.class + '" name="' + dropdown.name + '">'
                    + optons
                    + '</select>';

            if (dropdown.showHtml) {
                selectDomSelector = '<input class="' + dropdown.class + '" name="' + dropdown.name + '" />';
            }

            var selectDom = '<div class="mr15 DTTT_container">'
                    + selectDomSelector
                    + '</div>';

            appendFilterDom(selectDom);

            var $dropdown = $instanceWrapper.find("[name='" + dropdown.name + "']");
            if (window.Select2 !== undefined) {
                if (dropdown.showHtml) {
                    $dropdown.select2({
                        data: selectHtmlData,
                        escapeMarkup: function (markup) {
                            return markup;
                        }
                    });
                } else {
                    $dropdown.select2();
                }

            }

            $dropdown.change(function () {
                var $selector = $(this),
                        filterName = $selector.attr("name"),
                        value = $selector.val();

                //set the new value to settings
                settings.filterParams[filterName] = value;

                //check if there any dependent files,
                //reset the dependent fields if this value is empty
                //re-load the dependent fields if this value is not empty

                if (dropdown.dependent && dropdown.dependent.length) {
                    prepareDependentFilter(filterName, value, settings.filterDropdown, $instanceWrapper, settings.filterParams);
                }


                reloadInstance($instance, settings);
            });
        });
    }

    var prepareDependentFilter = function (filterName, filterValue, filterDropdown, $wrapper, filterParams) {

        //check all dropdowns and prepre the dependency dropdown list

        $.each(filterDropdown, function (index, option) {

            //is there any dependency for selected field (filterName)? Prepare the dropdown list 
            if (option.dependency && option.dependency.length && option.dependency.indexOf(filterName) !== -1) {

                var $dependencySelector = $wrapper.find("select[name=" + option.name + "]"); //select box

                //we'll call ajax to get the data list
                if (((option.selfDependency && !filterValue) || filterValue) && option.dataSource) {
                    $.ajax({
                        url: option.dataSource,
                        data: filterParams,
                        type: "POST",
                        dataType: 'json',
                        success: function (response) {

                            //if we found the dropdown list, we'll show the options in dropdown
                            if (response && response.length) {
                                var newOptions = "",
                                        firstValue = "";

                                $.each(response, function (index, value) {

                                    if (!index) {
                                        firstValue = value.id; //auto select the first option in select box
                                    }

                                    newOptions += "<option value='" + value.id + "'>" + value.text + "</option>";
                                });

                                //set the new dropdown list in select box
                                $dependencySelector.html(newOptions);
                                $dependencySelector.select2("val", firstValue);
                            }
                        }
                    });

                } else {
                    //no value selected in parent, reset the dropdown box

                    var $firstOption = $dependencySelector.find("option:first");
                    $dependencySelector.html("<option value='" + $firstOption.val() + "'>" + $firstOption.html() + "</option>");
                    $dependencySelector.select2("val", $firstOption.val());
                }

                //reset the filter param
                var $firstOption = $dependencySelector.find("option:first");
                filterParams[option.name] = $firstOption.val();

            }

        });
    };

};

if (typeof TableTools != 'undefined') {
    TableTools.DEFAULTS.sSwfPath = AppHelper.assetsDirectory + "js/datatable/TableTools/swf/copy_csv_xls_pdf.swf";
}

var $appFilterXhrRequest = 'new';

(function ($) {
    //appTable using datatable
    $.fn.appTable = function (options) {

        //set default display length
        var displayLength = AppHelper.settings.displayLength * 1;

        if (isNaN(displayLength) || !displayLength) {
            displayLength = 10;
        }

        var responsive = false;
        if (AppHelper.settings.disableResponsiveDataTable === "1") {
            responsive = false;
        } else if ((AppHelper.settings.disableResponsiveDataTableForMobile !== "1") && (window.outerWidth < 800)) {
            responsive = true;
        }

        var defaults = {
            serverSide: false,
            source: "", //data url
            xlsColumns: [], // array of excel exportable column numbers
            pdfColumns: [], // array of pdf exportable column numbers
            printColumns: [], // array of printable column numbers
            columns: [], //column title and options
            order: [[0, "asc"]], //default sort value
            hideTools: false, //show/hide tools section
            displayLength: displayLength, //default rows per page
            dateRangeType: "", // type: daily, weekly, monthly, yearly. output params: start_date and end_date
            checkBoxes: [], // [{text: "Caption", name: "status", value: "in_progress", isChecked: true}] 
            multiSelect: [], // [{text: "Caption", name: "status", options:[{text: "Caption", value: "in_progress", isChecked: true}]}] 
            radioButtons: [], // [{text: "Caption", name: "status", value: "in_progress", isChecked: true}] 
            filterDropdown: [], // [{id: 10, text:'Caption', isSelected:true}] 
            singleDatepicker: [], // [{name: '', value:'', options:[]}] 
            rangeDatepicker: [], // [{startDate:{name:"", value:""},endDate:{name:"", value:""}}] 
            stateSave: true, //save user state
            isMobile: window.outerWidth < 800 ? true : false,
            responsive: responsive, //by default, apply the responsive design only on the mobile view
            stateDuration: 60 * 60 * 24 * 60, //remember for 60 days
            columnShowHideOption: true, //show a option to show/hide the columns,
            tableRefreshButton: false, //show a option to refresh the table
            filterParams: {datatable: true}, //will post this vales on source url
            onDeleteSuccess: function () {
            },
            onUndoSuccess: function () {
            },
            onInitComplete: function () {
            },
            customLanguage: {
                noRecordFoundText: AppLanugage.noRecordFound,
                searchPlaceholder: AppLanugage.search,
                printButtonText: AppLanugage.print,
                excelButtonText: AppLanugage.excel,
                printButtonToolTip: AppLanugage.printButtonTooltip,
                today: AppLanugage.today,
                yesterday: AppLanugage.yesterday,
                tomorrow: AppLanugage.tomorrow
            },
            footerCallback: function (row, data, start, end, display) {
            },
            rowCallback: function (nRow, aData, iDisplayIndex, iDisplayIndexFull) {
            },
            summation: "", /* {column: 5, dataType: 'currency'}  dataType:currency, time */
            onRelaodCallback: function () {
            }
        };

        var $instance = $(this);

        //check if this binding with a table or not
        if (!$instance.is("table")) {
            console.log("appTable: Element must have to be a table", this);
            return false;
        }

        $instance.on('length.dt page.dt order.dt search.dt', function () {
            setTimeout(function () {
                feather.replace();
            }, 1);
        });

        var settings = $.extend({}, defaults, options);


        // reload

        if (settings.reload) {
            var table = $(this).dataTable();
            var instanceSettings = window.InstanceCollection[$(this).attr("id")];

            if (!instanceSettings) {
                instanceSettings = settings;
            }
            var tableId = table.get(0).id;

            if (instanceSettings.serverSide) {
                window.appTables[tableId]._fnReDraw();
            } else {
                table.fnReloadAjax(instanceSettings.filterParams);
            }




            if ($(this).data("onRelaodCallback")) {
                $(this).data("onRelaodCallback")(table, instanceSettings.filterParams);
            }

            return false;
        }

        // add/edit row
        if (settings.newData) {

            var table = $(this).dataTable();

            if (settings.dataId) {
                //check for existing row; if found, delete the row; 

                var $row = $(this).find("[data-post-id='" + settings.dataId + "']");

                if (!$row.length) {
                    $row = $(this).find("[data-index-id='" + settings.dataId + "']");
                }

                if ($row.length) {
                    // .fnDeleteRow($row.closest('tr'));

                    table.api().row(table.api().row($row.closest('tr')).index()).data(settings.newData);

                    table.fnUpdateRow(null, table.api().page()); //update existing row
                } else {
                    table.fnUpdateRow(settings.newData); //add new row
                }


            } else if (settings.rowDeleted) {
                table.fnUpdateRow(settings.newData, table.api().page(), true); //refresh row after delete
            } else {
                table.fnUpdateRow(settings.newData); //add new row
            }

            return false;
        }

        //add nowrap class in responsive view
        if (settings.responsive) {
            $instance.addClass("nowrap");
        }



        var _prepareFooter = function (settings, page, lable) {
            var tr = "",
                    trSection = '';

            if (page === "all") {
                trSection = 'data-section="all_pages"';
            }

            tr += "<tr " + trSection + ">";

            $.each(settings.columns, function (index, column) {

                var thAttr = "class = 'tf-blank' ",
                        thLable = " ";


                if (settings.summation[0] && settings.summation[0].column - 1 === index) {
                    thLable = lable;
                    thAttr = "class = 'tf-lable' ";
                }

                $.each(settings.summation, function (fIndex, sumColumn) {
                    if (sumColumn.column === index) {
                        thAttr = "class = 'tf-result text-right' ";
                        thAttr += 'data-' + page + '-page="' + sumColumn.column + '"';
                    }
                });

                tr += "<th " + thAttr + ">";
                tr += thLable;
                tr += "</th>";

            });
            tr += "</tr>";

            return tr;

        };

        //add summation footer 
        //don't add it on mobile view. We'll show another field in mobile view.

        if (settings.summation && settings.summation.length && !settings.isMobile) {
            var content = "<tfoot>";

            content += _prepareFooter(settings, 'current', AppLanugage.total);
            content += _prepareFooter(settings, 'all', AppLanugage.totalOfAllPages);

            content += "</tfoot>";

            $instance.html(content);
        }




        settings._visible_columns = [];
        $.each(settings.columns, function (index, column) {
            if (column.visible !== false) {
                settings._visible_columns.push(index);
            }

            //set orderable: false if serverSide:true and don't have order_by reference. 
            //also check if dependant sorting column has order_by reference
            var orderable = false;

            if (settings.serverSide) {
                if (column.order_by) {
                    orderable = true;
                } else if (!column.order_by && column.iDataSort && settings.columns[column.iDataSort].order_by) {
                    orderable = true;
                }
            } else {
                orderable = true;
            }

            settings.columns[index].orderable = orderable;

        });


        settings._exportable = settings.xlsColumns.length + settings.pdfColumns.length + settings.printColumns.length;
        settings._firstDayOfWeek = AppHelper.settings.firstDayOfWeek || 0;
        settings._inputDateFormat = "YYYY-MM-DD";


        settings = prepareDefaultFilters(settings);


        var datatableOptions = {

            // sAjaxSource: settings.source,

            ajax: {
                url: settings.source,
                type: "POST",
                data: function (postData) {



                    var order_by_index = (postData.order && postData.order[0]) ? postData.order[0].column : "",
                            order_dir = (postData.order && postData.order[0]) ? postData.order[0].dir : "",
                            search = postData.search ? postData.search['value'] : "";

                    if (order_dir) {
                        order_dir = order_dir.toUpperCase();
                    }


                    var server_side = 0;
                    if (settings.serverSide) {
                        server_side = 1;
                    }

                    return $.extend({
                        order_by: settings.columns[order_by_index] ? settings.columns[order_by_index].order_by : "",
                        order_dir: order_dir,
                        search_by: search,
                        skip: postData.start,
                        limit: postData.length,
                        draw: postData.draw,
                        server_side: server_side
                    }, settings.filterParams);
                }
            },
            sServerMethod: "POST",
            columns: settings.columns,
            bProcessing: true,
            serverSide: settings.serverSide,
            iDisplayLength: settings.displayLength,
            aLengthMenu: [[10, 25, 50, 100, -1], [10, 25, 50, 100, AppLanugage.all]],
            bAutoWidth: false,
            bSortClasses: false,
            order: settings.order,
            stateSave: settings.stateSave,
            responsive: settings.responsive,
            fnStateLoadParams: function (oSettings, oData) {

                //if the stateSave is true, we'll remove the search value after next reload. 
                if (oData && oData.search) {
                    oData.search.search = "";
                }

            },
            stateDuration: settings.stateDuration,
            fnInitComplete: function () {
                settings.onInitComplete(this);
            },
            language: {
                lengthMenu: "_MENU_",
                zeroRecords: settings.customLanguage.noRecordFoundText,
                info: "_START_-_END_ / _TOTAL_",
                sInfo: "_START_-_END_ / _TOTAL_",
                infoFiltered: "(_MAX_)",
                search: "",
                searchPlaceholder: settings.customLanguage.searchPlaceholder,
                sInfoEmpty: "0-0 / 0",
                sInfoFiltered: "(_MAX_)",
                sInfoPostFix: "",
                sInfoThousands: ",",
                sProcessing: "<div class='table-loader'><span class='loading'></span></div>",
                "oPaginate": {
                    "sPrevious": "<i data-feather='chevrons-left' class='icon-16'></i>",
                    "sNext": "<i data-feather='chevrons-right' class='icon-16'></i>"
                }

            },
            sDom: "",
            footerCallback: function (row, data, start, end, display) {
                var instance = this;
                if (settings.summation) {

                    var pageInfo = instance.api().page.info(),
                            summationContent = "",
                            pageTotalContent = "",
                            allPageTotalContent = "";

                    if (pageInfo.recordsTotal) {
                        $(instance).find("tfoot").show();
                    } else {
                        $(instance).find("tfoot").hide();
                        return false;
                    }

                    $.each(settings.summation, function (index, option) {
                        // total value of current page
                        var pageTotal = calculateDatatableTotal(instance, option.column, function (currentValue) {

                            //if we get <b> tag, we'll assume that is a group total. ignore the value
                            if (currentValue && !currentValue.startsWith("<b>")) {
                                if (option.dataType === "currency") {
                                    return unformatCurrency(currentValue, option.conversionRate);
                                } else if (option.dataType === "time") {
                                    return moment.duration(currentValue).asSeconds();
                                } else if (option.dataType === "number") {
                                    return unformatCurrency(currentValue);
                                } else {
                                    return currentValue;
                                }
                            } else {
                                return 0;
                            }

                        }, true);

                        if (option.dataType === "currency") {
                            pageTotal = toCurrency(pageTotal, option.currencySymbol);
                        } else if (option.dataType === "time") {
                            pageTotal = secondsToTimeFormat(pageTotal);
                        } else if (option.dataType === "number") {
                            pageTotal = toCurrency(pageTotal, "none");
                        }

                        var pagTotalTitle = table.column(option.column).header();
                        if (pagTotalTitle) {
                            pageTotalContent += "<div class='box'><div class='box-content'>" + $(pagTotalTitle).html() + "</div><div class='box-content text-right'>" + pageTotal + "</div></div>";
                        }

                        $(instance).find("[data-current-page=" + option.column + "]").html(pageTotal);

                        // total value of all pages
                        if (pageInfo.pages > 1) {
                            $(instance).find("[data-section='all_pages']").show();
                            var total = calculateDatatableTotal(instance, option.column, function (currentValue) {

                                //if we get <b> tag, we'll assume that is a group total. ignore the value
                                if (currentValue && !currentValue.startsWith("<b>")) {
                                    if (option.dataType === "currency") {
                                        return unformatCurrency(currentValue, option.conversionRate);
                                    } else if (option.dataType === "time") {
                                        return moment.duration(currentValue).asSeconds();
                                    } else if (option.dataType === "number") {
                                        return unformatCurrency(currentValue);
                                    } else {
                                        return currentValue;
                                    }
                                } else {
                                    return 0;
                                }
                            });

                            if (option.dataType === "currency") {
                                total = toCurrency(total, option.currencySymbol);
                            } else if (option.dataType === "time") {
                                total = secondsToTimeFormat(total);
                            } else if (option.dataType === "number") {
                                total = toCurrency(total, "none");
                            }

                            var title = table.column(option.column).header();
                            if (title) {
                                allPageTotalContent += "<div class='box'><div class='box-content'>" + $(title).html() + "</div><div class='box-content text-right'>" + total + "</div></div>";
                            }

                            $(instance).find("[data-all-page=" + option.column + "]").html(total);
                        } else {
                            $(instance).find("[data-section='all_pages']").hide();
                        }
                    });



                    //add summation section for mobile view.

                    if (settings.isMobile) {
                        if (pageTotalContent) {
                            summationContent += "<div class='box'><div class='box-content strong'>" + AppLanugage.total + "</div></div>" + pageTotalContent;
                        }
                        if (allPageTotalContent) {
                            summationContent += "<div class='box'><div class='box-content strong'>" + AppLanugage.totalOfAllPages + "</div></div>" + allPageTotalContent;
                        }

                        $(".summation-section").html(summationContent);
                    }

                }

                settings.footerCallback(row, data, start, end, display, instance);
            },
            fnRowCallback: function (nRow, aData, iDisplayIndex, iDisplayIndexFull) {
                settings.rowCallback(nRow, aData, iDisplayIndex, iDisplayIndexFull);
            }
        };



        //to save the datatatable state in cookie, we'll use the user's reference.
        //sometime the same user (most of the time the admin user) will login to different account to check. 
        //since the table columns are different for different users, 
        //we'll save the coockie based on table reference + user reference 

        if (AppHelper.userId) {

            datatableOptions.stateSaveParams = function (settings, data) {
                if (settings.sInstance.indexOf("-user-ref-") === -1) {
                    settings.sInstance += "-user-ref-" + AppHelper.userId;
                }
            };


            datatableOptions.stateLoadCallback = function (settings) {
                if (settings.sInstance.indexOf("-user-ref-") === -1) {
                    settings.sInstance += "-user-ref-" + AppHelper.userId;
                }
                try {
                    return JSON.parse(
                            (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
                            'DataTables_' + settings.sInstance + '_' + location.pathname
                            )
                            );
                } catch (e) {
                }
            };
        }


        //set custom toolbar
        if (!settings.hideTools) {
            datatableOptions.sDom = "<'datatable-tools row'<'col-md-2 toolbar-left-top pl15'l><'col-md-10 custom-toolbar pr15'f>r>t<'datatable-tools clearfix row'<'col-md-3 pl15'i><'col-md-9 pr15'p>>";
        }


        if (settings._exportable) {
            var datatableButtons = [];

            if (settings.xlsColumns.length) {
                //add excel button

                datatableButtons.push({
                    extend: 'excelHtml5',
                    footer: true,
                    text: settings.customLanguage.excelButtonText,
                    exportOptions: {
                        columns: settings.xlsColumns
                    },
                    customize: function (xls) {
                        //append the total of all pages row, if it exists
                        if ($instance.find("[data-section='all_pages']") && $instance.find("[data-section='all_pages']").css('display') !== "none") {
                            var sheet = xls.xl.worksheets['sheet1.xml'];

                            var $sheetSelector = $(sheet.childNodes[0].childNodes[1]);
                            var thisRowNumber = parseInt($sheetSelector.find("row:last-child").attr("r")) + 1;

                            //here should define the actual position of the item using the abc character
                            var chars = 'abcdefghijklmnopqrstuvwxyz',
                                    rowCounted = 0;

                            var rowDom = '<row r="' + thisRowNumber + '">';

                            $instance.find("[data-section='all_pages'] th").each(function () {
                                if ($(this).text()) {
                                    rowDom += '<c t="inlineStr" r="' + chars[rowCounted].toUpperCase() + thisRowNumber + '" s="2">';
                                    rowDom += '<is>';
                                    rowDom += '<t>' + $(this).text() + '</t>';
                                    rowDom += '</is>';
                                    rowDom += '</c>';
                                }

                                //increase the position variable
                                rowCounted = rowCounted + 1;
                            });

                            rowDom += '</row>';

                            //add the row finally
                            sheet.childNodes[0].childNodes[1].innerHTML = sheet.childNodes[0].childNodes[1].innerHTML + rowDom;
                        }
                    }
                });

                /* flash button
                 datatableButtons.push({
                 sExtends: "xls",
                 sButtonText: settings.customLanguage.excelButtonText,
                 mColumns: settings.xlsColumns
                 });
                 */
            }

            if (settings.pdfColumns.length) {
                //add pdf button

                datatableButtons.push({
                    extend: 'pdfHtml5',
                    exportOptions: {
                        // columns: settings.pdfColumns
                        columns: ':visible:not(.option)'
                    }
                });

                /*
                 datatableButtons.push({
                 sExtends: "pdf",
                 mColumns: settings.pdfColumns
                 });
                 */
            }

            if (settings.printColumns.length) {
                datatableButtons.push({
                    extend: 'print',
                    autoPrint: false,
                    text: settings.customLanguage.printButtonText,
                    footer: true,
                    exportOptions: {
                        columns: settings.printColumns
                    },
                    customize: function (win) {
                        $(win.document.body).closest("html").addClass("dt-print-view");

                        //append the total of all pages row, if it exists
                        if ($instance.find("[data-section='all_pages']") && $instance.find("[data-section='all_pages']").css('display') !== "none") {
                            var totalOfAllPagesClone = $instance.find("[data-section='all_pages']").clone();
                            $(win.document.body).find("tfoot").append(totalOfAllPagesClone);
                        }
                    },
                    customizeData: function (a, b, c) {

                    }
                });

            }
            if (!settings.hideTools) {
                datatableOptions.sDom = "<'datatable-tools'<'w140 float-start toolbar-left-top pl15'l><'w-filter-right float-end custom-toolbar pr15'f<'datatable-export DTTT_container'B>>r>t<'datatable-tools clearfix row'<'col-md-3 pl15'<'summation-section'> i><'col-md-9 pr15'p>>";
            }
            datatableOptions.buttons = datatableButtons;

            // datatableOptions.oTableTools = {aButtons: datatableButtons};
        }

        datatableOptions.drawCallback = function () {
            if (settings.serverSide) {
                $instance.closest(".dataTables_wrapper").find("input[type=search]").val((settings.filterParams && settings.filterParams.search_by) ? settings.filterParams.search_by : "");
            }
        };

        var oTable = $instance.dataTable(datatableOptions),
                $instanceWrapper = $instance.closest(".dataTables_wrapper");

        var tableId = $instance.get(0) ? $instance.get(0).id : "id_not_found";

        if (!window.appTables) {
            window.appTables = [];
        }
        window.appTables[tableId] = oTable;


        $instanceWrapper.find('.DTTT_button_print').tooltip({
            placement: 'bottom',
            container: 'body'
        });
        $instanceWrapper.find("select").select2({
            minimumResultsForSearch: -1
        });


        //add the column show/hide option
        if (settings.columnShowHideOption) {

            var tableId = $instance.attr("id");
            table = $instance.DataTable();

            //prepare a popover
            var popover = '<div class="DTTT_container float-start"><button class="btn btn-default column-show-hide-popover ml15" data-container="body" data-bs-toggle="popover" data-placement="bottom"><i data-feather="eye-off" class="icon-16"></i></button></div>';
            $instanceWrapper.find(".toolbar-left-top").append(popover);

            //prepare the list of columns when opening the popover
            $instanceWrapper.find(".column-show-hide-popover").popover({
                html: true,
                sanitize: false,
                content: function () {
                    var tableColumns = "";

                    $.each(settings.columns, function (index, column) {
                        //in coulmn list, show only the visible columns
                        if (column.visible !== false) {

                            var tableColumn = table.column(index),
                                    columnHiddenClass = "";

                            if (!tableColumn.visible()) {
                                columnHiddenClass = "active";
                            }

                            //prepare a list of columns
                            tableColumns += "<li class='" + columnHiddenClass + " list-group-item clickable toggle-table-column' data-column='" + index + "'>" + column.title + "</li>"
                        }
                    });

                    return "<ul class='list-group' data-table='" + tableId + "'>" + tableColumns + "</ul>";

                }
            });


            //show/hide column when clicking on the list items    

            $instanceWrapper.find(".column-show-hide-popover").on('shown.bs.popover', function () {
                feather.replace();

                $(".toggle-table-column").on('click', function () {

                    var instanceId = $(this).closest(".list-group").attr("data-table");

                    var column = $("#" + instanceId).DataTable().column($(this).attr('data-column'));


                    // check the actual status of the table column and toggle it
                    if (column) {
                        column.visible(!column.visible());

                        $(this).toggleClass("active");
                    }

                });
            });

        }



        if (settings.tableRefreshButton) {
            //prepare a refreshButton

            var refreshButton = '<div class="DTTT_container float-start "><button class="btn btn-default at-table-refresh-button ml15"><i data-feather="refresh-cw" class="icon-16"></i></button></div>';
            $instanceWrapper.find(".toolbar-left-top").append(refreshButton);

            $instanceWrapper.find(".at-table-refresh-button").on('click', function () {
                $instance.appTable({reload: true, filterParams: settings.filterParams});
            });
        }



        //hide popover when clicks on outside of the popover
        if (!$('body').hasClass("destroy-popover")) {
            $('body').addClass("destroy-popover"); //don't initiate this multiple time

            $('.destroy-popover').on('click', function (e) {
                if ($(e.target).closest("button").attr("data-bs-toggle") !== "popover" && !$(e.target).closest(".popover").length && !$(e.target).hasClass("editable")) {
                    var visiblePopoverId = $(".popover.in").attr("id");
                    $("[aria-describedby=" + visiblePopoverId + "]").trigger("click");

                }
            });
        }



        //set onReloadCallback
        $instance.data("onRelaodCallback", settings.onRelaodCallback);

        // add delay in search when applied serverside
        if (settings.serverSide) {
            var $searchBox = $instanceWrapper.find("input[type=search]");

            $searchBox.unbind().bind('input', (delayAction(function (e) {
                settings.filterParams.search_by = $(this).val();
                $instance.appTable({reload: true, filterParams: settings.filterParams});
                return;
            }, 1000)));

            //search datatable when clicks on the labels.
            $('body').on('click', "#" + $instance.get(0).id + ' .badge.clickable', function () {
                settings.filterParams.search_by = $(this).text();
                $instance.appTable({reload: true, filterParams: settings.filterParams});
                return false;
            });

            //search datatable when clicks on filter sub task icon
            $('body').on('click', "#" + $instance.get(0).id + ' .filter-sub-task-button', function () {
                settings.filterParams.search_by = $(this).attr('main-task-id');
                $instance.appTable({reload: true, filterParams: settings.filterParams});
                return false;
            });

            //remove sub tasks filter
            $('body').on('click', "#" + $instance.get(0).id + ' .remove-filter-button', function () {
                settings.filterParams.search_by = "";
                $instance.appTable({reload: true, filterParams: settings.filterParams});
                return false;
            });


        } else {
            //if not serverSide, then just re-draw the table when clicks on the labels. 
            $('body').on('click', "#" + $instance.get(0).id + ' .badge.clickable', function () {
                var value = $(this).text();

                $(this).closest(".dataTable").DataTable().search(value).draw();
                $(this).closest(".dataTables_wrapper").find("input[type=search]").val(value).focus().select();
                return false;
            });
        }



        buildFilterDom(settings, $instanceWrapper, $instance);
        var undoHandler = function (eventData) {
            $('<a class="undo-delete" href="javascript:;"><strong>' + AppLanugage.undo + '</strong></a>').insertAfter($(eventData.alertSelector).find(".app-alert-message"));
            $(eventData.alertSelector).find(".undo-delete").bind("click", function () {
                $(eventData.alertSelector).remove();
                appLoader.show();
                $.ajax({
                    url: eventData.url,
                    type: 'POST',
                    dataType: 'json',
                    data: {id: eventData.id, undo: true},
                    success: function (result) {
                        appLoader.hide();
                        if (result.success) {
                            $instance.appTable({newData: result.data, rowDeleted: true});
                            //fire success callback
                            settings.onUndoSuccess(result);
                        }
                    }
                });
            });
        };


        var rowDeleteHandler = function (result, $target) {
            var tr = $target.closest('tr'),
                    table = $instance.DataTable(),
                    undo = $target.attr('data-undo'),
                    url = $target.attr('data-action-url'),
                    id = $target.attr('data-id');

            oTable.fnDeleteRow(table.row(tr).index(), function () {
                table.page(table.page()).draw('page');
            }, false);

            var alertId = appAlert.warning(result.message, {duration: 20000});

            //fire success callback
            settings.onDeleteSuccess(result);

            //bind undo selector
            if (undo !== "0") {
                undoHandler({
                    alertSelector: alertId,
                    url: url,
                    id: id
                });
            }
        };

        var appTableDeleteConfirmationHandler = function (e) {
            deleteConfirmationHandler(e, rowDeleteHandler);
        };

        var appTableSimpleDeleteHandler = function (e) {
            deleteHandler(e, rowDeleteHandler);
        };

        var updateHandler = function (e) {
            appLoader.show();
            var $target = $(e.currentTarget);

            if (e.data && e.data.target) {
                $target = e.data.target;
            }

            var url = $target.attr("data-action-url");

            $.ajax({
                url: url,
                dataType: 'json',
                success: function (response) {
                    if (response.success) {
                        $(".dataTable:visible").appTable({newData: response.data, dataId: response.id});
                        appAlert.success(response.message, {duration: 10000});
                    } else {
                        appAlert.error(response.message);
                    }
                    appLoader.hide();
                }
            });
        };


        window.InstanceCollection = window.InstanceCollection || {};
        window.InstanceCollection[$(this).attr("id")] = settings;

        $('body').find($instance).on('click', 'a[data-action=delete]', appTableSimpleDeleteHandler);
        $('body').find($instance).on('click', 'a[data-action=delete-confirmation]', appTableDeleteConfirmationHandler);
        $('body').find($instance).on('click', '[data-action=update]', updateHandler);

        $.fn.dataTableExt.oApi.getSettings = function (oSettings) {
            return oSettings;
        };

        $.fn.dataTableExt.oApi.fnReloadAjax = function (oSettings, filterParams) {
            this.fnClearTable(this);
            this.oApi._fnProcessingDisplay(oSettings, true);
            var that = this;
            console.log("fnReloadAjax loaded", new Date());
            if ($appFilterXhrRequest !== 'new') {
                //an another xhr request is already running
                return;
            }

            $appFilterXhrRequest = $.ajax({
                url: oSettings.ajax.url,
                type: "POST",
                dataType: "json",
                data: filterParams,
                success: function (json) {
                    $appFilterXhrRequest = 'new';

                    /* Got the data - add it to the table */
                    for (var i = 0; i < json.data.length; i++) {
                        that.oApi._fnAddData(oSettings, json.data[i]);
                    }

                    oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
                    that.fnDraw(that);
                    that.oApi._fnProcessingDisplay(oSettings, false);
                }
            });
        };
        $.fn.dataTableExt.oApi.fnUpdateRow = function (oSettings, data, page, renderBeforePageChange) {
            //oSettings is not any parameter, we'll get it automatically.

            if (data) {
                this.oApi._fnAddData(oSettings, data);
            }

            if (renderBeforePageChange) {
                this.fnDraw(this);
            }

            if (page) {
                this.oApi._fnPageChange(oSettings, page, true);
            } else {
                this.fnDraw(this);
            }

        };

    };
})(jQuery);


deleteHandler = function (e, callback) {
    appLoader.show();
    var $target = $(e.currentTarget);

    if (e.data && e.data.target) {
        $target = e.data.target;
    }

    var url = $target.attr('data-action-url'),
            id = $target.attr('data-id'),
            reloadOnSuccess = $target.attr('data-reload-on-success');

    $.ajax({
        url: url,
        type: 'POST',
        dataType: 'json',
        data: {id: id},
        success: function (result) {
            if (result.success) {

                if (callback) {
                    callback(result, $target);
                }

                if (reloadOnSuccess) {
                    location.reload();
                }

            } else {
                appAlert.error(result.message);
            }
            appLoader.hide();
        }
    });
}


deleteConfirmationHandler = function (e, callback) {
    var $deleteButton = $("#confirmDeleteButton"),
            $target = $(e.currentTarget);
    //copy attributes

    $target.each(function () {
        $.each(this.attributes, function () {
            if (this.specified && this.name.match("^data-")) {
                $deleteButton.attr(this.name, this.value);
            }

        });
    });

    $target.attr("data-undo", "0"); //don't show undo

    //bind click event
    $deleteButton.unbind("click");
    $deleteButton.on("click", {target: $target}, function (e) {
        deleteHandler(e, callback);
    });

    $("#confirmationModal").modal('show');
};



// appAlert
(function (define) {
    define(['jquery'], function ($) {
        return (function () {
            var appAlert = {
                info: info,
                success: success,
                warning: warning,
                error: error,
                options: {
                    container: "body", // append alert on the selector
                    duration: 0, // don't close automatically,
                    showProgressBar: true, // duration must be set
                    clearAll: true, //clear all previous alerts
                    animate: true //show animation
                }
            };

            return appAlert;

            function info(message, options) {
                this._settings = _prepear_settings(options);
                this._settings.alertType = "info";
                _show(message);
                return "#" + this._settings.alertId;
            }

            function success(message, options) {
                this._settings = _prepear_settings(options);
                this._settings.alertType = "success";
                _show(message);
                return "#" + this._settings.alertId;
            }

            function warning(message, options) {
                this._settings = _prepear_settings(options);
                this._settings.alertType = "warning";
                _show(message);
                return "#" + this._settings.alertId;
            }

            function error(message, options) {
                this._settings = _prepear_settings(options);
                this._settings.alertType = "error";
                _show(message);
                return "#" + this._settings.alertId;
            }

            function _template(message) {
                var className = "info";
                if (this._settings.alertType === "error") {
                    className = "danger";
                } else if (this._settings.alertType === "success") {
                    className = "success";
                } else if (this._settings.alertType === "warning") {
                    className = "warning";
                }

                if (this._settings.animate) {
                    className += " animate";
                }

                return '<div id="' + this._settings.alertId + '" class="app-alert alert alert-' + className + ' alert-dismissible " role="alert">'
                        + '<button type="button" class="btn-close btn-close-white" data-bs-dismiss="alert" aria-label="Close"></button>'
                        + '<div class="app-alert-message">' + message + '</div>'
                        + '<div class="progress">'
                        + '<div class="progress-bar bg-' + className + ' hide" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 100%">'
                        + '</div>'
                        + '</div>'
                        + '</div>';
            }

            function _prepear_settings(options) {
                if (!options)
                    var options = {};
                options.alertId = "app-alert-" + _randomId();
                return this._settings = $.extend({}, appAlert.options, options);
            }

            function _randomId() {
                var id = "";
                var keys = "abcdefghijklmnopqrstuvwxyz0123456789";
                for (var i = 0; i < 5; i++)
                    id += keys.charAt(Math.floor(Math.random() * keys.length));
                return id;
            }

            function _clear() {
                if (this._settings.clearAll) {
                    $("[role='alert']").remove();
                }
            }

            function _show(message) {
                _clear();
                var container = $(this._settings.container);
                if (container.length) {
                    if (this._settings.animate) {
                        //show animation
                        setTimeout(function () {
                            $(".app-alert").animate({
                                opacity: 1,
                                right: "40px"
                            }, 500, function () {
                                $(".app-alert").animate({
                                    right: "15px"
                                }, 300);
                            });
                        }, 20);
                    }

                    $(this._settings.container).prepend(_template(message));
                    _progressBarHandler();
                } else {
                    console.log("appAlert: container must be an html selector!");
                }
            }

            function _progressBarHandler() {
                if (this._settings.duration && this._settings.showProgressBar) {
                    var alertId = "#" + this._settings.alertId;
                    var $progressBar = $(alertId).find('.progress-bar');

                    $progressBar.removeClass('hide').width(0);
                    var css = "width " + this._settings.duration + "ms ease";
                    $progressBar.css({
                        WebkitTransition: css,
                        MozTransition: css,
                        MsTransition: css,
                        OTransition: css,
                        transition: css
                    });

                    setTimeout(function () {
                        if ($(alertId).length > 0) {
                            $(alertId).remove();
                        }
                    }, this._settings.duration);
                }
            }
        })();
    });
}(function (d, f) {
    window['appAlert'] = f(window['jQuery']);
}));


(function (define) {
    define(['jquery'], function ($) {
        return (function () {
            var appLoader = {
                show: show,
                hide: hide,
                options: {
                    container: 'body',
                    zIndex: "auto",
                    css: "",
                }
            };

            return appLoader;

            function show(options) {
                var $template = $("#app-loader");
                this._settings = _prepear_settings(options);
                if (!$template.length) {
                    var $container = $(this._settings.container);
                    if ($container.length) {
                        $container.append('<div id="app-loader" class="app-loader" style="z-index:' + this._settings.zIndex + ';' + this._settings.css + '"><div class="loading"></div></div>');
                    } else {
                        console.log("appLoader: container must be an html selector!");
                    }

                }
            }

            function hide() {
                var $template = $("#app-loader");
                if ($template.length) {
                    $template.remove();
                }
            }

            function _prepear_settings(options) {
                if (!options)
                    var options = {};
                return this._settings = $.extend({}, appLoader.options, options);
            }
        })();
    });
}(function (d, f) {
    window['appLoader'] = f(window['jQuery']);
}));

/*prepare html form data for suitable ajax submit*/
function encodeAjaxPostData(html) {
    html = replaceAll("=", "~", html);
    html = replaceAll("&", "^", html);
    return html;
}

//replace all occurrences of a string
function replaceAll(find, replace, str) {
    return str.replace(new RegExp(find, 'g'), replace);
}

(function (define) {
    define(['jquery'], function ($) {
        return (function () {
            var appContentModal = {
                init: init,
                destroy: destroy,
                options: {
                    url: "",
                    css: "",
                    sidebar: true
                }
            };

            return appContentModal;

            function escKeyEvent(e) {
                if (e.keyCode === 27) {
                    destroy();
                }
            }

            function init(options) {
                this._settings = _prepear_settings(options);
                _load_template(this._settings);
            }

            function destroy() {
                $(".app-modal").remove();
                $(document).unbind("keyup", escKeyEvent);
                if (typeof appModalXhr !== 'undefined') {
                    appModalXhr.abort();
                }
            }

            function _prepear_settings(options) {
                if (!options)
                    options = {};

                return this._settings = $.extend({}, appLoader.options, options);
            }

            function _load_template(settings) {

                var sidebar = "<div class='app-modal-sidebar hidden-xs'>\
                                        <div class='app-modal-close'><span>&times;</span></div>\
                                        <div class='app-moadl-sidebar-scrollbar'>\
                                            <div class='app-modal-sidebar-area'>\
                                            </div>\
                                        </div>\
                                    </div>";
                var controlIcon = "<span class='expand hidden-xs'><i data-feather='maximize-2' class='icon-16'></i></span>";

                if (settings.sidebar === false || isMobile()) {
                    sidebar = "";
                    controlIcon = "<div class='app-modal-close app-modal-fixed-close-button'><span>&times;</span></div>";
                }

                var template = "<div class='app-modal loading'>\
                                <span class='compress'><i data-feather='minimize-2' class='icon-16'></i></span>\
                                <div class='app-modal-body'>\
                                    <div class='app-modal-content'>" + controlIcon +
                        "<div class='hide app-modal-close'><span>&times;</span></div>\
                                        <div class='app-modal-content-area d-inline-block'>\
                                        </div>\
                        </div>" + sidebar + "</div>\
                            </div>";
                destroy();
                $("body").prepend(template);


                setTimeout(function () {
                    var windowHeight = $(window).height() - 60;
                    if ($(".app-modal-content-area").prop("scrollHeight") > windowHeight) {
                        $(".app-modal-content-area").css({"max-height": windowHeight + "px", "overflow-y": "scroll", "width": "100%"});
                    }


                    if ($.fn.mCustomScrollbar) {
                        $('.app-moadl-sidebar-scrollbar').mCustomScrollbar({setHeight: windowHeight, theme: "minimal-dark", autoExpandScrollbar: true});
                    }
                }, 200);


                $(".expand").click(function () {
                    $(".app-modal").addClass("full-content");
                });

                $(".compress").click(function () {
                    $(".app-modal").removeClass("full-content");
                });
                $(".app-modal-close").click(function () {
                    destroy();
                });
                $(document).bind("keyup", escKeyEvent);
                appLoader.show({container: '.app-modal', css: "top:35%; right:48%;"});

                appModalXhr = $.ajax({
                    url: settings.url || "",
                    data: {},
                    cache: false,
                    type: 'POST',
                    success: function (response) {
                        var $content = $(response);
                        $(".app-modal-content-area").html($content.find(".app-modal-content").html());
                        $(".app-modal-sidebar-area").html($content.find(".app-modal-sidebar").html());
                        $content.remove();
                        $(".app-modal").removeClass("loading");
                        appLoader.hide();
                    },
                    statusCode: {
                        404: function () {
                            appContentModal.destroy();
                            appAlert.error("404: Page not found.");
                        }
                    },
                    error: function () {
                        appContentModal.destroy();
                        appAlert.error("500: Internal Server Error.");
                    }
                });

            }
        })();
    });
}(function (d, f) {
    window['appContentModal'] = f(window['jQuery']);
}));

//custom daterange controller
(function ($) {
    $.fn.appDateRange = function (options) {
        var defaults = {
            dateRangeType: "yearly",
            filterParams: {},
            onChange: function (dateRange) {
            },
            onInit: function (dateRange) {
            }
        };
        var settings = $.extend({}, defaults, options);
        settings._inputDateFormat = "YYYY-MM-DD";

        this.each(function () {

            var $instance = $(this);
            var dom = '<div class="ml15">'
                    + '<button data-act="prev" class="btn btn-default date-range-selector"><i data-feather="chevron-left" class="icon-16"></i></button>'
                    + '<button data-act="datepicker" class="btn btn-default" style="margin: -1px"></button>'
                    + '<button data-act="next"  class="btn btn-default date-range-selector"><i data-feather="chevron-right" class="icon-16"></i></button>'
                    + '</div>';
            $instance.append(dom);

            var $datepicker = $instance.find("[data-act='datepicker']"),
                    $dateRangeSelector = $instance.find(".date-range-selector");

            if (settings.dateRangeType === "yearly") {
                var inityearSelectorText = function ($elector) {
                    $elector.html(moment(settings.filterParams.start_date).format("YYYY"));
                };

                inityearSelectorText($datepicker);

                //bind the click events
                $datepicker.datepicker({
                    format: "YYYY-MM",
                    viewMode: "years",
                    minViewMode: "years",
                    autoclose: true,
                    language: "custom",
                }).on('changeDate', function (e) {
                    var date = moment(e.date).format(settings._inputDateFormat),
                            year = moment(date).format("YYYY");
                    settings.filterParams.start_date = year + "-01-01";
                    settings.filterParams.end_date = year + "-12-31";
                    settings.filterParams.year = year;
                    inityearSelectorText($datepicker);
                    settings.onChange(settings.filterParams);
                });

                //init default date
                var year = moment().format("YYYY");
                settings.filterParams.start_date = year + "-01-01";
                settings.filterParams.end_date = year + "-12-31";
                settings.filterParams.year = year;
                settings.onInit(settings.filterParams);


                $dateRangeSelector.click(function () {
                    var type = $(this).attr("data-act"),
                            startDate = moment(settings.filterParams.start_date),
                            endDate = moment(settings.filterParams.end_date);
                    if (type === "next") {
                        startDate = startDate.add(1, 'years').format(settings._inputDateFormat);
                        endDate = endDate.add(1, 'years').format(settings._inputDateFormat);
                    } else if (type === "prev") {
                        startDate = startDate.subtract(1, 'years').format(settings._inputDateFormat);
                        endDate = endDate.subtract(1, 'years').format(settings._inputDateFormat);
                    }

                    settings.filterParams.start_date = startDate;
                    settings.filterParams.end_date = endDate;
                    settings.filterParams.year = moment(startDate).format("YYYY");

                    inityearSelectorText($datepicker);
                    settings.onChange(settings.filterParams);
                });


            } else if (settings.dateRangeType === "monthly") {

                var initMonthSelectorText = function ($elector) {
                    $elector.html(moment(settings.filterParams.start_date).format("MMMM YYYY"));
                };

                //prepareDefaultDateRangeFilterParams();
                initMonthSelectorText($datepicker);

                //bind the click events
                $datepicker.datepicker({
                    format: "YYYY-MM",
                    viewMode: "months",
                    minViewMode: "months",
                    autoclose: true,
                    language: "custom",
                }).on('changeDate', function (e) {
                    var date = moment(e.date).format(settings._inputDateFormat);
                    var daysInMonth = moment(date).daysInMonth(),
                            yearMonth = moment(date).format("YYYY-MM");
                    settings.filterParams.start_date = yearMonth + "-01";
                    settings.filterParams.end_date = yearMonth + "-" + daysInMonth;
                    initMonthSelectorText($datepicker);
                    settings.onChange(settings.filterParams);
                });

                //init default date
                var year = moment().format("YYYY-MM");
                settings.filterParams.start_date = year + "-01";
                settings.filterParams.end_date = year + "-31";
                settings.filterParams.year = year;
                settings.onInit(settings.filterParams);

                $dateRangeSelector.click(function () {
                    var type = $(this).attr("data-act"),
                            startDate = moment(settings.filterParams.start_date),
                            endDate = moment(settings.filterParams.end_date);
                    if (type === "next") {
                        var nextMonth = startDate.add(1, 'months'),
                                daysInMonth = nextMonth.daysInMonth(),
                                yearMonth = nextMonth.format("YYYY-MM");

                        startDate = yearMonth + "-01";
                        endDate = yearMonth + "-" + daysInMonth;

                    } else if (type === "prev") {
                        var lastMonth = startDate.subtract(1, 'months'),
                                daysInMonth = lastMonth.daysInMonth(),
                                yearMonth = lastMonth.format("YYYY-MM");

                        startDate = yearMonth + "-01";
                        endDate = yearMonth + "-" + daysInMonth;
                    }

                    settings.filterParams.start_date = startDate;
                    settings.filterParams.end_date = endDate;
                    settings.filterParams.year = moment(startDate).format("YYYY-MM");

                    initMonthSelectorText($datepicker);
                    settings.onChange(settings.filterParams);
                });
            }


        });
    };
})(jQuery);


var loadFilterView = function (settings) {
    if (settings.source && settings.targetSelector) {
        $.ajax({
            url: settings.source,
            data: settings.filterParams,
            cache: false,
            type: 'POST',
            success: function (response) {
                $(settings.targetSelector).html(response);
                appLoader.hide();
            },
            statusCode: {
                404: function () {
                    appLoader.hide();
                    appAlert.error("404: Page not found.", {container: '.modal-body', animate: false});
                }
            },
            error: function () {
                appLoader.hide();
                appAlert.error("500: Internal Server Error.", {container: '.modal-body', animate: false});
            }
        });
    }
};

//custom filters controller
(function ($) {

    $.fn.appFilters = function (options) {
        appLoader.show();

        var defaults = {
            source: "", //data url
            targetSelector: "",
            reloadSelector: "",
            dateRangeType: "", // type: daily, weekly, monthly, yearly. output params: start_date and end_date
            checkBoxes: [], // [{text: "Caption", name: "status", value: "in_progress", isChecked: true}] 
            multiSelect: [], // [{text: "Caption", name: "status", options:[{text: "Caption", value: "in_progress", isChecked: true}]}] 
            radioButtons: [], // [{text: "Caption", name: "status", value: "in_progress", isChecked: true}] 
            filterDropdown: [], // [{id: 10, text:'Caption', isSelected:true}] 
            singleDatepicker: [], // [{name: '', value:'', options:[]}] 
            rangeDatepicker: [], // [{startDate:{name:"", value:""},endDate:{name:"", value:""}}] 
            isMobile: window.outerWidth < 800 ? true : false,
            filterParams: {customFilter: true}, //will post this vales on source url
            search: {show: false},
            customLanguage: {
                searchPlaceholder: AppLanugage.search,
                today: AppLanugage.today,
                yesterday: AppLanugage.yesterday,
                tomorrow: AppLanugage.tomorrow
            },
            beforeRelaodCallback: function () {},
            afterRelaodCallback: function () {},
            onInitComplete: function () {},
        };

        var $instance = $(this),
                $instanceWrapper = $instance; //$instanceWrapper is same as instance in this case

        $instanceWrapper.append("<div class='custom-toolbar'></div>");

        var settings = $.extend({}, defaults, options);

        if (settings.reload) {
            var instance = $(this);
            var instanceSettings = window.InstanceCollection[instance.attr("id")];


            if (instance.data("beforeRelaodCallback")) {
                instance.data("beforeRelaodCallback")(instance, instanceSettings.filterParams);
            }


            loadFilterView(instanceSettings);

            if (instance.data("afterRelaodCallback")) {
                instance.data("afterRelaodCallback")(instance, instanceSettings.filterParams);
            }


            return false;
        }

        settings._firstDayOfWeek = AppHelper.settings.firstDayOfWeek || 0;
        settings._inputDateFormat = "YYYY-MM-DD";


        settings = prepareDefaultFilters(settings);

        buildFilterDom(settings, $instanceWrapper, $instance);
        window.InstanceCollection = window.InstanceCollection || {};
        window.InstanceCollection[$instance.attr("id")] = settings;
        if (settings.onInitComplete) {
            settings.onInitComplete($instance, settings.filterParams);
        }

        loadFilterView(settings);


        //bind calbacks
        $instance.data("beforeRelaodCallback", settings.beforeRelaodCallback);
        $instance.data("afterRelaodCallback", settings.afterRelaodCallback);

    };
})(jQuery);



//find and replace all search string
replaceAllString = function (string, find, replaceWith) {
    return string.split(find).join(replaceWith);
};

//convert a number to curency format
toCurrency = function (number, currencySymbol) {

    if (AppHelper.settings.noOfDecimals == "0") {
        number = Math.round(parseFloat(number)) + ".00"; //round it and the add static 2 decimals
    } else {
        number = parseFloat(number).toFixed(2);
    }

    if (!currencySymbol) {
        currencySymbol = AppHelper.settings.currencySymbol;
    }
    var result = number.replace(/(\d)(?=(\d{3})+\.)/g, "$1,");

    //remove (,) if thousand separator is (space)
    if (AppHelper.settings.thousandSeparator === " ") {
        result = result.replace(',', ' ');
    }
    if (AppHelper.settings.decimalSeparator === ",") {
        result = replaceAllString(result, ".", "_");
        result = replaceAllString(result, ",", ".");
        result = replaceAllString(result, "_", ",");
    }
    if (currencySymbol === "none") {
        currencySymbol = "";
    }
    if (AppHelper.settings.noOfDecimals == "0") {
        result = result.slice(0, -3); //remove decimals
    }

    if (AppHelper.settings.currencyPosition === "right") {
        return  result + "" + currencySymbol;
    } else {
        if (result.indexOf("-") == "0") {
            result = result.replace('-', '');
            return "-" + currencySymbol + result;
        } else {
            return  currencySymbol + "" + result;
        }
    }
};


calculateDatatableTotal = function (instance, columnNumber, valueModifier, currentPage) {
    var api = instance.api(),
            columnOption = {};
    if (currentPage) {
        columnOption = {page: 'current'};
    }

    return api.column(columnNumber, columnOption).data()
            .reduce(function (previousValue, currentValue, test, test2) {
                if (valueModifier) {
                    return previousValue + valueModifier(currentValue);
                } else {
                    return previousValue + currentValue;
                }
            }, 0);
};

// rmove the formatting to get integer data
unformatCurrency = function (currency, conversionRate) {
    currency = currency.toString();
    var mainAmount = currency, decimalSeparatorUnformatted = false;

    if (currency) {
        currency = currency.replace(/[^0-9.,-]/g, '');

        if (conversionRate) {
            //prepare converted amount
            var currencySymbol = mainAmount.replace(currency, '');
            if (conversionRate[currencySymbol]) {
                //conversion rate exists for this currency
                currency = unformatDecimalSeparator(currency);
                currency = ((1 / conversionRate[currencySymbol]) * 1) * currency;
                currency = currency.toString();
                decimalSeparatorUnformatted = true;
            }
        }

        if (currency.indexOf(".") == 0 || currency.indexOf(",") == 0) {
            currency = currency.slice(1);
        }

        if (!decimalSeparatorUnformatted) {
            currency = unformatDecimalSeparator(currency);
        }

        currency = currency * 1;
    }
    if (currency) {
        return currency;
    }
    return 0;
};

unformatDecimalSeparator = function (currency) {
    if (AppHelper.settings.decimalSeparator === ",") {
        currency = replaceAllString(currency, ".", "");
        currency = replaceAllString(currency, ",", ".");
    } else {
        currency = replaceAllString(currency, ",", "");
    }
    return currency;
};

// convert seconds to hours:minutes:seconds format
secondsToTimeFormat = function (sec) {
    var sec_num = parseInt(sec, 10),
            hours = Math.floor(sec_num / 3600),
            minutes = Math.floor((sec_num - (hours * 3600)) / 60),
            seconds = sec_num - (hours * 3600) - (minutes * 60);
    if (hours < 10) {
        hours = "0" + hours;
    }
    if (minutes < 10) {
        minutes = "0" + minutes;
    }
    if (seconds < 10) {
        seconds = "0" + seconds;
    }
    var time = hours + ':' + minutes + ':' + seconds;
    return time;
};

//clear datatable state
clearAppTableState = function (tableInstance) {
    if (tableInstance) {
        setTimeout(function () {
            tableInstance.api().state.clear();
        }, 200);
    }
};

//show/hide datatable column
showHideAppTableColumn = function (tableInstance, columnIndex, visible) {
    tableInstance.fnSetColumnVis(columnIndex, !!visible);
};

//appMention using at.js
(function ($) {

    $.fn.appMention = function (options) {
        var defaults = {
            at: "@",
            dataType: "json",
            source: "",
            data: {}
        };

        var settings = $.extend({}, defaults, options);

        var selector = this;

        $.ajax({
            url: settings.source,
            data: settings.data,
            dataType: settings.dataType,
            method: "POST",
            success: function (result) {
                if (result.success) {
                    $(selector).atwho({
                        at: settings.at,
                        data: result.data,
                        insertTpl: '${content}'
                    });
                }
            }
        });

    };
})(jQuery);

//custom multi-select controller
(function ($) {
    $.fn.appMultiSelect = function (options) {
        var defaults = {
            text: "",
            options: [],
            onChange: function (values) {
            },
            onInit: function (values) {
            }
        };
        var settings = $.extend({}, defaults, options);

        this.each(function () {

            var $instance = $(this);
            var multiSelect = "", values = [];

            $.each(settings.options, function (index, listOption) {
                var active = "";

                if (listOption.isChecked) {
                    active = " active";
                    values.push(listOption.id);
                }
                //<li class=" list-group-item clickable toggle-table-column" data-column="1">ID</li>
                multiSelect += '<li class="list-group-item clickable ' + active + '" data-name="' + settings.name + '" data-value="' + listOption.id + '">';
                multiSelect += listOption.text;
                multiSelect += '</li>';
            });

            multiSelect = "<div class='dropdown-menu'><ul class='list-group' data-act='multiselect'>" + multiSelect + "</ul></div>";

            var dom = '<div class="mr15 DTTT_container custom-toolbar">'
                    + '<span class="dropdown inline-block filter-multi-select">'
                    + '<button class="btn btn-default dropdown-toggle caret " type="button" data-bs-toggle="dropdown" aria-expanded="true">' + settings.text + ' </button>'
                    + multiSelect + '</span>'
                    + '</div>';

            $instance.append(dom);
            settings.onInit(values);

            var $multiselect = $instance.find("[data-name='" + settings.name + "']");
            $multiselect.click(function () {
                var $selector = $(this);
                $selector.toggleClass("active");
                setTimeout(function () {
                    var values = [];
                    $selector.parent().find("li").each(function () {
                        if ($(this).hasClass("active")) {
                            values.push($(this).attr("data-value"));
                        }
                    });
                    settings.onChange(values);
                });
                return false;
            });
        });
    };
})(jQuery);

//instant popover modifier
(function ($) {
    $.fn.appModifier = function (options) {
        var defaults = {
            actionUrl: "", //the url where the response will go after modification
            value: "", //existing value
            actionType: "select2", //action type
            showbuttons: false, //show submit/cancel button
            datepicker: {}, //options for datepicker
            select2Option: {}, //options for select2
            dataType: 'json',
            onSuccess: function () {
            }
        };

        var settings = $.extend({}, defaults, options);

        //create popover content dom
        var tempId = getRandomAlphabet(5);

        //prepare submit or close buttons
        var buttonDom = "";
        if (settings.showbuttons) {
            buttonDom = "<div class='custom-popover-button-area mt10 clearfix row'>\n\
                            <div id='custom-popover-submit-btn-" + tempId + "' class='col-md-6 pr5'><button class='btn btn-primary btn-sm w100p'><i data-feather='check' class='icon-16'></i></button></div>\n\
                            <div class='col-md-6 pl5 custom-popover-close-btn'><button class='btn btn-default btn-sm w100p'><i data-feather='x' class='icon-16'></i></button></div>\n\
                        </div>";
        }

        //prepare container dom
        var containerDom = "";
        if (settings.actionType === "select2") {
            containerDom = "<input id='" + tempId + "' value='" + settings.value + "' type='text' class='form-control popover-tempId' /> " + buttonDom;
        } else if (settings.actionType === "date") {
            var dateFormat = getJsDateFormat();
            var dateArray = settings.value.split("-"),
                    year = dateArray[0],
                    month = dateArray[1],
                    day = dateArray[2];
            var dateValue = dateFormat.replace("yyyy", year).replace("mm", month).replace("dd", day);

            containerDom = "<div style='height: 240px;' id='" + tempId + "'  data-date='" + dateValue + "' data-date-format='" + dateFormat + "' class='popover-tempId'></div>"; //set height first for right popover position
        }

        var $instance = $(this);
        //show popover
        var offset = $instance.offset();
        var top = offset.top;
        var leftOffset = offset.left;
        var topOffset = top + $instance.outerHeight() + 10; //10 for arrow

        //create popover dom
        var popoverDom = "<div class='app-popover' style='top: " + topOffset + "px; left: " + leftOffset + "px'>\n\
                                <span class='app-popover-arrow' ></span>\n\
                                <div class='app-popover-body'>\n\
                                    <div class='loader-container inline-loader hide'></div>\n\
                                    " + containerDom + " \n\
                                </div>\n\
                            </div>";

        $(".app-popover").remove();
        $("body").append(popoverDom);
        feather.replace();

        //apply select2/datepicker on popover content
        var $inputField = $("#" + tempId);
        if (settings.actionType === "select2") {
            //select2 
            if (settings.showbuttons) {
                //submit with buttons
                $("#" + tempId).select2(settings.select2Option);
            } else {
                $("#" + tempId).select2(settings.select2Option).change(function (action) {
                    initAjaxAction($instance, $(this).val(), settings, action["added"]["text"]);
                });
            }
        } else if (settings.actionType === "date") {
            settings.datepicker.onChangeDate = function (response) {
                initAjaxAction($instance, response, settings);
            };

            setDatePicker("#" + tempId, settings.datepicker);
        }

        //check if the right side is overflowed
        $("body").find(".app-popover").each(function () {
            //position content
            var right = $(window).width() - ($(this).offset().left + $(this).outerWidth());
            if (right < 0) {
                //overflowed
                $(this).css({"left": "unset", "right": "10px"});

                //position arrow
                var right = $(window).width() - ($instance.offset().left + (($instance.outerWidth() / 2) * 1));
                $(this).find(".app-popover-arrow").css({"left": "unset", "right": right});
            }
        });

        //submit button
        $("div#custom-popover-submit-btn-" + tempId).click(function () {
            initAjaxAction($instance, $inputField.val(), settings);
        });

        //close button
        $(".custom-popover-close-btn").click(function () {
            $(".app-popover").remove(); //hide popover
        });

        function initAjaxAction($instance, value, settings, changedText) {
            var popoverContentHeight = $inputField.closest(".app-popover-body").height();
            var popoverContentWidth = $inputField.closest(".app-popover-body").width();
            $inputField.closest(".app-popover-body").find(".loader-container").removeClass("hide").css({"height": popoverContentHeight, "width": popoverContentWidth});
            $inputField.closest(".app-popover-body").find(".custom-popover-button-area").addClass("hide");
            $inputField.addClass("hide");

            $.ajax({
                url: settings.actionUrl,
                type: 'POST',
                dataType: settings.dataType,
                data: {value: value},
                success: function (result) {
                    $(".app-popover").remove(); //hide popover
                    setTimeout(function () {
                        $inputField.closest(".app-popover-body").find(".loader-container").addClass("hide");
                        $inputField.closest(".app-popover-body").find(".custom-popover-button-area").removeClass("hide");
                        $inputField.removeClass("hide");
                    }, 200);

                    if (result.success) {
                        settings.onSuccess(result);

                        //update for select2
                        if (changedText) {
                            $instance.text(changedText);
                        }

                        $instance.attr("data-value", value); //update value for instant future use
                        $(".app-popover").remove();
                    } else {
                        appAlert.error(result.message);
                    }
                }
            });
        }
    };
})(jQuery);

//instant popover modifier
(function ($) {
    $.fn.appConfirmation = function (options) {
        var defaults = {
            title: "",
            btnConfirmLabel: "",
            btnCancelLabel: "",
            onConfirm: function () {
            }
        };

        var settings = $.extend({}, defaults, options);

        var $instance = $(this);
        //show popover
        var offset = $instance.offset();
        var top = offset.top;
        var leftOffset = offset.left;
        var bottomOffset = $(window).height() - (top - 10); //10 for arrow

        //create popover dom
        var popoverDom = "<div class='app-popover' style='bottom: " + bottomOffset + "px; left: " + leftOffset + "px'>\n\
                                <span class='app-popover-arrow bottom-arrow' ></span>\n\
                                <div class='loader-container inline-loader hide'></div>\n\
                                <div class='app-popover-content-container'>\n\
                                    <div class='confirmation-title'>" + settings.title + "</div>\n\
                                    <div class='app-popover-body pt0'>\n\
                                        <div class='custom-popover-button-area mt15 clearfix row'>\n\
                                            <div class='col-md-6 pr5'><button class='btn btn-danger btn-sm w100p confirmation-confirm-button'><i data-feather='check' class='icon-16'></i> " + settings.btnConfirmLabel + "</button></div>\n\
                                            <div class='col-md-6 pl5'><button class='btn btn-default btn-sm w100p confirmation-cancel-button'><i data-feather='x' class='icon-16'></i> " + settings.btnCancelLabel + "</button></div>\n\
                                        </div>\n\
                                    </div>\n\
                                </div>\n\
                            </div>";

        $(".app-popover").remove();
        $("body").append(popoverDom);
        feather.replace();

        //submit button
        $(".confirmation-confirm-button").click(function () {
            $(".app-popover").remove(); //hide popover
            settings.onConfirm();
        });

        //close button
        $(".confirmation-cancel-button").click(function () {
            $(".app-popover").remove(); //hide popover
        });
    };
})(jQuery);
