/**
 * YourTeam Notice 訊息彈出小視窗 (on base bootstrap v4 toast)
 * 
 * 使用方式:
 * <div id="noticeBlock" style="position: fixed; top: 70px; right: 0px; padding: 20px; transition: 0.2s; z-index: 50000; height:100%; ">

    </div>
 * 
 * <script>
 *    $("#noticeBlock").YTNotice("add", { option... });
 * </script>
 * */


class YTNotice {
    constructor(option = {}) {
        this.id = option.id ?? null;
        this.title = option.title ?? "";
        this.content = option.content ?? "";
        this.type = option.type ?? null;
        this.hasCloseBtn = option.hasCloseBtn ?? true;
        this.keepTime = 0;
        this.timeText = option.timeText ?? "剛剛";
        this.iconClass = option.iconClass ?? "";
        this.container = "";
        this.eIcon = "";
        this.eTitle = "";
        this.eTimeAgo = "";
        this.eCloseBtn = "";
        this.eContent = "";
        this.init();
    }

    init = function () {
        this.setNoticeId();
        this.setIconClass();
        this.setContainer();

        if (this.title) {
            this.setTitle(this.title);
        }
        if (this.content) {
            this.setContent(this.content);
        }
        if (this.timeText) {
            this.setTimeAgo(this.timeText);
        }

        $(this.container)[0]._ytNotice = this;
    }

    setNoticeId = function () {
        if (this.id == null) {
            this.id = YT.Math.Random(10000000, 99999999);
        }
    }

    setContainer = function () {
        this.container = $(`<div class="toast fade" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false"> 
                                <div class="toast-header">
                                    
                                </div>
                                <div class="toast-body">
                                    
                                </div>
                            </div>`);

        this.setIcon(this.iconClass);
        this.eTitle = $(`<strong class="mr-auto notice-title"></strong>`);
        this.eTimeAgo = $(`<small class="text-muted notice-ago ml-4"></small>`);
        this.eCloseBtn = $(`<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close"><span aria-hidden="true">&times;</span></button>`);
        this.eContent = $(`<div class="notice-content"></div>`);
        if (this.type != null) {
            this.container.find(".toast-header").append(this.eIcon);
            this.eIcon.addClass("text-" + this.type);
        }
        this.container.find(".toast-header").append(this.eTitle);
        this.container.find(".toast-header").append(this.eTimeAgo);
        if (this.hasCloseBtn) { 
            this.container.find(".toast-header").append(this.eCloseBtn);
        }
        this.container.find(".toast-body").append(this.eContent);
    }

    setIconClass = function () {
        if (this.type == "success") {
            this.iconClass = `fas fa-check`;
        } else if (this.type == "warning") {
            this.iconClass = `fas fa-exclamation-triangle`;
        } else if (this.type == "danger") {
            this.iconClass = `fas fa-times`;
        }
    }

    setIcon = function (iconClass) {
        this.eIcon = $(`<i class="mr-2"></i>`);
        this.eIcon.addClass(iconClass);
    }

    setTitle = function (title = "") {
        this.eTitle.html(title);
    }

    setTimeAgo = function (timeAgo = "") {
        this.eTimeAgo.text(timeAgo);
    }

    setContent = function (content = "") {
        this.eContent.html(content);
    }

}

class YTNoticeBlock {
    constructor(option = {}) {
        this.element = option.element;
        this.offsetBottom = 200;
        this.noticeArr = [];
        this.eScroll = $(`<div class="yt-notice-block-scrollbody"></div>`);
        this.noticeContainer = "";
        this.scrollY = option.scrollY ?? true;

        this.init();
    }

    init = function () {
        this.drawInitScroll();
        this.drawElement();

        if (this.scrollY) {
            this.noticeContainer = this.eScroll;
        } else {
            this.noticeContainer = this.element;
        }

        this.updEleObj();
    }

