customElements.define('card-tools',
class {
  static get CUSTOM_TYPE_PREFIX() { return "custom:"}
  static get version() { return "0.4"}
  static checkVersion(v) {
    if (this.version < v) {
      throw new Error(`Old version of card-tools found. Get the latest version of card-tools.js from https://github.com/thomasloven/lovelace-card-tools`);
    }
  }
  static deprecationWarning() {
    if(window.cardTools_deprecationWarning) return;
    console.warn("One or more of your lovelace plugins are using the functions cardTools.litElement(), cardTools.litHtml() or cardTools.hass(). Those are replaced with better alternatives and will be removed a some point in the future.")
    console.warn("If you are a plugin developer, make sure you are using the new functions (see documentation).");
    console.warn("If you are a plugin user, feel free to ignore this warning (or poke the developer of your plugins - not me though, I already know about this).")
    console.warn("Best regards / thomasloven - " + (document.currentScript && document.currentScript.src));
  window.cardTools_deprecationWarning = true;
  }
  static get LitElement() {
    if(customElements.get('home-assistant-main'))
      return Object.getPrototypeOf(customElements.get('home-assistant-main'));
    return Object.getPrototypeOf(customElements.get('hui-view'));
  }
  static litElement() { // Backwards compatibility - deprecated
    this.deprecationWarning();
    return this.LitElement;
  }
  static get LitHtml() {
    return this.LitElement.prototype.html;
  }
  static litHtml() { // Backwards compatibility - deprecated
    this.deprecationWarning();
    return this.LitHtml;
  }
  static get LitCSS() {
    return this.LitElement.prototype.css;
  }
  static get hass() {
    var hass = function() { // Backwards compatibility - deprecated
      this.deprecationWarning();
      return hass;
    }
    for (var k in document.querySelector('home-assistant').hass)
      hass[k] = document.querySelector('home-assistant').hass[k];
    hass.original = document.querySelector('home-assistant').hass;
    return hass;
  }
  static fireEvent(ev, detail, entity=null) {
    ev = new Event(ev, {
      bubbles: true,
      cancelable: false,
      composed: true,
    });
    ev.detail = detail || {};
    if(entity) {
      entity.dispatchEvent(ev);
    } else {
      var root = document.querySelector("home-assistant");
      root = root && root.shadowRoot;
      root = root && root.querySelector("home-assistant-main");
      root = root && root.shadowRoot;
      root = root && root.querySelector("app-drawer-layout partial-panel-resolver");
      root = root && root.shadowRoot || root;
      root = root && root.querySelector("ha-panel-lovelace");
      root = root && root.shadowRoot;
      root = root && root.querySelector("hui-root");
      root = root && root.shadowRoot;
      root = root && root.querySelector("ha-app-layout #view");
      root = root && root.firstElementChild;
      if (root) root.dispatchEvent(ev);
    }
  }
  static get lovelace() {
    var root = document.querySelector("home-assistant");
    root = root && root.shadowRoot;
    root = root && root.querySelector("home-assistant-main");
    root = root && root.shadowRoot;
    root = root && root.querySelector("app-drawer-layout partial-panel-resolver");
    root = root && root.shadowRoot || root;
    root = root && root.querySelector("ha-panel-lovelace")
    root = root && root.shadowRoot;
    root = root && root.querySelector("hui-root")
    if (root) {
      var ll =  root.lovelace
      ll.current_view = root.___curView;
      return ll;
    }
    return null;
  }
  static createThing(thing, config) {
    const _createThing = (tag, config) => {
      const element = document.createElement(tag);
      try {
        element.setConfig(config);
      } catch (err) {
        console.error(tag, err);
        return _createError(err.message, config);
      }
      return element;
    };
    const _createError = (error, config) => {
      return _createThing("hui-error-card", {
        type: "error",
        error,
        config,
      });
    };
    if(!config || typeof config !== "object" || !config.type)
      return _createError(`No ${thing} type configured`, config);
    let tag = config.type;
    if(config.error) {
      const err = config.error;
      delete config.error;
      return _createError(err, config);
    }
    if(tag.startsWith(this.CUSTOM_TYPE_PREFIX))
      tag = tag.substr(this.CUSTOM_TYPE_PREFIX.length);
    else
      tag = `hui-${tag}-${thing}`;
    if(customElements.get(tag))
      return _createThing(tag, config);
    // If element doesn't exist (yet) create an error
    const element = _createError(
      `Custom element doesn't exist: ${tag}.`,
      config
    );
    element.style.display = "None";
    const timer = setTimeout(() => {
      element.style.display = "";
    }, 2000);
    // Remove error if element is defined later
    customElements.whenDefined(tag).then(() => {
      clearTimeout(timer);
      this.fireEvent("ll-rebuild", {}, element);
    });
    return element;
  }
  static createCard(config) {
    return this.createThing("card", config);
  }
  static createElement(config) {
    return this.createThing("element", config);
  }
  static createEntityRow(config) {
    const SPECIAL_TYPES = new Set([
      "call-service",
      "divider",
      "section",
      "weblink",
    ]);
    const DEFAULT_ROWS = {
      alert: "toggle",
      automation: "toggle",
      climate: "climate",
      cover: "cover",
      fan: "toggle",
      group: "group",
      input_boolean: "toggle",
      input_number: "input-number",
      input_select: "input-select",
      input_text: "input-text",
      light: "toggle",
      media_player: "media-player",
      lock: "lock",
      remote: "toggle",
      scene: "scene",
      script: "script",
      sensor: "sensor",
      timer: "timer",
      switch: "toggle",
      vacuum: "toggle",
      water_heater: "climate",
      input_datetime: "input-datetime",
    };
    if(!config || typeof config !== "object" || (!config.entity && !config.type)) {
      Object.assign(config, {error: "Invalid config given"});
      return this.createThing("", config);
    }
    const type = config.type || "default";
    if(SPECIAL_TYPES.has(type) || type.startsWith(this.CUSTOM_TYPE_PREFIX))
      return this.createThing("row", config);
    const domain = config.entity.split(".", 1)[0];
    Object.assign(config, {type: DEFAULT_ROWS[domain] || "text"});
    return this.createThing("entity-row", config);
  }
  static get deviceID() {
    const ID_STORAGE_KEY = 'lovelace-player-device-id';
    if(window['fully'] && typeof fully.getDeviceId === "function")
      return fully.getDeviceId();
    if(!localStorage[ID_STORAGE_KEY])
    {
      const s4 = () => {
        return Math.floor((1+Math.random())*100000).toString(16).substring(1);
      }
      localStorage[ID_STORAGE_KEY] = `${s4()}${s4()}-${s4()}${s4()}`;
    }
    return localStorage[ID_STORAGE_KEY];
  }
  static moreInfo(entity) {
    this.fireEvent("hass-more-info", {entityId: entity});
  }
  static longpress(element) {
    customElements.whenDefined("long-press").then(() => {
      const longpress = document.body.querySelector("long-press");
      longpress.bind(element);
    });
    return element;
  }
  static hasTemplate(text) {
    return /\[\[\s+.*\s+\]\]/.test(text);
  }
  static parseTemplateString(str, specialData = {}) {
    if(typeof(str) !== "string") return text;
    const FUNCTION = /^[a-zA-Z0-9_]+\(.*\)$/;
    const EXPR = /([^=<>!]+)\s*(==|!=|<|>|<=|>=)\s*([^=<>!]+)/;
    const SPECIAL = /^\{.+\}$/;
    const STRING = /^"[^"]*"|'[^']*'$/;
    if(typeof(specialData) === "string") specialData = {};
    specialData = Object.assign({
      user: this.hass.user.name,
      browser: this.deviceID,
      hash: location.hash.substr(1) || ' ',
    }, specialData);
    const _parse_function = (str) => {
      let args = [str.substr(0, str.indexOf('(')).trim()]
      str = str.substr(str.indexOf('(')+1);
      while(str) {
        let index = 0;
        let parens = 0;
        let quote = false;
        while(str[index]) {
          let c = str[index++];
          if(c === quote && index > 1 && str[index-2] !== "\\")
              quote = false;
          else if(`"'`.includes(c))
            quote = c;
          if(quote) continue;
          if(c === '(')
            parens = parens + 1;
          else if(c === ')') {
            parens = parens - 1;
            continue
          }
          if(parens > 0) continue;
          if(",)".includes(c)) break;
        }
        args.push(str.substr(0, index-1).trim());
        str = str.substr(index);
      }
      return args;
    };
    const _parse_special = (str) => {
      str = str.substr(1, str.length - 2);
      return specialData[str] || `{${str}}`;
    };
    const _parse_entity = (str) => {
      str = str.split(".");
      let v;
      if(str[0].match(SPECIAL)) {
        v = _parse_special(str.shift());
        v = this.hass.states[v] || v;
      } else {
        v = this.hass.states[`${str.shift()}.${str.shift()}`];
        if(!str.length) return v['state'];
      }
      str.forEach(item => v=v[item]);
      return v;
    }
    const _eval_expr = (str) => {
      str = EXPR.exec(str);
      if(str === null) return false;
      const lhs = this.parseTemplateString(str[1]);
      const rhs = this.parseTemplateString(str[3]);
      var expr = ''
      if(parseFloat(lhs) != lhs)
        expr = `"${lhs}" ${str[2]} "${rhs}"`;
      else
        expr = `${parseFloat(lhs)} ${str[2]} ${parseFloat(rhs)}`
      return eval(expr);
    }
    const _eval_function = (args) => {
      if(args[0] === "if") {
        if(_eval_expr(args[1]))
          return this.parseTemplateString(args[2]);
        return this.parseTemplateString(args[3]);
      }
    }
    try {
      str = str.trim();
      if(str.match(STRING))
        return str.substr(1, str.length - 2);
      if(str.match(SPECIAL))
        return _parse_special(str);
      if(str.match(FUNCTION))
        return _eval_function(_parse_function(str));
      if(str.includes("."))
        return _parse_entity(str);
      return str;
    } catch (err) {
      return `[[ Template matching failed: ${str} ]]`;
    }
  }
  static parseTemplate(text, data = {}) {
    if(typeof(text) !== "string") return text;
    // Note: .*? is javascript regex syntax for NON-greedy matching
    var RE_template = /\[\[\s(.*?)\s\]\]/g;
    text = text.replace(RE_template, (str, p1, offset, s) => this.parseTemplateString(p1, data));
    return text;
  }
  static args(script=null) {
    script = script || document.currentScript;
    var url = script.src;
    url = url.substr(url.indexOf("?")+1)
    let args = {};
    url.split("&").forEach((a) => {
      if(a.indexOf("=")) {
        let parts = a.split("=");
        args[parts[0]] = parts[1]
      } else {
        args[a] = true;
      }
    });
    return args;
  }
  static localize(key, def="") {
    const language = this.hass.language;
    if(this.hass.resources[language] && this.hass.resources[language][key])
      return this.hass.resources[language][key];
    return def;
  }
  static popUp(title, message, large=false) {
    let popup = document.createElement('div');
    popup.innerHTML = `
    
    
      
      
        ${title}
      
    
  `;
    popup.appendChild(message);
    this.moreInfo(Object.keys(this.hass.states)[0]);
    let moreInfo = document.querySelector("home-assistant")._moreInfoEl;
    moreInfo._page = "none";
    moreInfo.shadowRoot.appendChild(popup);
    moreInfo.large = large;
    document.querySelector("home-assistant").provideHass(message);
    setTimeout(() => {
      let interval = setInterval(() => {
        if (moreInfo.getAttribute('aria-hidden')) {
          popup.parentNode.removeChild(popup);
          clearInterval(interval);
        }
      }, 100)
    }, 1000);
  return moreInfo;
  }
  static closePopUp() {
    let moreInfo = document.querySelector("home-assistant")._moreInfoEl;
    if (moreInfo) moreInfo.close()
  }
  static logger(message, script=null) {
    if(!('debug' in this.args(script))) return;
    if(typeof message !== "string")
      message = JSON.stringify(message);
    console.log(`%cDEBUG:%c ${message}`,
      "color: blue; font-weight: bold", "");
  }
});
// Global definition of cardTools
var cardTools = customElements.get('card-tools');
console.info(`%cCARD-TOOLS IS INSTALLED
%cDeviceID: ${customElements.get('card-tools').deviceID}`,
"color: green; font-weight: bold",
"");