console.info(
  `%c COMPACT-CUSTOM-HEADER \n%c     Version 1.4.9     `,
  "color: orange; font-weight: bold; background: black",
  "color: white; font-weight: bold; background: dimgray"
);
class CompactCustomHeader {
  constructor() {
    this.LitElement = Object.getPrototypeOf(
      customElements.get("ha-panel-lovelace")
    );
    this.hass = document.querySelector("home-assistant").hass;
    this.fireEvent = (node, type, detail, options = {}) => {
      detail = detail === null || detail === undefined ? {} : detail;
      const event = new Event(type, {
        bubbles: options.bubbles === undefined ? true : options.bubbles,
        cancelable: Boolean(options.cancelable),
        composed: options.composed === undefined ? true : options.composed
      });
      event.detail = detail;
      node.dispatchEvent(event);
      return event;
    };
    let ll = document.querySelector("home-assistant");
    ll = ll && ll.shadowRoot;
    ll = ll && ll.querySelector("home-assistant-main");
    this.main = ll;
    ll = ll && ll.shadowRoot;
    ll = ll && ll.querySelector("app-drawer-layout partial-panel-resolver");
    this.panelResolver = ll;
    ll = (ll && ll.shadowRoot) || ll;
    ll = ll && ll.querySelector("ha-panel-lovelace");
    ll = ll && ll.shadowRoot;
    ll = ll && ll.querySelector("hui-root");
    this.lovelace = ll.lovelace;
    this.root = ll.shadowRoot;
    this.frontendVersion = Number(window.frontendVersion);
    this.newSidebar = this.frontendVersion >= 20190710;
    this.header = this.root.querySelector("app-header");
    this.editMode = this.header.className == "edit-mode";
    this.view = this.root.querySelector("ha-app-layout #view");
    this.sidebarClosed = false;
    this.firstRun = true;
    this.buttons = {};
    this.prevColor = {};
    this.defaultConfig = {
      header: true,
      disable: false,
      yaml_editor: false,
      menu: "show",
      voice: "show",
      notifications: "show",
      options: "show",
      clock_format: 12,
      clock_am_pm: true,
      clock_date: false,
      date_locale: this.hass.language,
      chevrons: false,
      redirect: true,
      background: "",
      hide_tabs: "",
      show_tabs: "",
      edit_mode_show_tabs: false,
      default_tab: "",
      default_tab_template: "",
      kiosk_mode: false,
      sidebar_swipe: true,
      sidebar_closed: false,
      disable_sidebar: false,
      hide_help: false,
      hide_config: false,
      hide_unused: false,
      tab_color: {},
      button_color: {},
      statusbar_color: "",
      swipe: false,
      swipe_amount: "15",
      swipe_animate: "none",
      swipe_skip: "",
      swipe_wrap: true,
      swipe_prevent_default: false,
      swipe_skip_hidden: true,
      warning: true,
      compact_header: true,
      view_css: "",
      time_css: "",
      date_css: "",
      header_css: "",
      tab_css: {},
      button_css: {}
    };
    this.cchConfig = this.buildConfig(
      this.lovelace.config.cch || {},
      this.hass.user.name
    );
  }
  run() {
    const tabContainer = this.root.querySelector("paper-tabs");
    const tabs = tabContainer
      ? Array.from(tabContainer.querySelectorAll("paper-tab"))
      : [];
    let disabled =
      window.location.href.includes("disable_cch") || this.cchConfig.disable;
    if (this.firstRun || this.buttons == undefined) {
      this.buttons = this.getButtonElements(tabContainer);
    }
    if (!this.buttons.menu || !this.buttons.options || this.editMode) return;
    if (!disabled) {
      this.insertEditMenu(tabs);
      this.hideMenuItems();
      this.styleHeader(tabContainer, tabs);
      this.styleButtons(tabs, tabContainer);
      if (this.firstRun) this.sidebarMod();
      this.hideTabs(tabContainer, tabs);
      for (let button in this.buttons) {
        if (this.cchConfig[button] == "clock") this.insertClock(button);
      }
      if (!this.editMode) this.tabContainerMargin(tabContainer);
      if (this.cchConfig.swipe) this.swipeNavigation(tabs, tabContainer);
      if (this.firstRun) this.defaultTab(tabs, tabContainer);
    }
    if (this.firstRun) {
      this.observers(tabContainer, tabs, disabled);
      this.breakingChangeNotification();
    }
    this.firstRun = false;
    this.fireEvent(this.header, "iron-resize");
  }
  buildConfig(config, user_name) {
    let exceptionConfig = {};
    let highestMatch = 0;
    // Count number of matching conditions and choose config with most matches.
    if (config.exceptions) {
      config.exceptions.forEach(exception => {
        const matches = countMatches(exception.conditions, user_name);
        if (matches > highestMatch) {
          highestMatch = matches;
          exceptionConfig = exception.config;
        }
      });
    }
    // If exception config uses hide_tabs and main config uses show_tabs,
    // delete show_tabs and vice versa.
    if (
      exceptionConfig.hide_tabs &&
      config.show_tabs &&
      exceptionConfig.hide_tabs.length &&
      config.show_tabs.length
    ) {
      delete config.show_tabs;
    } else if (
      exceptionConfig.show_tabs &&
      config.hide_tabs &&
      exceptionConfig.show_tabs.length &&
      config.hide_tabs.length
    ) {
      delete config.hide_tabs;
    }
    return { ...this.defaultConfig, ...config, ...exceptionConfig };
    function countMatches(conditions, user_name) {
      const userVars = {
        user: user_name,
        user_agent: navigator.userAgent
      };
      let count = 0;
      for (const cond in conditions) {
        if (cond == "user" && conditions[cond].includes(",")) {
          conditions[cond].split(/[ ,]+/).forEach(user => {
            if (userVars[cond] == user) count++;
          });
        } else {
          if (
            userVars[cond] == conditions[cond] ||
            (cond == "query_string" &&
              window.location.search.includes(conditions[cond])) ||
            (cond == "user_agent" &&
              userVars[cond].includes(conditions[cond])) ||
            (cond == "media_query" &&
              window.matchMedia(conditions[cond]).matches)
          ) {
            count++;
          } else {
            return 0;
          }
        }
      }
      return count;
    }
  }
  observers(tabContainer, tabs, disabled) {
    // Watch for changes in Lovelace.
    const callback = mutations => {
      // Theme changed.
      if (mutations[0].target.nodeName == "HTML") {
        mutations = [mutations[0]];
        this.styleHeader(tabContainer, tabs);
        this.conditionalStyling(tabs);
        return;
      }
      mutations.forEach(({ addedNodes, target }) => {
        if (addedNodes.length && target.nodeName == "PARTIAL-PANEL-RESOLVER") {
          // Navigated back to lovelace from elsewhere in HA.
          this.buttons = this.getButtonElements();
          this.run();
        } else if (target.className == "edit-mode" && addedNodes.length) {
          // Entered edit mode.
          this.editMode = true;
          if (!disabled) this.removeStyles(tabContainer, tabs, this.header);
          this.buttons.options = this.root.querySelector("paper-menu-button");
          this.insertEditMenu(tabs);
          this.fireEvent(this.header, "iron-resize");
        } else if (target.nodeName == "APP-HEADER" && addedNodes.length) {
          // Exited edit mode.
          let editor = this.root
            .querySelector("ha-app-layout")
            .querySelector("editor");
          if (editor) {
            this.root.querySelector("ha-app-layout").removeChild(editor);
          }
          for (let node of addedNodes) {
            if (node.nodeName == "APP-TOOLBAR") {
              this.editMode = false;
              this.buttons = this.getButtonElements();
              this.root.querySelectorAll("[id^='cch']").forEach(style => {
                style.remove();
              });
              setTimeout(() => {
                this.run();
                if (!disabled) this.conditionalStyling(tabs, this.header);
              }, 100);
            }
          }
        } else if (
          // Viewing unused entities
          this.frontendVersion < 20190911 &&
          addedNodes.length &&
          !addedNodes[0].nodeName == "HUI-UNUSED-ENTITIES"
        ) {
          let editor = this.root
            .querySelector("ha-app-layout")
            .querySelector("editor");
          if (editor) {
            this.root.querySelector("ha-app-layout").removeChild(editor);
          }
          if (this.cchConfig.conditional_styles) {
            this.buttons = this.getButtonElements(tabContainer);
            this.conditionalStyling(tabs, this.header);
          }
        } else if (target.id == "view" && addedNodes.length) {
          // Navigating to new tab/view.
          this.run();
          if (tabContainer) this.scrollTabIconIntoView();
        }
      });
    };
    let observer = new MutationObserver(callback);
    observer.observe(this.panelResolver, { childList: true });
    observer.observe(document.querySelector("html"), { attributes: true });
    observer.observe(this.view, { childList: true });
    observer.observe(this.root.querySelector("app-header"), {
      childList: true
    });
    if (!disabled) {
      // Watch for changes in entities.
      window.hassConnection.then(({ conn }) => {
        conn.socket.onmessage = () => {
          if (this.cchConfig.conditional_styles && !this.editMode) {
            this.conditionalStyling(tabs, this.header);
          }
        };
      });
    }
  }
  getButtonElements(disabled) {
    let buttons = {};
    buttons.options = this.root.querySelector("paper-menu-button");
    if (!this.editMode) {
      buttons.menu = this.root.querySelector("ha-menu-button");
      buttons.voice =
        this.root.querySelector("ha-start-voice-button") ||
        this.root.querySelector('[icon="hass:microphone"]');
      if (!this.newSidebar) {
        buttons.notifications = this.root.querySelector(
          "hui-notifications-button"
        );
      }
    }
    // Remove space taken up by "hidden" menu button anytime we get buttons.
    if (
      buttons.menu &&
      buttons.menu.style.visibility == "hidden" &&
      !disabled
    ) {
      buttons.menu.style.display = "none";
    } else if (buttons.menu) {
      buttons.menu.style.display = "";
    }
    return buttons;
  }
  tabContainerMargin(tabContainer) {
    let marginRight = 0;
    let marginLeft = 15;
    for (const button in this.buttons) {
      if (!this.buttons[button]) continue;
      let paperIconButton =
        this.buttons[button].querySelector("paper-icon-button") ||
        this.buttons[button].shadowRoot.querySelector("paper-icon-button");
      let visible = paperIconButton
        ? this.buttons[button].style.display !== "none" &&
          !paperIconButton.hasAttribute("hidden")
        : this.buttons[button].style.display !== "none";
      if (this.cchConfig[button] == "show" && visible) {
        if (button == "menu") marginLeft += 45;
        else marginRight += 45;
      } else if (this.cchConfig[button] == "clock" && visible) {
        const clockWidth =
          (this.cchConfig.clock_format == 12 && this.cchConfig.clock_am_pm) ||
          this.cchConfig.clock_date
            ? 110
            : 80;
        if (button == "menu") marginLeft += clockWidth + 15;
        else marginRight += clockWidth;
      }
    }
    if (tabContainer) {
      tabContainer.style.marginRight = `${marginRight}px`;
      tabContainer.style.marginLeft = `${marginLeft}px`;
    }
  }
  scrollTabIconIntoView() {
    let paperTabs = this.root.querySelector("paper-tabs");
    let currentTab = paperTabs.querySelector(".iron-selected");
    if (!paperTabs || !currentTab) return;
    let tab = currentTab.getBoundingClientRect();
    let container = paperTabs.shadowRoot
      .querySelector("#tabsContainer")
      .getBoundingClientRect();
    // If tab's icon isn't in view scroll it in.
    if (container.right < tab.right || container.left > tab.left) {
      if ("scrollMarginInline" in document.documentElement.style) {
        currentTab.scrollIntoView({ inline: "center" });
      } else if (Element.prototype.scrollIntoViewIfNeeded) {
        currentTab.scrollIntoViewIfNeeded(true);
      } else {
        currentTab.scrollIntoView();
      }
    }
  }
  hideMenuItems() {
    // Hide items in options menu.
    if (
      this.cchConfig.hide_help ||
      this.cchConfig.hide_config ||
      this.cchConfig.hide_unused
    ) {
      const localized = (item, string) => {
        let localString = this.hass.localize(
          `ui.panel.lovelace.menu.${string}`
        );
        return (
          item.innerHTML.includes(localString) ||
          item.getAttribute("aria-label") == localString
        );
      };
      this.buttons.options
        .querySelector("paper-listbox")
        .querySelectorAll("paper-item")
        .forEach(item => {
          if (
            (this.cchConfig.hide_help && localized(item, "help")) ||
            (this.cchConfig.hide_unused &&
              localized(item, "unused_entities")) ||
            (this.cchConfig.hide_config && localized(item, "configure_ui"))
          ) {
            item.parentNode.removeChild(item);
          }
        });
    }
  }
  insertEditMenu(tabs, disabled) {
    if (
      this.buttons.options &&
      (this.editMode ||
        (this.lovelace.mode == "yaml" && this.cchConfig.yaml_editor))
    ) {
      // If any tabs are hidden, add "show all tabs" option.
      if (this.cchConfig.hide_tabs && !this.cchConfig.edit_mode_show_tabs) {
        let show_tabs = document.createElement("paper-item");
        show_tabs.setAttribute("id", "show_tabs");
        show_tabs.addEventListener("click", () => {
          for (let i = 0; i < tabs.length; i++) {
            tabs[i].style.removeProperty("display");
          }
        });
        show_tabs.innerHTML = "Show all tabs";
        this.insertMenuItem(
          this.buttons.options.querySelector("paper-listbox"),
          show_tabs
        );
      }
      // Add menu item to open CCH settings.
      let cchSettings = document.createElement("paper-item");
      cchSettings.setAttribute("id", "cch_settings");
      cchSettings.addEventListener("click", () => this.showEditor());
      cchSettings.innerHTML = "CCH Settings";
      this.insertMenuItem(
        this.buttons.options.querySelector("paper-listbox"),
        cchSettings
      );
      if (!disabled) this.hideMenuItems();
    }
  }
  removeStyles(tabContainer, tabs, { style }) {
    this.root.querySelector("app-header").style.backgroundColor = "#455a64";
    this.root.querySelectorAll("[id^='cch']").forEach(style => {
      style.remove();
    });
    if (this.cchConfig.tab_css) {
      for (let [key, value] of Object.entries(this.cchConfig.tab_css)) {
        key = this.getViewIndex(key);
        value = value.replace(/: /g, ":").replace(/; /g, ";");
        let css = tabs[key].style.cssText
          .replace(/: /g, ":")
          .replace(/; /g, ";");
        tabs[key].style.cssText = css.replace(value, "");
      }
    }
    if (this.cchConfig.header_css) {
      let value = this.cchConfig.header_css
        .replace(/: /g, ":")
        .replace(/; /g, ";");
      let css = style.cssText.replace(/: /g, ":").replace(/; /g, ";");
      style.cssText = css.replace(value, "");
    }
    if (tabContainer) {
      tabContainer.style.marginLeft = "";
      tabContainer.style.marginRight = "";
    }
    this.view.style = "";
    for (let i = 0; i < tabs.length; i++) {
      tabs[i].style.color = "";
    }
    if (this.cchConfig.edit_mode_show_tabs) {
      for (let i = 0; i < tabs.length; i++) {
        tabs[i].style.removeProperty("display");
      }
    }
    let viewStyle = document.createElement("style");
    viewStyle.setAttribute("id", "cch_view_styling");
    viewStyle.innerHTML = `
    hui-view {
      min-height: 100vh;
    }
    hui-panel-view {
      min-height: calc(100vh - 52px);
    }
    `;
    this.root.appendChild(viewStyle);
  }
  styleHeader(tabContainer, tabs) {
    // Fix for old background config option.
    if (typeof this.cchConfig.background == "boolean") {
      this.cchConfig.background = "";
    }
    this.prevColor.background =
      this.cchConfig.background ||
      getComputedStyle(document.body).getPropertyValue("--cch-background") ||
      getComputedStyle(document.body).getPropertyValue("--primary-color");
    let statusBarColor =
      this.cchConfig.statusbar_color || this.prevColor.background;
    // Match mobile status bar color to header color.
    let themeColor = document.querySelector('[name="theme-color"]');
    let themeColorApple =
      document.querySelector(
        '[name="apple-mobile-web-app-status-bar-style"]'
      ) || document.createElement("meta");
    colorStatusBar(statusBarColor);
    // If browser is idle or in background sometimes theme-color needs reset.
    let observeStatus = new MutationObserver(() => {
      if (themeColor.content != statusBarColor) colorStatusBar(statusBarColor);
    });
    if (this.firstRun) {
      observeStatus.observe(themeColor, {
        attributes: true,
        attributeFilter: ["content"]
      });
    }
    // Adjust view size & padding for new header size.
    if (!this.cchConfig.header || this.cchConfig.kiosk_mode) {
      this.header.style.display = "none";
      this.view.style.minHeight = "100vh";
      if (
        this.frontendVersion >= 20190911 &&
        !this.root.querySelector("#cch_view_styling")
      ) {
        let viewStyle = document.createElement("style");
        viewStyle.setAttribute("id", "cch_view_styling");
        viewStyle.innerHTML = `
        hui-view {
          ${this.cchConfig.view_css ? this.cchConfig.view_css : ""}
        }
        hui-panel-view {
          ${this.cchConfig.view_css ? this.cchConfig.view_css : ""}
        }
        `;
        this.root.appendChild(viewStyle);
      }
    } else {
      this.view.style.minHeight = "100vh";
      this.view.style.marginTop = "-48.5px";
      this.view.style.paddingTop = "48.5px";
      this.view.style.boxSizing = "border-box";
      this.header.style.background = this.prevColor.background;
      this.conditionalStyling(tabs, this.header);
      this.header.querySelector("app-toolbar").style.background = "transparent";
      if (
        this.frontendVersion >= 20190911 &&
        !this.root.querySelector("#cch_view_styling")
      ) {
        let viewStyle = document.createElement("style");
        viewStyle.setAttribute("id", "cch_view_styling");
        viewStyle.innerHTML = `
        hui-view {
          margin-top: -48.5px;
          padding-top: 52px;
          min-height: 100vh;
          ${this.cchConfig.view_css ? this.cchConfig.view_css : ""}
        }
        hui-panel-view {
          margin-top: -52px;
          padding-top: 52px;
          min-height: calc(100vh - 52px);
          ${this.cchConfig.view_css ? this.cchConfig.view_css : ""}
        }
        `;
        this.root.appendChild(viewStyle);
      }
    }
    // Match sidebar elements to header's size.
    if (this.newSidebar && this.cchConfig.compact_header) {
      let sidebar = this.main.shadowRoot.querySelector("ha-sidebar").shadowRoot;
      sidebar.querySelector(".menu").style = "height:49px;";
      sidebar.querySelector("paper-listbox").style =
        "height:calc(100% - 180px);";
    }
    // Current tab icon color.
    let conditionalTabs = this.cchConfig.conditional_styles
      ? JSON.stringify(this.cchConfig.conditional_styles).includes("tab")
      : false;
    if (
      !this.root.querySelector("#cch_iron_selected") &&
      !this.editMode &&
      !conditionalTabs &&
      tabContainer
    ) {
      let style = document.createElement("style");
      style.setAttribute("id", "cch_iron_selected");
      style.innerHTML = `
              .iron-selected {
                ${
                  this.cchConfig.active_tab_color
                    ? `color: ${`${
                        this.cchConfig.active_tab_color
                      } !important`}`
                    : "var(--cch-active-tab-color)"
                }
              }
            `;
      tabContainer.appendChild(style);
    }
    // Style current tab indicator.
    let indicator = this.cchConfig.tab_indicator_color;
    if (
      indicator &&
      !this.root.querySelector("#cch_header_colors") &&
      !this.editMode
    ) {
      let style = document.createElement("style");
      style.setAttribute("id", "cch_header_colors");
      style.innerHTML = `
            paper-tabs {
              ${
                indicator
                  ? `--paper-tabs-selection-bar-color: ${indicator} !important`
                  : "var(--cch-tab-indicator-color) !important"
              }
            }
          `;
      this.root.appendChild(style);
    }
    // Tab's icon color.
    let all_tabs_color =
      this.cchConfig.all_tabs_color || "var(--cch-all-tabs-color)";
    if (
      (this.cchConfig.tab_color &&
        Object.keys(this.cchConfig.tab_color).length) ||
      all_tabs_color
    ) {
      for (let i = 0; i < tabs.length; i++) {
        tabs[i].style.color = this.cchConfig.tab_color[i] || all_tabs_color;
      }
    }
    // Add custom css.
    if (this.cchConfig.tab_css) {
      for (let [key, value] of Object.entries(this.cchConfig.tab_css)) {
        key = this.getViewIndex(key);
        if (tabs[key]) tabs[key].style.cssText += value;
      }
    }
    if (this.cchConfig.header_css)
      this.header.style.cssText += this.cchConfig.header_css;
    if (this.cchConfig.view_css && this.frontendVersion < 20190911) {
      this.view.style.cssText += this.cchConfig.view_css;
    }
    if (tabContainer) {
      // Shift the header up to hide unused portion.
      this.root.querySelector("app-toolbar").style.marginTop = this.cchConfig
        .compact_header
        ? "-64px"
        : "";
      tabs.forEach(({ style }) => {
        style.marginTop = "-1px";
      });
      // Show/hide tab navigation chevrons.
      if (!this.cchConfig.chevrons) {
        let chevron = tabContainer.shadowRoot.querySelectorAll(
          '[icon^="paper-tabs:chevron"]'
        );
        chevron[0].style.display = "none";
        chevron[1].style.display = "none";
      } else {
        // Remove space taken up by "not-visible" chevron.
        let style = document.createElement("style");
        style.setAttribute("id", "cch_chevron");
        style.innerHTML = `
              .not-visible {
                display:none;
              }
            `;
        tabContainer.shadowRoot.appendChild(style);
      }
    }
    function colorStatusBar(statusBarColor) {
      themeColor = document.querySelector("meta[name=theme-color]");
      themeColor.setAttribute("content", statusBarColor);
      themeColor.setAttribute("default-content", statusBarColor);
      if (
        !document.querySelector(
          '[name="apple-mobile-web-app-status-bar-style"]'
        )
      ) {
        themeColorApple.name = "apple-mobile-web-app-status-bar-style";
        themeColorApple.content = statusBarColor;
        document.getElementsByTagName("head")[0].appendChild(themeColorApple);
      } else {
        themeColorApple.setAttribute("content", statusBarColor);
      }
    }
  }
  styleButtons({ length }, tabContainer) {
    let topMargin =
      length > 0 && this.cchConfig.compact_header ? "margin-top:111px;" : "";
    let topMarginMenu =
      length > 0 && this.cchConfig.compact_header ? "margin-top:115px;" : "";
    // Reverse buttons object so "menu" is first in the overflow menu.
    this.buttons = this.reverseObject(this.buttons);
    for (const button in this.buttons) {
      if (!this.buttons[button]) continue;
      if (button == "options" && this.cchConfig[button] == "overflow") {
        this.cchConfig[button] = "show";
      }
      let buttonStyle = `
        z-index:1;
        ${
          button == "menu"
            ? `padding: 8px 0; margin-bottom:5px; ${topMarginMenu}`
            : "padding: 8px;"
        }
        ${
          button == "voice" && this.cchConfig["voice"] == "clock"
            ? "width: 100px; padding:4px;"
            : ""
        }
        ${button == "menu" ? "" : topMargin}
        ${button == "options" ? "margin-right:-5px;" : ""}
      `;
      if (
        this.cchConfig[button] == "show" ||
        this.cchConfig[button] == "clock"
      ) {
        if (button == "menu") {
          let paperIconButton = this.buttons[button].querySelector(
            "paper-icon-button"
          )
            ? this.buttons[button].querySelector("paper-icon-button")
            : this.buttons[button].shadowRoot.querySelector(
                "paper-icon-button"
              );
          if (!paperIconButton) continue;
          paperIconButton.style.cssText = buttonStyle;
        } else {
          this.buttons[button].style.cssText = buttonStyle;
        }
      } else if (this.cchConfig[button] == "overflow") {
        const menu_items = this.buttons.options.querySelector("paper-listbox");
        let paperIconButton = this.buttons[button].querySelector(
          "paper-icon-button"
        )
          ? this.buttons[button].querySelector("paper-icon-button")
          : this.buttons[button].shadowRoot.querySelector("paper-icon-button");
        if (paperIconButton && paperIconButton.hasAttribute("hidden")) {
          continue;
        }
        const id = `menu_item_${button}`;
        if (!menu_items.querySelector(`#${id}`)) {
          const wrapper = document.createElement("paper-item");
          wrapper.setAttribute("id", id);
          wrapper.innerText = this.getTranslation(button);
          wrapper.appendChild(this.buttons[button]);
          wrapper.addEventListener("click", () => {
            paperIconButton.click();
          });
          paperIconButton.style.pointerEvents = "none";
          this.insertMenuItem(menu_items, wrapper);
          if (button == "notifications" && !this.newSidebar) {
            let style = document.createElement("style");
            style.innerHTML = `
                  .indicator {
                    top: 5px;
                    right: 0px;
                    width: 10px;
                    height: 10px;
                    ${
                      this.cchConfig.notify_indicator_color
                        ? `background-color:${
                            this.cchConfig.notify_indicator_color
                          }`
                        : ""
                    }
                  }
                  .indicator > div{
                    display:none;
                  }
                `;
            paperIconButton.parentNode.appendChild(style);
          }
        }
      } else if (this.cchConfig[button] == "hide") {
        this.buttons[button].style.display = "none";
      }
      // Hide menu button if hiding the sidebar.
      if (
        this.newSidebar &&
        (this.cchConfig.kiosk_mode || this.cchConfig.disable_sidebar)
      ) {
        this.buttons.menu.style.display = "none";
      }
    }
    // Remove empty space taken up by hidden menu button.
    if (this.buttons.menu && this.newSidebar && this.firstRun) {
      new MutationObserver(() => {
        if (this.buttons.menu.style.visibility == "hidden") {
          this.buttons.menu.style.display = "none";
        } else {
          this.buttons.menu.style.display = "";
        }
        this.tabContainerMargin(tabContainer);
      }).observe(this.buttons.menu, {
        attributes: true,
        attributeFilter: ["style"]
      });
    }
    // Use color vars set in HA theme.
    this.buttons.menu.style.color = "var(--cch-button-color-menu)";
    if (!this.newSidebar) {
      this.buttons.notifications.style.color =
        "var(--cch-button-color-notifications)";
    }
    if (this.buttons.voice) this.buttons.voice.style.color = "var(--cch-button-color-voice)";
    this.buttons.options.style.color = "var(--cch-button-color-options)";
    if (this.cchConfig.all_buttons_color) {
      this.root.querySelector("app-toolbar").style.color =
        this.cchConfig.all_buttons_color || "var(--cch-all-buttons-color)";
    }
    // Use colors set in CCH config.
    for (const button in this.buttons) {
      if (this.cchConfig.button_color[button]) {
        this.buttons[button].style.color = this.cchConfig.button_color[button];
      }
    }
    // Notification indicator's color for HA 0.96 and above.
    if (
      this.newSidebar &&
      this.cchConfig.menu != "hide" &&
      !this.buttons.menu.shadowRoot.querySelector("#cch_dot")
    ) {
      let style = document.createElement("style");
      style.setAttribute("id", "cch_dot");
      let indicator =
        this.cchConfig.notify_indicator_color ||
        getComputedStyle(this.header).getPropertyValue(
          "--cch-tab-indicator-color"
        ) ||
        "";
      let border = getComputedStyle(this.header)
        .getPropertyValue("background")
        .includes("url")
        ? "border-color: transparent !important"
        : `border-color: ${getComputedStyle(this.header).getPropertyValue(
            "background-color"
          )} !important;`;
      style.innerHTML = `
          .dot {
            ${topMargin}
            z-index: 2;
            ${indicator ? `background: ${indicator} !important` : ""}
            ${border}
          }
      `;
      this.buttons.menu.shadowRoot.appendChild(style);
    } else if (
      // Notification indicator's color for HA 0.95 and below.
      this.cchConfig.notify_indicator_color &&
      this.cchConfig.notifications == "show" &&
      !this.newSidebar
    ) {
      let style = document.createElement("style");
      style.innerHTML = `
            .indicator {
              background-color:${this.cchConfig.notify_indicator_color ||
                "var(--cch-notify-indicator-color)"} !important;
              color: ${this.cchConfig.notify_text_color ||
                "var(--cch-notify-text-color), var(--primary-text-color)"};
            }
          `;
      this.buttons.notifications.shadowRoot.appendChild(style);
    }
    // Add buttons's custom css.
    let buttonCss = this.cchConfig.button_css;
    if (buttonCss) {
      for (const [key, value] of Object.entries(buttonCss)) {
        if (!this.buttons[key]) {
          continue;
        } else {
          this.buttons[key].style.cssText += value;
        }
      }
    }
  }
  getTranslation(button) {
    switch (button) {
      case "notifications":
        return this.hass.localize("ui.notification_drawer.title");
      default:
        return button.charAt(0).toUpperCase() + button.slice(1);
    }
  }
  defaultTab(tabs, tabContainer) {
    let firstTab = tabs.indexOf(tabs.filter(tab => tab.style.display == "")[0]);
    let default_tab = this.cchConfig.default_tab;
    if (typeof default_tab == "object" && !default_tab.length) return;
    let template = this.cchConfig.default_tab_template;
    if ((default_tab || template) && tabContainer) {
      if (template) default_tab = this.templateEval(template, this.hass.states);
      default_tab = this.getViewIndex(default_tab);
      let activeTab = tabs.indexOf(
        tabContainer.querySelector(".iron-selected")
      );
      if (
        activeTab != default_tab &&
        activeTab == firstTab &&
        (!this.cchConfig.redirect ||
          (this.cchConfig.redirect &&
            tabs[default_tab].style.display != "none"))
      ) {
        tabs[default_tab].click();
      }
    }
  }
  sidebarMod() {
    let menu = this.buttons.menu.querySelector("paper-icon-button");
    let sidebar = this.main.shadowRoot.querySelector("app-drawer");
    // HA 0.95 and below
    if (!this.newSidebar) {
      if (!this.cchConfig.sidebar_swipe || this.cchConfig.kiosk_mode) {
        sidebar.removeAttribute("swipe-open");
      }
      if (
        (this.cchConfig.sidebar_closed || this.cchConfig.kiosk_mode) &&
        !this.sidebarClosed
      ) {
        if (sidebar.hasAttribute("opened")) menu.click();
        this.sidebarClosed = true;
      }
      // HA 0.96 and above
    } else if (this.cchConfig.disable_sidebar || this.cchConfig.kiosk_mode) {
      sidebar.style.display = "none";
      sidebar.addEventListener(
        "mouseenter",
        event => {
          event.stopPropagation();
        },
        true
      );
      let style = document.createElement("style");
      style.type = "text/css";
      style.appendChild(
        document.createTextNode(
          ":host(:not([expanded])) {width: 0px !important;}"
        )
      );
      this.main.shadowRoot
        .querySelector("ha-sidebar")
        .shadowRoot.appendChild(style);
      style = document.createElement("style");
      style.type = "text/css";
      style.appendChild(
        document.createTextNode(":host {--app-drawer-width: 0px !important;}")
      );
      this.main.shadowRoot.appendChild(style);
    }
  }
  hideTabs(tabContainer, tabs) {
    let hidden_tabs = String(this.cchConfig.hide_tabs).length
      ? String(this.cchConfig.hide_tabs)
          .replace(/\s+/g, "")
          .split(",")
      : null;
    let shown_tabs = String(this.cchConfig.show_tabs).length
      ? String(this.cchConfig.show_tabs)
          .replace(/\s+/g, "")
          .split(",")
      : null;
    // Set the tab config source.
    if (!hidden_tabs && shown_tabs) {
      let all_tabs = [];
      shown_tabs = this.buildRanges(shown_tabs);
      for (let i = 0; i < tabs.length; i++) all_tabs.push(i);
      // Invert shown_tabs to hidden_tabs.
      hidden_tabs = all_tabs.filter(el => !shown_tabs.includes(el));
    } else {
      hidden_tabs = this.buildRanges(hidden_tabs);
    }
    // Hide tabs.
    for (const tab of hidden_tabs) {
      if (!tabs[tab]) continue;
      tabs[tab].style.display = "none";
    }
    if (this.cchConfig.redirect && tabContainer) {
      const activeTab = tabContainer.querySelector("paper-tab.iron-selected");
      const activeTabIndex = tabs.indexOf(activeTab);
      // Is the current tab hidden and is there at least one tab is visible.
      if (
        hidden_tabs.includes(activeTabIndex) &&
        hidden_tabs.length != tabs.length
      ) {
        let i = 0;
        // Find the first visible tab and navigate.
        while (hidden_tabs.includes(i)) {
          i++;
        }
        tabs[i].click();
      }
    }
    return hidden_tabs;
  }
  insertMenuItem(menu_items, element) {
    let first_item = menu_items.querySelector("paper-item");
    if (!menu_items.querySelector(`#${element.id}`)) {
      first_item.parentNode.insertBefore(element, first_item);
    }
  }
  insertClock(button) {
    if (!this.buttons[button]) return;
    const clock_button = this.buttons[button].querySelector("paper-icon-button")
      ? this.buttons[button]
      : this.buttons[button].shadowRoot;
    const clockIcon =
      clock_button.querySelector("paper-icon-button") || this.buttons[button];
    const clockIronIcon =
      clockIcon.querySelector("iron-icon") ||
      clockIcon.shadowRoot.querySelector("iron-icon");
    const clockWidth =
      (this.cchConfig.clock_format == 12 && this.cchConfig.clock_am_pm) ||
      this.cchConfig.clock_date
        ? 105
        : 80;
    if (
      !this.newSidebar &&
      this.cchConfig.notifications == "clock" &&
      this.cchConfig.clock_date &&
      !this.buttons.notifications.shadowRoot.querySelector("#cch_indicator")
    ) {
      let style = document.createElement("style");
      style.setAttribute("id", "cch_indicator");
      style.innerHTML = `
            .indicator {
              top: unset;
              bottom: -3px;
              right: 0px;
              width: 90%;
              height: 3px;
              border-radius: 0;
              ${
                this.cchConfig.notify_indicator_color
                  ? `background-color:${this.cchConfig.notify_indicator_color}`
                  : ""
              }
            }
            .indicator > div{
              display:none;
            }
          `;
      this.buttons.notifications.shadowRoot.appendChild(style);
    }
    let clockElement = clockIronIcon.parentNode.getElementById("cch_clock");
    if (this.cchConfig.menu == "clock") {
      this.buttons.menu.style.marginTop = this.cchConfig.compact_header
        ? "111px"
        : "";
      this.buttons.menu.style.zIndex = "1";
    }
    if (!clockElement) {
      clockIcon.style.cssText = `
                margin-right:-5px;
                width:${clockWidth}px;
                text-align: center;
              `;
      clockElement = document.createElement("p");
      clockElement.setAttribute("id", "cch_clock");
      let clockAlign = "center";
      let padding = "";
      let fontSize = "";
      if (this.cchConfig.clock_date && this.cchConfig.menu == "clock") {
        clockAlign = "left";
        padding = "margin-right:-20px";
        fontSize = "font-size:12pt";
      } else if (this.cchConfig.clock_date) {
        clockAlign = "right";
        padding = "margin-left:-20px";
        fontSize = "font-size:12pt";
      }
      clockElement.style.cssText = `
                margin-top: ${this.cchConfig.clock_date ? "-4px" : "2px"};
                text-align: ${clockAlign};
                ${padding};
                ${fontSize};
              `;
      clockIronIcon.parentNode.insertBefore(clockElement, clockIronIcon);
      clockIronIcon.style.display = "none";
      let style = document.createElement("style");
      style.setAttribute("id", "cch_clock");
      style.innerHTML = `
            time {
              ${this.cchConfig.time_css}
            }
            date {
              ${this.cchConfig.date_css}
            }
          `;
      clockIronIcon.parentNode.insertBefore(style, clockIronIcon);
    }
    const clockFormat = {
      hour12: this.cchConfig.clock_format != 24,
      hour: "2-digit",
      minute: "2-digit"
    };
    this.updateClock(clockElement, clockFormat);
  }
  updateClock(clock, clockFormat) {
    let date = new Date();
    let seconds = date.getSeconds();
    let locale = this.cchConfig.date_locale || this.hass.language;
    let time = date.toLocaleTimeString([], clockFormat);
    let options = {
      weekday: "short",
      month: "2-digit",
      day: "2-digit"
    };
    date = this.cchConfig.clock_date
      ? `
${cch.hass.user.name}