//

class Modifier {

modify() {
  console.info("[Zotica] Start");
  let startDate = new Date();
  let elements = [];
  elements.push(...document.querySelectorAll("math-subsup"));
  elements.push(...document.querySelectorAll("math-underover"));
  elements.push(...document.querySelectorAll("math-rad.mod"));
  elements.push(...document.querySelectorAll("math-fence.mod"));
  elements.push(...document.querySelectorAll("math-diagram"));
  elements.push(...document.querySelectorAll("math-step"));
  elements = elements.sort((first, second) => {
    return this.getDepth(second) - this.getDepth(first);
  });
  elements.forEach((element) => {
    let name = element.localName;
    if (name == "math-subsup") {
      SubsuperModifier.execute(element);
    } else if (name == "math-underover") {
      UnderoverModifier.execute(element);
      if (element.classList.contains("wid") && element.classList.contains("mod")) {
        WideModifier.execute(element);
      }
    } else if (name == "math-rad") {
      RadicalModifier.execute(element);
    } else if (name == "math-fence") {
      FenceModifier.execute(element);
    } else if (name == "math-diagram") {
      DiagramModifier.execute(element);
    } else if (name == "math-step") {
      TreeModifier.execute(element);
    }
  });
  let finishDate = new Date();
  let elapsedTime = ((finishDate - startDate) / 1000).toFixed(4);
  console.info("[Zotica] Finish (" + elements.length + " elements, " + elapsedTime + " seconds)");
}
modifyDebug() {
  document.querySelectorAll("debug").forEach((element) => {
    let modifier = new Modifier();
    modifier.renderDebug(element);
  });
}
getFontSize(element) {
  let fontSizeString = window.getComputedStyle(element).fontSize;
  let fontSize = parseFloat(fontSizeString);
  return fontSize;
}
getWidthPx(element) {
  let width = element.getBoundingClientRect().width;
  return width;
}
getWidth(element, fontElement) {
  let width = this.getWidthPx(element) / this.getFontSize(fontElement || element);
  return width;
}
getHeightPx(element) {
  let height = element.getBoundingClientRect().height;
  return height;
}
getHeight(element, fontElement) {
  let height = this.getHeightPx(element) / this.getFontSize(fontElement || element);
  return height;
}
getLowerHeightPx(element) {
  let bottom = element.getBoundingClientRect().bottom + window.pageYOffset;
  let locator = document.createElement("math-sys-locator");
  element.appendChild(locator);
  locator.style.verticalAlign = "baseline";
  let baselineBottom = locator.getBoundingClientRect().bottom + window.pageYOffset;
  let height = bottom - baselineBottom + this.getFontSize(element) * 0.3;
  element.removeChild(locator);
  return height;
}
getLowerHeight(element, fontElement) {
  let height = this.getLowerHeightPx(element) / this.getFontSize(fontElement || element);
  return height;
}
getUpperHeightPx(element) {
  let height = this.getHeightPx(element) - this.getLowerHeightPx(element);
  return height;
}
getUpperHeight(element, fontElement) {
  let height = this.getHeight(element, fontElement) - this.getLowerHeight(element, fontElement);
  return height;
}
getOffsetLeft(element, fontElement) {
  let offset = element.offsetLeft / this.getFontSize(fontElement || element);
  return offset;
}
getOffsetRight(element, fontElement) {
  let offset = (element.offsetParent.offsetWidth - element.offsetLeft - element.offsetWidth) / this.getFontSize(fontElement || element);
  return offset;
}
getDepth(element) {
  let depth = 0;
  if (element.zoticaDepth != undefined) {
    depth = element.zoticaDepth;
  } else {
    let parent = element.parentNode;
    if (parent) {
      depth = this.getDepth(parent) + 1;
    } else {
      depth = 0;
    }
  }
  element.zoticaDepth = depth;
  return depth;
}  
findChild(element, name) {
  return Array.from(element.children).find((child) => child.localName == name);
}
findChildren(element, name) {
  return Array.from(element.children).filter((child) => child.localName == name);
}
renderDebug(element) {
  let clientRect = element.getBoundingClientRect();
  let scrollOffset = window.pageYOffset;
  let lowerHeight = this.getLowerHeightPx(element);
  let upperHeight = this.getUpperHeightPx(element);
  let line = document.createElement("div");
  let upperBox = document.createElement("div");
  let lowerBox = document.createElement("div");
  line.style.position = "absolute";
  line.style.borderTop = "1px #FF000088 solid";
  line.style.width = "" + clientRect.width + "px";
  line.style.height = "1px";
  line.style.top = "" + (clientRect.bottom - lowerHeight + scrollOffset) + "px";
  line.style.left = "" + clientRect.left + "px";
  lowerBox.style.position = "absolute";
  lowerBox.style.backgroundColor = "#FFFF0033";
  lowerBox.style.width = "" + clientRect.width + "px";
  lowerBox.style.height = "" + lowerHeight + "px";
  lowerBox.style.top = "" + (clientRect.top + upperHeight + scrollOffset) + "px";
  lowerBox.style.left = "" + clientRect.left + "px";
  upperBox.style.position = "absolute";
  upperBox.style.backgroundColor = "#FF000033";
  upperBox.style.width = "" + clientRect.width + "px";
  upperBox.style.height = "" + upperHeight + "px";
  upperBox.style.top = "" + (clientRect.top + scrollOffset) + "px";
  upperBox.style.left = "" + clientRect.left + "px";
  document.body.appendChild(line);
  document.body.appendChild(lowerBox);
  document.body.appendChild(upperBox);
}
static execute(element) {
  let modifier = new this();
  modifier.modify(element);
}

}