    drawInitScroll = function () {
        if (this.scrollY) {
            $(this.eScroll).css("height", "100%");
            $(this.eScroll).css("overflow-y", "auto");
            $(this.element).append(this.eScroll);
        }
    }

    drawElement = function () {
        $(this.element).addClass("yt-notice-block");
    }

    showOneNotice = function (obj = null,append = "prepend") {
        if (obj) {
            if (append == "prepend") {
                $(this.noticeContainer).prepend(obj.container);
            } else if (append == "append") {
                $(this.noticeContainer).append(obj.container);
            }
            $(obj.container).toast("show");
        }
    }

    hideOneNotice = function (obj = null) {
        if (obj) {
            let toast = "";
            if (obj.is("div.toast")) {
                toast = obj;
            } else {
                toast = obj.container;
            }

            $(toast).toast('dispose');

            setTimeout(() => {
                $(toast).remove();

                let tarNoticeId = $(toast)[0]._ytNotice.id
                let tarNoticeIdx = this.noticeArr.findIndex(x => x.obj.id == tarNoticeId);
                if (tarNoticeIdx != -1) {
                    this.noticeArr[tarNoticeIdx].canShow = false;
                }

                this.showNotices();
            }, 100)

            
        }
        this.updEleObj();
    }

    checkCanShow = function (notice = null) {
        let lastNoticeOffset = $(this.noticeContainer).find(".toast").last().offset();
        if ($(this.noticeContainer).find(".toast").last().length == 0) {
            return true;
        }

        if ($(notice.obj.container).is(":visible")) {
            return false;
        }

        if (!notice.canShow) {
            return false;
        }

        if (lastNoticeOffset.top + this.offsetBottom > $(window).height()) {
            return false;
        } else {
            return true;
        }
    }

    showNotices = function () {
        $.each(this.noticeArr, (idx, notice) => {
            if (this.checkCanShow(notice)) {
                this.showOneNotice(notice.obj,"append");
            }
        })
    }

    pushNotice = function (option = {}) {
        if (this.noticeArr.findIndex(x => x.obj.id == option.id) == -1) {
            let notice = new YTNotice(option);
            this.noticeArr.push({ obj: notice, time: (new Date()).getTime(), canShow: true });
            this.setEvent(notice);
        }
        this.updEleObj();
    }

    updEleObj = function () {
        $(this.element)[0]._noticeBlock = this;
    }

    setEvent = function (notice) {
        let _this = this;
        $(notice.container).on("hidden.bs.toast", function () {
            setTimeout(() => {
                $(notice.container).remove();

                let tarNoticeId = $(notice.container)[0]._ytNotice.id
                let tarNoticeIdx = _this.noticeArr.findIndex(x => x.obj.id == tarNoticeId);
                if (tarNoticeIdx != -1) {
                    _this.noticeArr[tarNoticeIdx].canShow = false;
                }
                _this.showNotices();
            }, 100)
        })
    }

}

$.fn.YTNotice = function (method = "init", ...args) {
    let _this = this;

    if (method == "init") {
        initNoticeBlock();
    }

    let noticeBlock = _this[0]._noticeBlock;
    if (!noticeBlock) {
        initNoticeBlock();
        noticeBlock = _this[0]._noticeBlock;
    }

    if (method == "add") {
       
        noticeBlock.pushNotice(args[0] ?? {});
        noticeBlock.showNotices();

    } else if (method == "add_many") {
       
        args[0].forEach((arg, idx) => {
            noticeBlock.pushNotice(arg);
        })

        noticeBlock.showNotices();
    } else if (method == "hide") {
        if (args.length == 0) {
            noticeBlock = $(_this).parents(".yt-notice-block")[0]._noticeBlock;
            noticeBlock.hideOneNotice(this);
        }
    }

    function initNoticeBlock() {
        let option = {};
        option.element = _this;
        let noticeBlock = new YTNoticeBlock(option);
    }

}