/*
 * Copyright (c) 2016. tom@axisj.com
 * - github.com/thomasjang
 * - www.axisj.com
 */

// ax5.ui.modal
(function () {

    const UI = ax5.ui;
    const U = ax5.util;
    let MODAL;

    UI.addClass({
        className: "modal"
    }, (function () {
        /**
         * @class ax5modal
         * @alias ax5.ui.modal
         * @author tom@axisj.com
         */
        return function () {
            let self = this,
                cfg,
                ENM = {
                    "mousedown": (ax5.info.supportTouch) ? "touchstart" : "mousedown",
                    "mousemove": (ax5.info.supportTouch) ? "touchmove" : "mousemove",
                    "mouseup": (ax5.info.supportTouch) ? "touchend" : "mouseup"
                },
                getMousePosition = function (e) {
                    let mouseObj = e;
                    if ('changedTouches' in e && e.changedTouches) {
                        mouseObj = e.changedTouches[0];
                    }
                    return {
                        clientX: mouseObj.clientX,
                        clientY: mouseObj.clientY
                    }
                };

            this.instanceId = ax5.getGuid();
            this.config = {
                id: 'ax5-modal-' + this.instanceId,
                position: {
                    left: "center",
                    top: "middle",
                    margin: 10
                },
                minimizePosition: "bottom-right",
                clickEventName: (('ontouchstart' in document.documentElement) ? "touchstart" : "click"),
                theme: 'default',
                width: 300,
                height: 400,
                closeToEsc: true,
                disableDrag: false,
                disableResize: false,
                animateTime: 250,
                iframe: false
            };
            this.activeModal = null;
            this.watingModal = false;
            this.$ = {}; // UI inside of the jQuery object store

            cfg = this.config; // extended config copy cfg

            let onStateChanged = function (opts, that) {
                    var eventProcessor = {
                        "resize": function (that) {
                            if (opts && opts.onResize) {
                                opts.onResize.call(that, that);
                            }
                            else if (this.onResize) {
                                this.onResize.call(that, that);
                            }
                        },
                        "move": function () {

                        }
                    };
                    if (that.state in eventProcessor) {
                        eventProcessor[that.state].call(this, that);
                    }

                    if (opts && opts.onStateChanged) {
                        opts.onStateChanged.call(that, that);
                    }
                    else if (this.onStateChanged) {
                        this.onStateChanged.call(that, that);
                    }
                    return true;
                },
                getContent = function (modalId, opts) {
                    let data = {
                        modalId: modalId,
                        theme: opts.theme,
                        header: opts.header,
                        fullScreen: (opts.fullScreen ? "fullscreen" : ""),
                        styles: "",
                        iframe: opts.iframe,
                        iframeLoadingMsg: opts.iframeLoadingMsg,
                        disableResize: opts.disableResize
                    };

                    if (opts.zIndex) {
                        data.styles += "z-index:" + opts.zIndex + ";";
                    }
                    if (opts.absolute) {
                        data.styles += "position:absolute;";
                    }

                    if (data.iframe && typeof data.iframe.param === "string") {
                        data.iframe.param = ax5.util.param(data.iframe.param);
                    }

                    return MODAL.tmpl.get.call(this, "content", data, {});
                },
                open = function (opts, callback) {
                    let that;
                    jQuery(document.body).append(getContent.call(this, opts.id, opts));

                    this.activeModal = jQuery('#' + opts.id);
                    // 파트수집
                    this.$ = {
                        "root": this.activeModal,
                        "header": this.activeModal.find('[data-modal-els="header"]'),
                        "body": this.activeModal.find('[data-modal-els="body"]')
                    };

                    if (opts.iframe) {
                        this.$["iframe-wrap"] = this.activeModal.find('[data-modal-els="iframe-wrap"]');
                        this.$["iframe"] = this.activeModal.find('[data-modal-els="iframe"]');
                        this.$["iframe-form"] = this.activeModal.find('[data-modal-els="iframe-form"]');
                        this.$["iframe-loading"] = this.activeModal.find('[data-modal-els="iframe-loading"]');
                    }
                    else {
                        this.$["body-frame"] = this.activeModal.find('[data-modal-els="body-frame"]');
                    }

                    //- position 정렬
                    this.align();

                    that = {
                        self: this,
                        id: opts.id,
                        theme: opts.theme,
                        width: opts.width,
                        height: opts.height,
                        state: "open",
                        $: this.$
                    };

                    if (opts.iframe) {
                        this.$["iframe-wrap"].css({height: opts.height});
                        this.$["iframe"].css({height: opts.height});

                        // iframe content load
                        this.$["iframe-form"].attr({"method": opts.iframe.method});
                        this.$["iframe-form"].attr({"target": opts.id + "-frame"});
                        this.$["iframe-form"].attr({"action": opts.iframe.url});
                        this.$["iframe"].on("load", (function () {
                            that.state = "load";
                            if (opts.iframeLoadingMsg) {
                                this.$["iframe-loading"].hide();
                            }
                            onStateChanged.call(this, opts, that);
                        }).bind(this));
                        if (!opts.iframeLoadingMsg) {
                            this.$["iframe"].show();
                        }
                        this.$["iframe-form"].submit();
                    }

                    if (callback) callback.call(that, that);

                    if (!this.watingModal) {
                        onStateChanged.call(this, opts, that);
                    }

                    // bind key event
                    if (opts.closeToEsc) {
                        jQuery(window).bind("keydown.ax-modal", (function (e) {
                            onkeyup.call(this, e || window.event);
                        }).bind(this));
                    }

                    jQuery(window).bind("resize.ax-modal", (function (e) {
                        this.align(null, e || window.event);
                    }).bind(this));

                    this.$.header
                        .off(ENM["mousedown"])
                        .off("dragstart")
                        .on(ENM["mousedown"], function (e) {
                            /// 이벤트 필터링 추가 : 버튼엘리먼트로 부터 발생된 이벤트이면 moveModal 시작하지 않도록 필터링
                            let isButton = U.findParentNode(e.target, function (_target) {
                                if (_target.getAttribute("data-modal-header-btn")) {
                                    return true;
                                }
                            });

                            if (!opts.isFullScreen && !isButton && opts.disableDrag != true) {
                                self.mousePosition = getMousePosition(e);
                                moveModal.on.call(self);
                            }
                            if(isButton){
                                btnOnClick.call(self, e || window.event, opts);
                            }
                        })
                        .on("dragstart", function (e) {
                            U.stopEvent(e.originalEvent);
                            return false;
                        });

                    this.activeModal
                        .off(ENM["mousedown"])
                        .off("dragstart")
                        .on(ENM["mousedown"], "[data-ax5modal-resizer]", function (e) {
                            if (opts.disableDrag || opts.isFullScreen) return false;
                            self.mousePosition = getMousePosition(e);
                            resizeModal.on.call(self, this.getAttribute("data-ax5modal-resizer"));
                        })
                        .on("dragstart", function (e) {
                            U.stopEvent(e.originalEvent);
                            return false;
                        });

                },
                btnOnClick = function (e, opts, callback, target, k) {
                    let that;
                    if (e.srcElement) e.target = e.srcElement;

                    target = U.findParentNode(e.target, function (target) {
                        if (target.getAttribute("data-modal-header-btn")) {
                            return true;
                        }
                    });

                    if (target) {
                        k = target.getAttribute("data-modal-header-btn");

                        that = {
                            self: this,
                            key: k, value: opts.header.btns[k],
                            dialogId: opts.id,
                            btnTarget: target
                        };

                        if (opts.header.btns[k].onClick) {
                            opts.header.btns[k].onClick.call(that, k);
                        }
                    }

                    that = null;
                    opts = null;
                    callback = null;
                    target = null;
                    k = null;
                },
                onkeyup = function (e) {
                    if (e.keyCode == ax5.info.eventKeys.ESC) {
                        this.close();
                    }
                },
                alignProcessor = {
                    "top-left": function () {
                        this.align({left: "left", top: "top"});
                    },
                    "top-right": function () {
                        this.align({left: "right", top: "top"});
                    },
                    "bottom-left": function () {
                        this.align({left: "left", top: "bottom"});
                    },
                    "bottom-right": function () {
                        this.align({left: "right", top: "bottom"});
                    },
                    "center-middle": function () {
                        this.align({left: "center", top: "middle"});
                    }
                },
                moveModal = {
                    "on": function () {
                        let modalZIndex = this.activeModal.css("z-index"),
                            modalOffset = this.activeModal.position(),
                            modalBox = {
                                width: this.activeModal.outerWidth(), height: this.activeModal.outerHeight()
                            },
                            windowBox = {
                                width: jQuery(window).width(),
                                height: jQuery(window).height(),
                                scrollLeft: (self.modalConfig.absolute) ? 0 : jQuery(document).scrollLeft(),
                                scrollTop: (self.modalConfig.absolute) ? 0 : jQuery(document).scrollTop(),
                            },
                            getResizerPosition = function (e) {
                                self.__dx = e.clientX - self.mousePosition.clientX;
                                self.__dy = e.clientY - self.mousePosition.clientY;

                                if (minX > modalOffset.left + self.__dx) {
                                    self.__dx = -modalOffset.left;
                                }
                                else if (maxX < modalOffset.left + self.__dx) {
                                    self.__dx = (maxX) - modalOffset.left;
                                }

                                if (minY > modalOffset.top + self.__dy) {
                                    self.__dy = -modalOffset.top;
                                }
                                else if (maxY < modalOffset.top + self.__dy) {
                                    self.__dy = (maxY) - modalOffset.top;
                                }

                                return {
                                    left: modalOffset.left + self.__dx + windowBox.scrollLeft,
                                    top: modalOffset.top + self.__dy + windowBox.scrollTop
                                };
                            };

                        let minX = 0, maxX = windowBox.width - modalBox.width,
                            minY = 0, maxY = windowBox.height - modalBox.height;

                        self.__dx = 0; // 변화량 X
                        self.__dy = 0; // 변화량 Y

                        // self.resizerBg : body 가 window보다 작을 때 문제 해결을 위한 DIV
                        self.resizerBg = jQuery('<div class="ax5modal-resizer-background" ondragstart="return false;"></div>');
                        self.resizer = jQuery('<div class="ax5modal-resizer" ondragstart="return false;"></div>');
                        self.resizerBg.css({zIndex: modalZIndex});
                        self.resizer.css({
                            left: modalOffset.left + windowBox.scrollLeft,
                            top: modalOffset.top + windowBox.scrollTop,
                            width: modalBox.width,
                            height: modalBox.height,
                            zIndex: modalZIndex + 1
                        });

                        jQuery(document.body)
                            .append(self.resizerBg)
                            .append(self.resizer);
                        self.activeModal.addClass("draged");

                        jQuery(document.body)
                            .on(ENM["mousemove"] + ".ax5modal-move-" + this.instanceId, function (e) {
                                self.resizer.css(getResizerPosition(e));
                            })
                            .on(ENM["mouseup"] + ".ax5modal-move-" + this.instanceId, function (e) {
                                moveModal.off.call(self);
                            })
                            .on("mouseleave.ax5modal-move-" + this.instanceId, function (e) {
                                moveModal.off.call(self);
                            });

                        jQuery(document.body)
                            .attr('unselectable', 'on')
                            .css('user-select', 'none')
                            .on('selectstart', false);
                    },
                    "off": function () {
                        let setModalPosition = function () {
                            let box = this.resizer.offset();
                            if (!this.modalConfig.absolute) {
                                box.left -= jQuery(document).scrollLeft();
                                box.top -= jQuery(document).scrollTop();
                            }
                            this.activeModal.css(box);
                            this.modalConfig.left = box.left;
                            this.modalConfig.top = box.top;

                            box = null;
                        };

                        this.activeModal.removeClass("draged");
                        setModalPosition.call(this);

                        this.resizer.remove();
                        this.resizer = null;
                        this.resizerBg.remove();
                        this.resizerBg = null;
                        //this.align();

                        jQuery(document.body)
                            .off(ENM["mousemove"] + ".ax5modal-move-" + this.instanceId)
                            .off(ENM["mouseup"] + ".ax5modal-move-" + this.instanceId)
                            .off("mouseleave.ax5modal-move-" + this.instanceId);

                        jQuery(document.body)
                            .removeAttr('unselectable')
                            .css('user-select', 'auto')
                            .off('selectstart');

                        onStateChanged.call(this, self.modalConfig, {
                            self: this,
                            state: "move"
                        });

                    }
                },
                resizeModal = {
                    "on": function (resizerType) {
                        let modalZIndex = this.activeModal.css("z-index"),
                            modalOffset = this.activeModal.position(),
                            modalBox = {
                                width: this.activeModal.outerWidth(), height: this.activeModal.outerHeight()
                            },
                            windowBox = {
                                width: jQuery(window).width(),
                                height: jQuery(window).height(),
                                scrollLeft: (this.modalConfig.absolute) ? 0 : jQuery(document).scrollLeft(),
                                scrollTop: (this.modalConfig.absolute) ? 0 : jQuery(document).scrollTop(),
                            },
                            resizerProcessor = {
                                "top": function (e) {

                                    if (minHeight > modalBox.height - self.__dy) {
                                        self.__dy = modalBox.height - (minHeight);
                                    }

                                    if (e.shiftKey) {

                                        if (minHeight > modalBox.height - (self.__dy * 2)) {
                                            self.__dy = (modalBox.height - (minHeight)) / 2;
                                        }

                                        return {
                                            left: modalOffset.left,
                                            top: modalOffset.top + self.__dy,
                                            width: modalBox.width,
                                            height: modalBox.height - (self.__dy * 2)
                                        };
                                    }
                                    else if (e.altKey) {

                                        if (minHeight > modalBox.height - (self.__dy * 2)) {
                                            self.__dy = (modalBox.height - (minHeight)) / 2;
                                        }

                                        return {
                                            left: modalOffset.left + self.__dy,
                                            top: modalOffset.top + self.__dy,
                                            width: modalBox.width - (self.__dy * 2),
                                            height: modalBox.height - (self.__dy * 2)
                                        };
                                    }
                                    else {
                                        return {
                                            left: modalOffset.left,
                                            top: modalOffset.top + self.__dy,
                                            width: modalBox.width,
                                            height: modalBox.height - self.__dy,
                                        };
                                    }
                                },
                                "bottom": function (e) {

                                    if (minHeight > modalBox.height + self.__dy) {
                                        self.__dy = -modalBox.height + (minHeight);
                                    }

                                    if (e.shiftKey) {

                                        if (minHeight > modalBox.height + (self.__dy * 2)) {
                                            self.__dy = (-modalBox.height + (minHeight)) / 2;
                                        }

                                        return {
                                            left: modalOffset.left,
                                            top: modalOffset.top - self.__dy,
                                            width: modalBox.width,
                                            height: modalBox.height + (self.__dy * 2)
                                        };
                                    }
                                    else if (e.altKey) {

                                        if (minHeight > modalBox.height + (self.__dy * 2)) {
                                            self.__dy = (-modalBox.height + (minHeight)) / 2;
                                        }

                                        return {
                                            left: modalOffset.left - self.__dy,
                                            top: modalOffset.top - self.__dy,
                                            width: modalBox.width + (self.__dy * 2),
                                            height: modalBox.height + (self.__dy * 2),
                                        };
                                    }
                                    else {
                                        return {
                                            left: modalOffset.left,
                                            top: modalOffset.top,
                                            width: modalBox.width,
                                            height: modalBox.height + self.__dy,
                                        };
                                    }
                                },
                                "left": function (e) {

                                    if (minWidth > modalBox.width - self.__dx) {
                                        self.__dx = modalBox.width - (minWidth);
                                    }

                                    if (e.shiftKey) {

                                        if (minWidth > modalBox.width - (self.__dx * 2)) {
                                            self.__dx = (modalBox.width - (minWidth)) / 2;
                                        }

                                        return {
                                            left: modalOffset.left + self.__dx,
                                            top: modalOffset.top,
                                            width: modalBox.width - (self.__dx * 2),
                                            height: modalBox.height
                                        };
                                    }
                                    else if (e.altKey) {

                                        if (minWidth > modalBox.width - (self.__dx * 2)) {
                                            self.__dx = (modalBox.width - (minWidth)) / 2;
                                        }

                                        return {
                                            left: modalOffset.left + self.__dx,
                                            top: modalOffset.top + self.__dx,
                                            width: modalBox.width - (self.__dx * 2),
                                            height: modalBox.height - (self.__dx * 2),
                                        };
                                    }
                                    else {
                                        return {
                                            left: modalOffset.left + self.__dx,
                                            top: modalOffset.top,
                                            width: modalBox.width - self.__dx,
                                            height: modalBox.height,
                                        };
                                    }
                                },
                                "right": function (e) {

                                    if (minWidth > modalBox.width + self.__dx) {
                                        self.__dx = -modalBox.width + (minWidth);
                                    }

                                    if (e.shiftKey) {

                                        if (minWidth > modalBox.width + (self.__dx * 2)) {
                                            self.__dx = (-modalBox.width + (minWidth)) / 2;
                                        }

                                        return {
                                            left: modalOffset.left - self.__dx,
                                            top: modalOffset.top,
                                            width: modalBox.width + (self.__dx * 2),
                                            height: modalBox.height,
                                        };
                                    }
                                    else if (e.altKey) {

                                        if (minWidth > modalBox.width + (self.__dx * 2)) {
                                            self.__dx = (-modalBox.width + (minWidth)) / 2;
                                        }

                                        return {
                                            left: modalOffset.left - self.__dx,
                                            top: modalOffset.top - self.__dx,
                                            width: modalBox.width + (self.__dx * 2),
                                            height: modalBox.height + (self.__dx * 2),
                                        };
                                    }
                                    else {
                                        return {
                                            left: modalOffset.left,
                                            top: modalOffset.top,
                                            width: modalBox.width + self.__dx,
                                            height: modalBox.height,
                                        };
                                    }
                                },
                                "top-left": function (e) {

                                    if (minWidth > modalBox.width - self.__dx) {
                                        self.__dx = modalBox.width - (minWidth);
                                    }

                                    if (minHeight > modalBox.height - self.__dy) {
                                        self.__dy = modalBox.height - (minHeight);
                                    }

                                    if (e.shiftKey || e.altKey) {

                                        if (minHeight > modalBox.height - (self.__dy * 2)) {
                                            self.__dy = (modalBox.height - (minHeight)) / 2;
                                        }
                                        if (minWidth > modalBox.width - (self.__dx * 2)) {
                                            self.__dx = (modalBox.width - (minWidth)) / 2;
                                        }

                                        return {
                                            left: modalOffset.left + self.__dx,
                                            top: modalOffset.top + self.__dy,
                                            width: modalBox.width - (self.__dx * 2),
                                            height: modalBox.height - (self.__dy * 2),
                                        };
                                    }
                                    else {

                                        if (minHeight > modalBox.height - (self.__dy * 2)) {
                                            self.__dy = (modalBox.height - (minHeight)) / 2;
                                        }
                                        if (minWidth > modalBox.width - (self.__dx * 2)) {
                                            self.__dx = (modalBox.width - (minWidth)) / 2;
                                        }

                                        return {
                                            left: modalOffset.left + self.__dx,
                                            top: modalOffset.top + self.__dy,
                                            width: modalBox.width - self.__dx,
                                            height: modalBox.height - self.__dy,
                                        };
                                    }
                                },
                                "top-right": function (e) {

                                    if (minWidth > modalBox.width + self.__dx) {
                                        self.__dx = -modalBox.width + (minWidth);
                                    }

                                    if (minHeight > modalBox.height - self.__dy) {
                                        self.__dy = modalBox.height - (minHeight);
                                    }

                                    if (e.shiftKey || e.altKey) {

                                        if (minHeight > modalBox.height - (self.__dy * 2)) {
                                            self.__dy = (modalBox.height - (minHeight)) / 2;
                                        }
                                        if (minWidth > modalBox.width + (self.__dx * 2)) {
                                            self.__dx = (-modalBox.width + (minWidth)) / 2;
                                        }

                                        return {
                                            left: modalOffset.left - self.__dx,
                                            top: modalOffset.top + self.__dy,
                                            width: modalBox.width + (self.__dx * 2),
                                            height: modalBox.height - (self.__dy * 2),
                                        };
                                    }
                                    else {
                                        return {
                                            left: modalOffset.left,
                                            top: modalOffset.top + self.__dy,
                                            width: modalBox.width + self.__dx,
                                            height: modalBox.height - self.__dy,
                                        };
                                    }
                                },
                                "bottom-left": function (e) {

                                    if (minWidth > modalBox.width - self.__dx) {
                                        self.__dx = modalBox.width - (minWidth);
                                    }

                                    if (minHeight > modalBox.height + self.__dy) {
                                        self.__dy = -modalBox.height + (minHeight);
                                    }

                                    if (e.shiftKey || e.altKey) {
                                        if (minWidth > modalBox.width - (self.__dx * 2)) {
                                            self.__dx = (modalBox.width - (minWidth)) / 2;
                                        }
                                        if (minHeight > modalBox.height + (self.__dy * 2)) {
                                            self.__dy = (-modalBox.height + (minHeight)) / 2;
                                        }
                                        return {
                                            left: modalOffset.left + self.__dx,
                                            top: modalOffset.top - self.__dy,
                                            width: modalBox.width - (self.__dx * 2),
                                            height: modalBox.height + (self.__dy * 2),
                                        };
                                    }
                                    else {
                                        return {
                                            left: modalOffset.left + self.__dx,
                                            top: modalOffset.top,
                                            width: modalBox.width - self.__dx,
                                            height: modalBox.height + self.__dy,
                                        };
                                    }
                                },
                                "bottom-right": function (e) {

                                    if (minWidth > modalBox.width + self.__dx) {
                                        self.__dx = -modalBox.width + (minWidth);
                                    }

                                    if (minHeight > modalBox.height + self.__dy) {
                                        self.__dy = -modalBox.height + (minHeight);
                                    }

                                    if (e.shiftKey || e.altKey) {
                                        if (minWidth > modalBox.width + (self.__dx * 2)) {
                                            self.__dx = (-modalBox.width + (minWidth)) / 2;
                                        }
                                        if (minHeight > modalBox.height + (self.__dy * 2)) {
                                            self.__dy = (-modalBox.height + (minHeight)) / 2;
                                        }
                                        return {
                                            left: modalOffset.left - self.__dx,
                                            top: modalOffset.top - self.__dy,
                                            width: modalBox.width + (self.__dx * 2),
                                            height: modalBox.height + (self.__dy * 2),
                                        };
                                    }
                                    else {
                                        return {
                                            left: modalOffset.left,
                                            top: modalOffset.top,
                                            width: modalBox.width + self.__dx,
                                            height: modalBox.height + self.__dy,
                                        };
                                    }
                                },
                            },
                            getResizerPosition = function (e) {
                                self.__dx = e.clientX - self.mousePosition.clientX;
                                self.__dy = e.clientY - self.mousePosition.clientY;

                                return resizerProcessor[resizerType](e);
                            };

                        if (!this.modalConfig.absolute) {
                            modalOffset.left += windowBox.scrollLeft;
                            modalOffset.top += windowBox.scrollTop;
                        }

                        let minWidth = 100,
                            minHeight = 100;

                        let cursorType = {
                            "top": "row-resize",
                            "bottom": "row-resize",
                            "left": "col-resize",
                            "right": "col-resize",
                            "top-left": "nwse-resize",
                            "top-right": "nesw-resize",
                            "bottom-left": "nesw-resize",
                            "bottom-right": "nwse-resize",
                        };

                        self.__dx = 0; // 변화량 X
                        self.__dy = 0; // 변화량 Y

                        // self.resizerBg : body 가 window보다 작을 때 문제 해결을 위한 DIV
                        self.resizerBg = jQuery('<div class="ax5modal-resizer-background" ondragstart="return false;"></div>');
                        self.resizer = jQuery('<div class="ax5modal-resizer" ondragstart="return false;"></div>');
                        self.resizerBg.css({
                            zIndex: modalZIndex,
                            cursor: cursorType[resizerType]
                        });
                        self.resizer.css({
                            left: modalOffset.left,
                            top: modalOffset.top,
                            width: modalBox.width,
                            height: modalBox.height,
                            zIndex: modalZIndex + 1,
                            cursor: cursorType[resizerType]
                        });
                        jQuery(document.body)
                            .append(self.resizerBg)
                            .append(self.resizer);
                        self.activeModal.addClass("draged");

                        jQuery(document.body)
                            .bind(ENM["mousemove"] + ".ax5modal-resize-" + this.instanceId, function (e) {
                                self.resizer.css(getResizerPosition(e));
                            })
                            .bind(ENM["mouseup"] + ".ax5modal-resize-" + this.instanceId, function (e) {
                                resizeModal.off.call(self);
                            })
                            .bind("mouseleave.ax5modal-resize-" + this.instanceId, function (e) {
                                resizeModal.off.call(self);
                            });

                        jQuery(document.body)
                            .attr('unselectable', 'on')
                            .css('user-select', 'none')
                            .bind('selectstart', false);
                    },
                    "off": function () {
                        let setModalPosition = function () {
                            let box = this.resizer.offset();
                            jQuery.extend(box, {
                                width: this.resizer.width(),
                                height: this.resizer.height(),
                            });
                            if (!this.modalConfig.absolute) {
                                box.left -= jQuery(document).scrollLeft();
                                box.top -= jQuery(document).scrollTop();
                            }
                            this.activeModal.css(box);

                            this.modalConfig.left = box.left;
                            this.modalConfig.top = box.top;
                            this.modalConfig.width = box.width;
                            this.modalConfig.height = box.height;
                            this.$["body"].css({height: box.height - this.modalConfig.headerHeight});
                            if (this.modalConfig.iframe) {
                                this.$["iframe-wrap"].css({height: box.height - this.modalConfig.headerHeight});
                                this.$["iframe"].css({height: box.height - this.modalConfig.headerHeight});
                            }

                            box = null;
                        };

                        this.activeModal.removeClass("draged");
                        setModalPosition.call(this);

                        this.resizer.remove();
                        this.resizer = null;
                        this.resizerBg.remove();
                        this.resizerBg = null;

                        onStateChanged.call(this, self.modalConfig, {
                            self: this,
                            state: "resize"
                        });

                        jQuery(document.body)
                            .unbind(ENM["mousemove"] + ".ax5modal-resize-" + this.instanceId)
                            .unbind(ENM["mouseup"] + ".ax5modal-resize-" + this.instanceId)
                            .unbind("mouseleave.ax5modal-resize-" + this.instanceId);

                        jQuery(document.body)
                            .removeAttr('unselectable')
                            .css('user-select', 'auto')
                            .unbind('selectstart');

                    }
                };

            /// private end

            /**
             * Preferences of modal UI
             * @method ax5modal.setConfig
             * @param {Object} config - 클래스 속성값
             * @param {Number} [config.zIndex]
             * @param {Object} [config.position]
             * @param {String} [config.position.left="center"]
             * @param {String} [config.position.top="middle"]
             * @param {Number} [config.position.margin=10]
             * @param {String} [config.minimizePosition="bottom-right"]
             * @param {Number} [config.width=300]
             * @param {Number} [config.height=400]
             * @param {Boolean} [config.closeToEsc=true]
             * @param {Boolean} [config.absolute=false]
             * @param {Boolean} [config.disableDrag=false]
             * @param {Boolean} [config.disableResize=false]
             * @param {Number} [config.animateTime=250]
             * @param {Function} [config.fullScreen]
             * @param {Function} [config.onStateChanged] - `onStateChanged` function can be defined in setConfig method or new ax5.ui.modal initialization method. However, you can us to define an event function after initialization, if necessary
             * @param {Function} [config.onResize]
             * @returns {ax5modal}
             * @example
             * ```js
             * var modal = new ax5.ui.modal({
             *     iframeLoadingMsg: '<i class="fa fa-spinner fa-5x fa-spin" aria-hidden="true"></i>',
             *     header: {
             *         title: "MODAL TITLE",
             *         btns: {
             *             minimize: {
             *                 label: '<i class="fa fa-minus-circle" aria-hidden="true"></i>', onClick: function () {
             *                     modal.minimize();
             *                 }
             *             },
             *             maximize: {
             *                 label: '<i class="fa fa-plus-circle" aria-hidden="true"></i>', onClick: function () {
             *                     modal.maximize();
             *                 }
             *             },
             *             close: {
             *                 label: '<i class="fa fa-times-circle" aria-hidden="true"></i>', onClick: function () {
             *                     modal.close();
             *                 }
             *             }
             *         }
             *     }
             * });
             *
             * modal.open({
             *     width: 800,
             *     height: 600,
             *     fullScreen: function(){
             *         return ($(window).width() < 600);
             *     },
             *     iframe: {
             *         method: "get",
             *         url: "http://chequer-app:2017/html/login.html",
             *         param: "callback=modalCallback"
             *     },
             *     onStateChanged: function(){
             *          console.log(this);
             *     },
             *     onResize: function(){
             *          console.log(this);
             *     }
             * });
             * ```
             */
            //== class body start
            this.init = function () {
                this.onStateChanged = cfg.onStateChanged;
                this.onResize = cfg.onResize;
            };

            /**
             * open the modal
             * @method ax5modal.open
             * @returns {ax5modal}
             * @example
             * ```
             * modal.open();
             * modal.open({
             *  width: 500,
             *  height: 500
             * });
             * moaal.open({}, function(){
             *  console.log(this);
             * });
             * ```
             */
            this.open = function (opts, callback, tryCount) {
                if (typeof tryCount === "undefined") tryCount = 0;
                if (!this.activeModal) {
                    opts = self.modalConfig = jQuery.extend(true, {}, cfg, opts);
                    open.call(this, opts, callback);
                    this.watingModal = false;
                }
                else if (tryCount < 3) {
                    // 3번까지 재 시도
                    this.watingModal = true;
                    setTimeout((function () {
                        this.open(opts, callback, tryCount + 1);
                    }).bind(this), cfg.animateTime);
                } else {
                    // 열기 시도 종료
                    this.watingModal = false;
                }
                return this;
            };

            /**
             * close the modal
             * @method ax5modal.close
             * @param _option
             * @returns {ax5modal}
             * @example
             * ```
             * my_modal.close();
             * my_modal.close({callback: function(){
             *  // on close event
             * });
             * // close 함수에 callback을 전달하면 정확한 close 타이밍을 캐치할 수 있습니다
             * ```
             */

            this.close = function (_option) {
                let opts, that;

                if (this.activeModal) {
                    opts = self.modalConfig;
                    this.activeModal.addClass("destroy");
                    jQuery(window).unbind("keydown.ax-modal");
                    jQuery(window).unbind("resize.ax-modal");


                    setTimeout((function () {
                        // 프레임 제거
                        if (opts.iframe) {
                            var $iframe = this.$["iframe"]; // iframe jQuery Object
                            if ($iframe) {
                                var iframeObject = $iframe.get(0),
                                    idoc = (iframeObject.contentDocument) ? iframeObject.contentDocument : iframeObject.contentWindow.document;

                                try {
                                    $(idoc.body).children().each(function () {
                                        $(this).remove();
                                    });
                                } catch (e) {

                                }
                                idoc.innerHTML = "";
                                $iframe
                                    .attr('src', 'about:blank')
                                    .remove();

                                // force garbarge collection for IE only
                                window.CollectGarbage && window.CollectGarbage();
                            }
                        }

                        this.activeModal.remove();
                        this.activeModal = null;

                        // 모달 오픈 대기중이면 닫기 상태 전달 안함.
                        if (!this.watingModal) {
                            onStateChanged.call(this, opts, {
                                self: this,
                                state: "close"
                            });
                        }

                        if (_option && U.isFunction(_option.callback)) {
                            that = {
                                self: this,
                                id: opts.id,
                                theme: opts.theme,
                                width: opts.width,
                                height: opts.height,
                                state: "close",
                                $: this.$
                            };
                            _option.callback.call(that, that);
                        }

                    }).bind(this), cfg.animateTime);
                }

                this.minimized = false; // hoksi

                return this;
            };

            /**
             * @method ax5modal.minimize
             * @returns {ax5modal}
             */
            this.minimize = (function () {

                return function (minimizePosition) {

                    if (this.minimized !== true) {

                        var opts = self.modalConfig;
                        if (typeof minimizePosition === "undefined") minimizePosition = cfg.minimizePosition;

                        this.minimized = true;
                        this.$.body.hide();
                        self.modalConfig.originalHeight = opts.height;
                        self.modalConfig.height = 0;
                        alignProcessor[minimizePosition].call(this);

                        onStateChanged.call(this, opts, {
                            self: this,
                            state: "minimize"
                        });
                    }

                    return this;
                };
            })();

            /**
             * @method ax5modal.restore
             * @returns {ax5modal}
             */
            this.restore = function () {
                var opts = self.modalConfig;
                if (this.minimized) {
                    this.minimized = false;
                    this.$.body.show();
                    self.modalConfig.height = self.modalConfig.originalHeight;
                    self.modalConfig.originalHeight = undefined;

                    this.align({left: "center", top: "middle"});
                    onStateChanged.call(this, opts, {
                        self: this,
                        state: "restore"
                    });
                }
                return this;
            };

            /**
             * setCSS
             * @method ax5modal.css
             * @param {Object} css -
             * @returns {ax5modal}
             */
            this.css = function (css) {
                if (this.activeModal && !self.fullScreen) {
                    this.activeModal.css(css);
                    if (typeof css.width !== "undefined") {
                        self.modalConfig.width = css.width;
                    }
                    if (typeof css.height !== "undefined") {
                        self.modalConfig.height = css.height;
                    }

                    this.align();
                }
                return this;
            };

            /**
             * @method ax5modal.setModalConfig
             * @param _config
             * @returns {ax5.ui.ax5modal}
             */
            this.setModalConfig = function (_config) {
                self.modalConfig = jQuery.extend({}, self.modalConfig, _config);
                this.align();
                return this;
            };

            /**
             * @method ax5modal.align
             * @param position
             * @param e
             * @returns {ax5modal}
             * @example
             * ```js
             * modal.align({left:"center", top:"middle"});
             * modal.align({left:"left", top:"top", margin: 20});
             * ```
             */
            this.align = (function () {

                return function (position, e) {
                    if (!this.activeModal) return this;

                    var opts = self.modalConfig,
                        box = {
                            width: opts.width,
                            height: opts.height
                        };

                    var fullScreen = opts.isFullScreen = (function (_fullScreen) {
                        if (typeof _fullScreen === "undefined") {
                            return false;
                        } else if (U.isFunction(_fullScreen)) {
                            return _fullScreen();
                        }
                    })(opts.fullScreen);

                    if (fullScreen) {
                        if (opts.header) this.$.header.show();
                        if (opts.header) {
                            opts.headerHeight = this.$.header.outerHeight();
                            box.height += opts.headerHeight;
                        } else {
                            opts.headerHeight = 0;
                        }
                        box.width = jQuery(window).width();
                        box.height = opts.height;
                        box.left = 0;
                        box.top = 0;
                    }
                    else {
                        if (opts.header) this.$.header.show();
                        if (position) {
                            jQuery.extend(true, opts.position, position);
                        }

                        if (opts.header) {
                            opts.headerHeight = this.$.header.outerHeight();
                            box.height += opts.headerHeight;
                        } else {
                            opts.headerHeight = 0;
                        }

                        //- position 정렬
                        if (opts.position.left == "left") {
                            box.left = (opts.position.margin || 0);
                        }
                        else if (opts.position.left == "right") {
                            // window.innerWidth;
                            box.left = jQuery(window).width() - box.width - (opts.position.margin || 0);
                        }
                        else if (opts.position.left == "center") {
                            box.left = jQuery(window).width() / 2 - box.width / 2;
                        }
                        else {
                            box.left = opts.position.left || 0;
                        }

                        if (opts.position.top == "top") {
                            box.top = (opts.position.margin || 0);
                        }
                        else if (opts.position.top == "bottom") {
                            box.top = jQuery(window).height() - box.height - (opts.position.margin || 0);
                        }
                        else if (opts.position.top == "middle") {
                            box.top = jQuery(window).height() / 2 - box.height / 2;
                        }
                        else {
                            box.top = opts.position.top || 0;
                        }
                        if (box.left < 0) box.left = 0;
                        if (box.top < 0) box.top = 0;
                    }

                    this.activeModal.css(box);
                    this.$["body"].css({height: box.height - (opts.headerHeight || 0)});
                    
                    if (opts.iframe) {
                        this.$["iframe-wrap"].css({height: box.height - opts.headerHeight});
                        this.$["iframe"].css({height: box.height - opts.headerHeight});
                    } else {

                    }
                    return this;
                };
            })();

            // 클래스 생성자
            this.main = (function () {

                UI.modal_instance = UI.modal_instance || [];
                UI.modal_instance.push(this);

                if (arguments && U.isObject(arguments[0])) {
                    this.setConfig(arguments[0]);
                }

            }).apply(this, arguments);
        };
    })());

    MODAL = ax5.ui.modal;
})();
