import {Widget} from "widget/Widget";
import {EventHub} from "event/EventHub";
import {MessageType} from "event/MessageType";
import {Event} from "event/Event";
import {Keys} from "hotkey/Keys";

export class ExpandableText extends Widget {

    private static TemplateNormal = `
        <div class="input-field">
            <i></i>
            <input type="text">
            <label></label>
        </div>`;

    private static Template1 = `
        <ul class="adore_dropDown dropdown-content" style="opacity:1;">
        </ul>`;

    private static Template2 = `
        <li>
            <a href='#!' style=" "></a>
        </li>`;

    private datas: string[];

    private maxShowItems = 5;

    private expandableTextId: string;

    private $attachNode: JQuery;

    private $textCode: JQuery;

    private currentIndex = -1;

    private scrollIndexs: number[];


    constructor(parentId: string, id: string, style: number) {
        super(parentId, id, style);

        this.datas = [];
        this.maxShowItems = 5;
        this.expandableTextId = this.id;

        this.$thisNode = $(ExpandableText.TemplateNormal).attr("id", this.id);
        this.$attachNode = this.$thisNode;
        this.$textCode = this.$thisNode.find("input").attr("id", this.id + "_input");
        this.$thisNode.find("label").attr("for", this.id);

        let own = this;
        //add listener
        this.$textCode.on("input", (e: BaseJQueryEventObject) => {
            own.handleInput(e, this.$textCode.val());
        });
        this.$textCode.on("keydown", (e: JQueryKeyEventObject) => {
            own.handleKeyDown(e);
        });
        this.$textCode.on("blur", (e: BaseJQueryEventObject) => {
            own.handleBlur(e);
        });
        this.$textCode.on("focus", (e: BaseJQueryEventObject) => {
            own.sendFocusGain();
        });
    }

    public setText(args: { text: string }) {
        this.$textCode.val(args.text);
    }

    public setName(args: { name: string }) {
        this.$thisNode.find("label").text(args.name);
    }

    public setItems(args: { items: string[] }) {
        this.datas = args.items;
    }

    public dispose() {
        super.dispose();
        $("#" + this.expandableTextId + "_dropDown").remove();
    }

    public setFocus(): void {
        let $dropDownNode = $("#" + this.id + "_dropDown");
        if ($dropDownNode.css("display") !== "block" && document.activeElement !== this.$textCode[0]) {
            this.$textCode.focus();
        }
    }

    public setEnabled(args: { enabled: boolean }) {
        this.enabled = args.enabled;
        if (this.enabled) {
            this.$thisNode.find("input").removeAttr("disabled");
        } else {
            this.$thisNode.find("input").attr("disabled", "disabled");
        }
    }

    public setPlaceholder(args: { placeholder: string }) {
        this.$thisNode.find("input").attr("placeholder", args.placeholder);
    }

