/** *
 * 工具类
 */
(function () {

    /**
     * 最新修改的元素
     */
    const latestOpDoc = null

    class MyRecovery {
        constructor(data, func) {
            this.data = data;
            this.func = func;
        }

        getData() {
            return this.data;
        }

        getFun() {
            return this.func;
        }

        recovery() {
            this.func();
        }
    }

    /**
     * 行数增加记录
     */
    const num = 0

    /**
     * 是否开始输入中文
     */
    const inCompositionEvent = false;

    /**
     * 我的文档数据
     */
    const MyDocMap = new Map()


    // push,推一个在后面,就是 append 的意思
    // pop,从后面拉走,配合 push 就是栈
    // unshift,从前面加一个数据,就是 insert(it, 0) 的意思
    // shift,前面拉个数据走,配合 shift 就是一个反向栈,配合 push 就是队列
    class MyQueue {
        constructor(size) {
            this.insertIndex = 0
            this.delIndex = 0
            this.capacity = 0;
            this.size = size;
            this.arr = new Array(size);
        }

        push(handle) {
            if (this.capacity === this.arr.length) {
                console.log("满了");
                this.capacity--;
                this.arr[this.capacity] = null;

                //todo 替代
                // this.end++;
            }
            this.arr[this.capacity] = handle;
            this.capacity++;
        }

        pull() {
            if (this.capacity <= 0) {
                return null
            }
            this.capacity--;

            //到底回退
            if (this.shift > this.size) {
                this.shift = 0;
            }

            return this.arr[this.shift];
        }
    }


    class MyNode {
        constructor(id) {
            this.id = id
            this.hidden = false
            this.style = new InnerStyle()
        }

        getHidden() {
            return this.hidden
        }

        setHidden(val) {
            this.hidden = val
        }

        setSource(source) {
            this.source = source
        }

        getSource() {
            return this.source
        }

        getStyle() {
            return this.style
        }
    }

    class InnerStyle {
        constructor() {
            this.nodeType = "p"
            //map-> index:classList
            this.childrenStyle = null;
            this.preStyle = null;

            this.getNodeType = function getNodeType() {
                return this.nodeType
            }
            this.setNodeType = function setNodeType(nodeType) {
                this.nodeType = nodeType
            }

            //前置类型 如 ul ol 代码块 等
            this.setPreStyle = function setPreStyle(k, v) {
                if (this.preStyle == null) {
                    this.preStyle = new MyKV(k, v);
                }
            }
            this.getPreStyle = function getPreStyle() {
                return this.preStyle
            }
        }

        setChildrenStyle(index, classList) {
            if (this.childrenStyle === null) {
                this.childrenStyle = new Map();
            }
            this.childrenStyle.set(index, classList)
        }

        getChildrenStyle(index) {
            return this.childrenStyle.get(index);
        }

        getChildrenStyleMap() {
            return this.childrenStyle;
        }

        setChildrenStyleMapNull() {
            this.childrenStyle = null;
        }

    }

    class MyKV {
        constructor(k, v) {
            this.k = k
            this.v = v

            this.getK = function getK() {
                return this.k
            }
            this.getV = function getV() {
                return this.v
            }

        }
    }

    /**
     * 主节点元素
     */
    const MyRoot = document.getElementById("noteshare")


    function isNum(value) {
        return !isNaN(parseFloat(value)) && isFinite(value)
    }

    function getSelection() {
        return window.getSelection() || document.selection
    }

    /**
     *
     * @returns 生产uuid
     */
    function uuid() {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
            .replace(/[xy]/g, function (c) {
                const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8)
                return v.toString(16)
            }).split("-")[0]
    }

    /**
     * 在目标元素后面插叙 新元素
     * @param {*} newElement
     * @param {*} targetElement
     */
    function insertAfter(newElement, targetElement) {
        // console.log("开始: ",newElement, targetElement)
        var parent = targetElement.parentNode
        if (parent.lastChild == targetElement) {
            // 如果最后的节点是目标元素,则直接添加。因为默认是最后
            parent.appendChild(newElement)
        } else {
            parent.insertBefore(newElement, targetElement.nextSibling)
            //如果不是,则插入在目标元素的下一个兄弟节点 的前面。也就是目标元素的后面
        }
    }

    function parseOrder(curP) {
        return parseInt(curP.getAttribute("data-order"))
    }

    /**
     *
     * @param {*} curP
     * @param onkeydownHandle
     */
    function firstCmd(curP, onkeydownHandle) {
        let newParagraph;
        let inputLength = curP.innerText.length
        /**
         * h1 ~ h6
         */
        if (curP.innerText.startsWith("#") && curP.innerHTML.endsWith("&nbsp;")) {
            let curNo = parseOrder(curP)
            let mapNode = utils.MyDocMap.get(curNo)

            // console.log(curP, " - ", curP.innerHTML, curP.innerHTML.startsWith("# "))
            if (curP.innerHTML.startsWith("#&nbsp;") || curP.innerHTML.startsWith("# ")) {
                mapNode.getStyle().setNodeType("h1")
                becomeAnotherElement(curP, "h1", onkeydownHandle)
            } else if (curP.innerHTML.startsWith("##&nbsp;")) {
                mapNode.getStyle().setNodeType("h2")
                becomeAnotherElement(curP, "h2", onkeydownHandle)
            } else if (curP.innerHTML.startsWith("###&nbsp;")) {
                mapNode.getStyle().setNodeType("h3")
                becomeAnotherElement(curP, "h3", onkeydownHandle)
            } else if (curP.innerHTML.startsWith("####&nbsp;")) {
                mapNode.getStyle().setNodeType("h4")
                becomeAnotherElement(curP, "h4", onkeydownHandle)
            } else if (curP.innerHTML.startsWith("#####&nbsp;")) {
                mapNode.getStyle().setNodeType("h5")
                becomeAnotherElement(curP, "h5", onkeydownHandle)
            } else {
                mapNode.getStyle().setNodeType("h6")
                becomeAnotherElement(curP, "h6", onkeydownHandle)
            }
        }

        /**
         * 无序列表效果
         */
        if (inputLength === 2 && curP.innerText.startsWith("-") && curP.innerHTML.endsWith("&nbsp;")) {
            let curNo = parseOrder(curP)
            let mapNode = utils.MyDocMap.get(curNo)
            mapNode.getStyle().setPreStyle("ul", true)

            //clean
            curP.innerHTML = ""
            mapNode.setSource("")

            //根据上一层级元素动态选择 todo
            curP.setAttribute("style", "padding-left: 1rem;")
            //新增元素
            newParagraph = document.createElement("span");
            newParagraph.setAttribute("contenteditable", "false")
            //∙ vs ∘ 
            newParagraph.innerHTML = "∙ &nbsp;"
            curP.append(newParagraph)

            //添加一个选区
            var selObj = window.getSelection()
            var rangeObj = document.createRange()
            rangeObj.selectNode(curP)
            selObj.addRange(rangeObj)

            //收起选区到一个点,光标落在一个可编辑元素上
            window.getSelection().collapse(curP, true)
        }

        /**
         * 有序列表效果
         */
        if (inputLength > 2 && inputLength <= 5 && isNum(curP.innerText.substring(0, inputLength - 2)) && curP.innerHTML.endsWith(".&nbsp;")) {
            let num = curP.innerText.substring(0, inputLength - 2)
            console.log(curP.innerText, num)

            let curNo = parseOrder(curP)
            let mapNode = utils.MyDocMap.get(curNo)
            mapNode.getStyle().setPreStyle("ol", num)

            //clean
            curP.innerHTML = ""
            mapNode.setSource("")
            //todo
            curP.setAttribute("style", "padding-left: 1rem;")
            //新增元素
            newParagraph = document.createElement("span");
            newParagraph.setAttribute("contenteditable", "false")
            newParagraph.innerHTML = num + ".&nbsp;"
            curP.append(newParagraph)

            //添加一个选区
            var selObj = window.getSelection()
            var rangeObj = document.createRange()
            rangeObj.selectNode(curP)
            selObj.addRange(rangeObj)

            //收起选区到一个点,光标落在一个可编辑元素上
            window.getSelection().collapse(curP, true)
        }

    }

    /**
     * 变成另一个元素
     * @param {*} curP
     * @param {*} elementName
     */
    function becomeAnotherElement(curP, elementName, onkeydownHandle) {
        var newParagraph = document.createElement(elementName)
        newParagraph.setAttribute("contenteditable", "true")
        newParagraph.setAttribute("data-id", curP.getAttribute("data-id"))
        newParagraph.setAttribute("id", curP.getAttribute("data-id"))
        newParagraph.setAttribute("data-order", curP.getAttribute("data-order"))
        newParagraph.onkeydown = onkeydownHandle

        //todo 支持 有数据的行 在行首输入 #
        // if()
        // switch (elementName){
        //     case "h1":
        // }
        newParagraph.innerHTML = "<br>"

        insertAfter(newParagraph, curP)
        curP.remove()

        //matData
        let curNo = parseOrder(curP)
        let mapNode = utils.MyDocMap.get(curNo)
        mapNode.setSource("")

        //收起选区到一个点,光标落在一个可编辑元素上
        window.getSelection().setPosition(newParagraph, 0)
    }

    function parseStyleName2ClassName(styleName) {
        switch (styleName) {
            case "b":
                return "childStyleStrong";
            case "i":
                return "childStyleI";
            case "u":
                return "childStyleU";
            case "c_red":
                return "childStyleColor";
            case "del":
                return "childStyleDel"
        }
    }

    function syncOnePInfo(p) {
        //子元素为空不处理
        if (p.children.length <= 0) {
            return
        }
        // let id = p.getAttribute("id");
        let order = parseInt(p.getAttribute("data-order"));
        let curMapData = this.MyDocMap.get(order);
        //清空重置
        curMapData.getStyle().setChildrenStyleMapNull();
        for (let i = 0; i < p.children.length; i++) {
            let curItem = p.children[i];
            let tmpClassList = curItem.classList;
            if (tmpClassList != null && tmpClassList.length > 0) {
                curMapData.getStyle().setChildrenStyle(i, tmpClassList);
            }
        }

        console.log("curPEle : ", p, " children: ", p.children, " childrenMap: ", curMapData.getStyle().getChildrenStyleMap())
    }


    window.utils = {
        isNum,
        uuid,
        parseOrder,
        getSelection,
        insertAfter,
        firstCmd,
        becomeAnotherElement,
        parseStyleName2ClassName,
        syncOnePInfo,

        latestOpDoc,
        num,
        inCompositionEvent,
        MyDocMap,
        MyRoot,

        MyNode,
        InnerStyle,
        MyKV,
        MyQueue,
        MyRecovery,
    }

})()