"use strict";
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
const util = require("../core/util.js");
const core = require("./core.js");
const domapi = require("./domapi.js");
var colonChar = 58;
var xChar = 120;
var emptyNode = core.createVNode("", "");
function isUndef(s) {
  return s === void 0;
}
function isDef(s) {
  return s !== void 0;
}
function createKeyToOldIdx(children, beginIdx, endIdx) {
  var map = {};
  for (var i = beginIdx; i <= endIdx; ++i) {
    var key = children[i].key;
    if (key !== void 0) {
      if (process.env.NODE_ENV !== "production") {
        if (map[key] != null) {
          console.error("Duplicate key " + key);
        }
      }
      map[key] = i;
    }
  }
  return map;
}
function sameVnode(vnode1, vnode2) {
  var isSameKey = vnode1.key === vnode2.key;
  var isSameTag = vnode1.tag === vnode2.tag;
  return isSameTag && isSameKey;
}
function createElm(vnode) {
  var i;
  var children = vnode.children;
  var tag = vnode.tag;
  if (isDef(tag)) {
    var elm = vnode.elm = core.createElement(tag);
    updateAttrs(emptyNode, vnode);
    if (util.isArray(children)) {
      for (i = 0; i < children.length; ++i) {
        var ch = children[i];
        if (ch != null) {
          domapi.appendChild(elm, createElm(ch));
        }
      }
    } else if (isDef(vnode.text) && !util.isObject(vnode.text)) {
      domapi.appendChild(elm, domapi.createTextNode(vnode.text));
    }
  } else {
    vnode.elm = domapi.createTextNode(vnode.text);
  }
  return vnode.elm;
}
function addVnodes(parentElm, before, vnodes, startIdx, endIdx) {
  for (; startIdx <= endIdx; ++startIdx) {
    var ch = vnodes[startIdx];
    if (ch != null) {
      domapi.insertBefore(parentElm, createElm(ch), before);
    }
  }
}
function removeVnodes(parentElm, vnodes, startIdx, endIdx) {
  for (; startIdx <= endIdx; ++startIdx) {
    var ch = vnodes[startIdx];
    if (ch != null) {
      if (isDef(ch.tag)) {
        var parent_1 = domapi.parentNode(ch.elm);
        domapi.removeChild(parent_1, ch.elm);
      } else {
        domapi.removeChild(parentElm, ch.elm);
      }
    }
  }
}
function updateAttrs(oldVnode, vnode) {
  var key;
  var elm = vnode.elm;
  var oldAttrs = oldVnode && oldVnode.attrs || {};
  var attrs = vnode.attrs || {};
  if (oldAttrs === attrs) {
    return;
  }
  for (key in attrs) {
    var cur = attrs[key];
    var old = oldAttrs[key];
    if (old !== cur) {
      if (cur === true) {
        elm.setAttribute(key, "");
      } else if (cur === false) {
        elm.removeAttribute(key);
      } else {
        if (key.charCodeAt(0) !== xChar) {
          elm.setAttribute(key, cur);
        } else if (key === "xmlns:xlink" || key === "xmlns") {
          elm.setAttributeNS(core.XMLNS, key, cur);
        } else if (key.charCodeAt(3) === colonChar) {
          elm.setAttributeNS(core.XML_NAMESPACE, key, cur);
        } else if (key.charCodeAt(5) === colonChar) {
          elm.setAttributeNS(core.XLINKNS, key, cur);
        } else {
          elm.setAttribute(key, cur);
        }
      }
    }
  }
  for (key in oldAttrs) {
    if (!(key in attrs)) {
      elm.removeAttribute(key);
    }
  }
}
function updateChildren(parentElm, oldCh, newCh) {
  var oldStartIdx = 0;
  var newStartIdx = 0;
  var oldEndIdx = oldCh.length - 1;
  var oldStartVnode = oldCh[0];
  var oldEndVnode = oldCh[oldEndIdx];
  var newEndIdx = newCh.length - 1;
  var newStartVnode = newCh[0];
  var newEndVnode = newCh[newEndIdx];
  var oldKeyToIdx;
  var idxInOld;
  var elmToMove;
  var before;
  while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
    if (oldStartVnode == null) {
      oldStartVnode = oldCh[++oldStartIdx];
    } else if (oldEndVnode == null) {
      oldEndVnode = oldCh[--oldEndIdx];
    } else if (newStartVnode == null) {
      newStartVnode = newCh[++newStartIdx];
    } else if (newEndVnode == null) {
      newEndVnode = newCh[--newEndIdx];
    } else if (sameVnode(oldStartVnode, newStartVnode)) {
      patchVnode(oldStartVnode, newStartVnode);
      oldStartVnode = oldCh[++oldStartIdx];
      newStartVnode = newCh[++newStartIdx];
    } else if (sameVnode(oldEndVnode, newEndVnode)) {
      patchVnode(oldEndVnode, newEndVnode);
      oldEndVnode = oldCh[--oldEndIdx];
      newEndVnode = newCh[--newEndIdx];
    } else if (sameVnode(oldStartVnode, newEndVnode)) {
      patchVnode(oldStartVnode, newEndVnode);
      domapi.insertBefore(parentElm, oldStartVnode.elm, domapi.nextSibling(oldEndVnode.elm));
      oldStartVnode = oldCh[++oldStartIdx];
      newEndVnode = newCh[--newEndIdx];
    } else if (sameVnode(oldEndVnode, newStartVnode)) {
      patchVnode(oldEndVnode, newStartVnode);
      domapi.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);
      oldEndVnode = oldCh[--oldEndIdx];
      newStartVnode = newCh[++newStartIdx];
    } else {
      if (isUndef(oldKeyToIdx)) {
        oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx);
      }
      idxInOld = oldKeyToIdx[newStartVnode.key];
      if (isUndef(idxInOld)) {
        domapi.insertBefore(parentElm, createElm(newStartVnode), oldStartVnode.elm);
      } else {
        elmToMove = oldCh[idxInOld];
        if (elmToMove.tag !== newStartVnode.tag) {
          domapi.insertBefore(parentElm, createElm(newStartVnode), oldStartVnode.elm);
        } else {
          patchVnode(elmToMove, newStartVnode);
          oldCh[idxInOld] = void 0;
          domapi.insertBefore(parentElm, elmToMove.elm, oldStartVnode.elm);
        }
      }
      newStartVnode = newCh[++newStartIdx];
    }
  }
  if (oldStartIdx <= oldEndIdx || newStartIdx <= newEndIdx) {
    if (oldStartIdx > oldEndIdx) {
      before = newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].elm;
      addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx);
    } else {
      removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
    }
  }
}
function patchVnode(oldVnode, vnode) {
  var elm = vnode.elm = oldVnode.elm;
  var oldCh = oldVnode.children;
  var ch = vnode.children;
  if (oldVnode === vnode) {
    return;
  }
  updateAttrs(oldVnode, vnode);
  if (isUndef(vnode.text)) {
    if (isDef(oldCh) && isDef(ch)) {
      if (oldCh !== ch) {
        updateChildren(elm, oldCh, ch);
      }
    } else if (isDef(ch)) {
      if (isDef(oldVnode.text)) {
        domapi.setTextContent(elm, "");
      }
      addVnodes(elm, null, ch, 0, ch.length - 1);
    } else if (isDef(oldCh)) {
      removeVnodes(elm, oldCh, 0, oldCh.length - 1);
    } else if (isDef(oldVnode.text)) {
      domapi.setTextContent(elm, "");
    }
  } else if (oldVnode.text !== vnode.text) {
    if (isDef(oldCh)) {
      removeVnodes(elm, oldCh, 0, oldCh.length - 1);
    }
    domapi.setTextContent(elm, vnode.text);
  }
}
function patch(oldVnode, vnode) {
  if (sameVnode(oldVnode, vnode)) {
    patchVnode(oldVnode, vnode);
  } else {
    var elm = oldVnode.elm;
    var parent_2 = domapi.parentNode(elm);
    createElm(vnode);
    if (parent_2 !== null) {
      domapi.insertBefore(parent_2, vnode.elm, domapi.nextSibling(elm));
      removeVnodes(parent_2, [oldVnode], 0, 0);
    }
  }
  return vnode;
}
exports.default = patch;
exports.updateAttrs = updateAttrs;