    private handleKeyDown(e: JQueryKeyEventObject) {
        let dropDown = $("#" + this.expandableTextId + "_dropDown");
        let dis = dropDown.css("display");
        // 还未弹出dropDown，忽略
        if (!dis || dis === "none") {
            if (e.keyCode === Keys.DOWN_ARROW) {
                this.showDropDown(e, "", true);
            }
            return;
        }
        let items = dropDown.find("li");
        if (items.length === 0) {
            return;
        }
        //上
        if (e.keyCode === Keys.UP_ARROW) {
            if (this.currentIndex === -1) {
                this.currentIndex = items.length - 1;
            } else {
                this.currentIndex--;
            }
            items.css("background-color", "#FFFFFF");
            if (this.currentIndex < 0) {
                this.currentIndex = -1;
            } else {
                $(items[this.currentIndex]).css("background-color", "#BEBEBE");
                this.$textCode.val($(items[this.currentIndex]).find("a").text().split(" ")[0]);
            }
            this.refreshScroll(dropDown, this.currentIndex);
            e.preventDefault();
            return;
        }
        // 下
        else if (e.keyCode === Keys.DOWN_ARROW) {
            this.currentIndex++;
            items.css("background-color", "#FFFFFF");
            if (this.currentIndex >= items.length) {
                this.currentIndex = -1;
            } else {
                $(items[this.currentIndex]).css("background-color", "#BEBEBE");
                this.$textCode.val($(items[this.currentIndex]).find("a").text().split(" ")[0]);
            }
            this.refreshScroll(dropDown, this.currentIndex);
            e.preventDefault();
            return;
        }
        // enter
        else if (e.keyCode === Keys.ENTER || e.keyCode === Keys.NUMPAD_ENTER) {
            dropDown.css("display", "none");
            if (this.currentIndex >= 0 && this.currentIndex < items.length) {
                let text = $(items[this.currentIndex]).find("a").text();
                let val = text.split(" ")[0];
                this.$textCode.val(val);
                // dispatch modify event
                EventHub.dispatchEvent(MessageType.WIDGET, { id: this.id, text: val, evtType: Event.MODIFY });
                // dispatch click event
                EventHub.dispatchEvent(MessageType.WIDGET, { id: this.id, evtType: Event.CLICK });
            }
        }

    }

    private showDropDown(e: BaseJQueryEventObject, value: string, showAll: boolean) {
        let height = this.$textCode.height();
        this.scrollIndexs = [0, this.maxShowItems - 1];//重置滚动区域的可视下标[beginIndex,endIndex]
        //height = Number(height.replace("px", ""));
        let pos = this.getPosition(this.$textCode[0]);
        let tmpHeight = height + pos[0] + 14;
        // 把原来dropDown remove掉
        $("#" + this.expandableTextId + "_dropDown").remove();
        // 添加 dropDown
        let $dropDown = $(ExpandableText.Template1).attr("id", this.expandableTextId + "_dropDown");
        $dropDown.attr({ mouseOn: "false" });
        $dropDown.appendTo(document.body);

        //设置位置
        $dropDown.css("top", tmpHeight);
        $dropDown.css("left", pos[1]);
        $dropDown.css("background-color", "#FFFFFF");
        this.currentIndex = -1;
        //添加列表
        let $liNode: JQuery;
        if (this.datas) {
            if (showAll === true && value === "") {
                for (let i = 0; i < this.datas.length; i++) {
                    $liNode = $(ExpandableText.Template2);
                    $liNode.find("a").text(this.datas[i]);
                    $liNode.appendTo($dropDown);
                }
            }
            else if (value != "") {
                for (let i = 0; i < this.datas.length; i++) {
                    if (this.datas[i].toLocaleLowerCase().indexOf(value) >= 0) {
                        $liNode = $(ExpandableText.Template2);
                        $liNode.find("a").text(this.datas[i]);
                        $liNode.appendTo($dropDown);
                    }
                }
            }
        }
        let len = $dropDown.find("li").length;
        let inputNode = this.$textCode;
        let tmpId = this.expandableTextId;
        if (len > 0) {
            // 为每个列表添加click事件
            $dropDown.find("li").find("a").on("click", function (e) {
                let value = $(this).text();
                let newValue = value.split(" ")[0];
                $("#" + tmpId + "_input").val(newValue);
                $("#" + tmpId + "_dropDown").css("display", "none");
                // dispatch modify event
                EventHub.dispatchEvent(MessageType.WIDGET, { id: tmpId, text: newValue, evtType: Event.MODIFY });
                // dispatch click event
                EventHub.dispatchEvent(MessageType.WIDGET, { id: tmpId, evtType: Event.CLICK });
            });
            /**
             * 添加mouseover和mouseout事件，解决为input添加blur事件后不能选中选项的问题
             * */
            $dropDown.on("mouseover", function (e) {
                $dropDown.attr("mouseOn", "true");
            });
            $dropDown.on("mouseout", function (e) {
                $dropDown.attr("mouseOn", "false");
            });

            //弹出dropDown
            $dropDown.css("display", "block");
            // 若超出最大显示条数，设置最大高度
            if (len > this.maxShowItems) {
                let h = $($dropDown.find("li")[0]).height();
                let maxHeight = h * this.maxShowItems;
                $dropDown.css("height", maxHeight);
            }
            let own = this;
            $(document).bind('click.' + this.expandableTextId + "_dropDown", function (e) {
                if ((!$dropDown.is(e.target) && !inputNode.is(e.target)) || $dropDown.css("display") === "none") {
                    $dropDown.css("display", "none");
                    $(document).unbind('click.' + tmpId + "_dropDown");
                }
            });
        } else {
            $dropDown.css("display", "none");
        }

    }

