<template>
  <span class="icon" :class="sizeClass" @click="$emit('click', $event)" ref="container">

  </span>
</template>

<script>
  
  import IconicJs from "../iconic/js/iconic.min";

  import Caret from "../iconic/svg/smart/caret";
  import Check from "../iconic/svg/smart/check";
  import CircleCheck from "../iconic/svg/smart/circle-check";
  import Link from "../iconic/svg/smart/link";
  import Lock from "../iconic/svg/smart/lock";
  import Menu from "../iconic/svg/smart/menu";
  import Person from "../iconic/svg/smart/person";
  import Pencil from "../iconic/svg/smart/pencil";
  import Star from "../iconic/svg/smart/star";
  import StarEmpty from "../iconic/svg/smart/star-empty";
  import X from "../iconic/svg/smart/x";
  
  const SVG_CACHE = {};
  let REMAP_COUNT = 0;
  
  class IconData {
    constructor(svgData, dataAttributes) {
      this.svgData = svgData;
      this.dataAttributes = dataAttributes || {};
      this.svgTemplate = null;
    }

    getSvg() {
      if (this.svgTemplate === null) {
        const iconicName = this.svgData.attributes.class;

        this.svgTemplate = SVG_CACHE[iconicName] || null;

        if (this.svgTemplate === null) {
          this.svgTemplate = document.createElementNS("http://www.w3.org/2000/svg", "svg");
          SVG_CACHE[iconicName] = this.svgTemplate;

          for (let attr in this.svgData.attributes) {
            this.svgTemplate.setAttribute(attr, this.svgData.attributes[attr]);
          }
          this.svgTemplate.innerHTML = this.svgData.content;


          // Find then prune the scripts
          const scripts = [...this.svgTemplate.querySelectorAll('script')];

          scripts.filter(s => {
            let scriptType = s.getAttribute("type");
            return !scriptType || scriptType === 'application/ecmascript' || scriptType === 'application/javascript'
          }).forEach(s => {
            new Function(s.innerText || s.textContent)(window);
            this.svgTemplate.removeChild(s);
          });
        }
      }

      const clone = this.svgTemplate.cloneNode(true);
      this.remapIds(clone);
      this.attachIconicApi(clone);
      for (let attr in this.dataAttributes) {
        clone.setAttribute(`data-${attr}`, this.dataAttributes[attr]);
      }
      return clone;
    }

    remapIds(svg) {
      const iriElementsAndProperties = {
        'clipPath': ['clip-path'],
        'color-profile': ['color-profile'],
        'cursor': ['cursor'],
        'filter': ['filter'],
        'linearGradient': ['fill', 'stroke'],
        'marker': ['marker', 'marker-start', 'marker-mid', 'marker-end'],
        'mask': ['mask'],
        'pattern': ['fill', 'stroke'],
        'radialGradient': ['fill', 'stroke']
      };

      REMAP_COUNT += 1;

      let element, elementDefs, properties, currentId, newId;
      Object.keys(iriElementsAndProperties).forEach(function (key) {
        element = key;
        properties = iriElementsAndProperties[key];

        elementDefs = svg.querySelectorAll('defs ' + element + '[id]');
        for (var i = 0, elementsLen = elementDefs.length; i < elementsLen; i++) {
          currentId = elementDefs[i].id;
          newId = currentId + '-' + REMAP_COUNT;

          // All of the properties that can reference this element type
          var referencingElements;
          properties.forEach(function (property) {
            // :NOTE: using a substring match attr selector here to deal with IE "adding extra quotes in url() attrs"
            referencingElements = svg.querySelectorAll('[' + property + '*="' + currentId + '"]');
            for (var j = 0, referencingElementLen = referencingElements.length; j < referencingElementLen; j++) {
              referencingElements[j].setAttribute(property, 'url(#' + newId + ')');
            }
          });

          elementDefs[i].id = newId;
        }
      });
    }

    attachIconicApi(svg) {
      const key = svg.getAttribute("data-icon");
      const apis = window.iconicSmartIconApis;
      if (key && apis[key]) {
        const iconApi = apis[key](svg);
        for (let func in iconApi) svg[func] = iconApi[func]
      }
    }
  }

  class SizeData {
    constructor(bulmaIconClass, defaultPadding) {
      this.bulmaIconClass = bulmaIconClass;
      this.defaultPadding = defaultPadding || null;
    }
  }

  class IconicQueue {
    constructor(iconicInstance) {
      this.iconic = iconicInstance;
      this.updateQueue = [];
      this.isTimerRunning = false;
    }

    processQueues() {
      if (this.updateQueue.length > 0) {
        console.log(`updating ${this.updateQueue.length}`);
        this.iconic.update(this.updateQueue);
        this.updateQueue.forEach(s => (s.style.visibility = null));
        this.updateQueue = [];
      }

      this.isTimerRunning = false;
    }

    ensureTimer() {
      if (!this.isTimerRunning) {
        this.isTimerRunning = true;
        setTimeout(() => this.processQueues());
      }
    }

    updateSvg(svgElem) {
      this.updateQueue.push(svgElem);
      this.ensureTimer();
    }
  }

  const iconicInstance = IconicJs({
    autoInjectSelector: "#notreal-noinjection"
  });

  const iconicQueue = new IconicQueue(iconicInstance);
  
  const iconMap = {
    'caret-bottom': new IconData(Caret, {direction: 'bottom'}),
    'caret-top': new IconData(Caret, {direction: 'top'}),
    check: new IconData(Check),
    'circle-check': new IconData(CircleCheck),
    'link-broken': new IconData(Link, {state: 'broken'}),
    'link-intact': new IconData(Link, {state: 'intact'}),
    'lock-locked': new IconData(Lock, {state: 'locked'}),
    'lock-unlocked': new IconData(Lock, {state: 'unlocked'}),
    menu: new IconData(Menu),
    pencil: new IconData(Pencil),
    person: new IconData(Person),
    star: new IconData(Star),
    'star-empty': new IconData(StarEmpty),
    x: new IconData(X)
  };

  const sizeMap = {
    xs: new SizeData('is-small', '25%'),
    sm: new SizeData('is-small'),
    md: new SizeData(''),
    lg: new SizeData('is-medium'),
    xl: new SizeData('is-large')
  };

  export default {
    props: {
      icon: {
        validator: (i) => iconMap[i] !== undefined
      },
      size: {
        required: false,
        type: String,
        validator: (s) => sizeMap[s] !== undefined,
        default: 'md'
      },
      padding: {
        type: String,
        required: false,
        default: null
      }
    },

    data() {
      return {
        injectedSvg: null
      }
    },

    computed: {
      iconData() {
        return iconMap[this.icon];
      },

      sizeData() {
        return sizeMap[this.size];
      },

      sizeClass() {
        return this.sizeData.bulmaIconClass;
      },

      svgPadding() {
        return this.padding || this.sizeData.defaultPadding || "15%";
      }
    },

    methods: {
      insertSvg() {
        const parent = this.$refs.container;

        while (parent.firstChild) {
          parent.removeChild(parent.firstChild);
        }

        const svg = this.iconData.getSvg();
        this.injectedSvg = svg;

        svg.style.padding = this.svgPadding;
        svg.style.visibility = "hidden";
        svg.classList.add("iconic-fluid");
        parent.appendChild(svg);


        setTimeout(() => {
          //svg.style.visibility = "visible";
          //iconicInstance.update(svg);
          iconicQueue.updateSvg(svg);
        });
      }
    },

    mounted() {
      let self = this;
      this.$watch(
        function() { return this.icon + this.size + this.padding },
        function() {
          this.insertSvg();
        },
        {
          immediate: true
        }
      )
    }
  }

</script>

<style lang="scss" scoped>



</style>