    private getPosition(obj: HTMLElement): number[] {
        let pos = [0, 0];
        if (obj && obj.offsetParent) {
            while (obj && obj.offsetParent) {
                pos[0] += obj.offsetTop;
                pos[1] += obj.offsetLeft;
                obj = <HTMLElement>obj.offsetParent;
            }
        }
        return pos;
    }

    private refreshScroll($dropDown: JQuery, currentIndex: number) {
        if (currentIndex === -1) {
            return;
        }
        let count = $dropDown.find("li").length - 1;
        let needRefresh = false;
        /**判断当前下标对应的li是否已经不在可视滚动区域内,若不在，需要刷新滚动条的位置**/
        if (currentIndex < this.scrollIndexs[0]) {
            // 6 10 currentIndex:5
            let endIndex = currentIndex + this.maxShowItems - 1;
            endIndex = endIndex > count ? count : endIndex;
            this.scrollIndexs = [currentIndex, endIndex];
            needRefresh = true;
        } else if (currentIndex > this.scrollIndexs[1]) {
            let beginIndex = currentIndex - this.maxShowItems + 1;
            beginIndex = beginIndex < 0 ? 0 : beginIndex;
            this.scrollIndexs = [beginIndex, currentIndex];
            needRefresh = true;
        }
        if (needRefresh) {
            let h = $dropDown.find("li").height();
            $dropDown[0].scrollTop = h * this.scrollIndexs[0];
        }

    }

    private handleInput(e: BaseJQueryEventObject, value: string) {
        // dispatch modify event
        let tmpId = this.expandableTextId;
        EventHub.dispatchEvent(MessageType.WIDGET, { id: tmpId, text: value, evtType: Event.MODIFY });
        this.showDropDown(e, value.toLocaleLowerCase(), false);
    }

    private handleBlur(e: BaseJQueryEventObject) {
        let mouseOn = $("#" + this.expandableTextId + "_dropDown").attr("mouseOn");
        if (mouseOn === "false") {
            $("#" + this.expandableTextId + "_dropDown").css("display", "none");
        }
    }

    public handleKeyDownEvent(e: KeyboardEvent, hasFilter: boolean) {
        if ($("#" + this.expandableTextId + "_dropDown").css("display") === "block") {
            if (e.keyCode === Keys.ENTER || e.keyCode === Keys.NUMPAD_ENTER || e.keyCode === Keys.DOWN_ARROW
                || e.keyCode === Keys.UP_ARROW) {
                return;
            }
        }
        if (e.keyCode === Keys.LEFT_ARROW
            || e.keyCode === Keys.RIGHT_ARROW) {
            return;
        }
        super.handleKeyDownEvent(e, hasFilter);
    }

    public handleKeyUpEvent(e: KeyboardEvent) {
        if ($("#" + this.expandableTextId + "_dropDown").css("display") === "block") {
            if (e.keyCode === Keys.ENTER || e.keyCode === Keys.NUMPAD_ENTER || e.keyCode === Keys.DOWN_ARROW
                || e.keyCode === Keys.UP_ARROW) {
                return;
            }
        }
        if (e.keyCode === Keys.LEFT_ARROW
            || e.keyCode === Keys.RIGHT_ARROW) {
            return;
        }
        super.handleKeyUpEvent(e);
    }
}