"use strict"

import view from "./view.js";

class InputNumberFormViewController extends HTMLElement {

  static get observedAttributes(){ return ["value"]; }

  constructor(model){
    super();
    this.state = {};
    this.model = model || {};
    this.state.connected = false;
    this.model.name = this.model.name || "";
    this.model.label = this.model.label || "";
    this.model.placeholder = this.model.placeholder || "";
    this.model.required = this.model.required || false;

    //Keeps reference of events with bindings (so we can remove them)
    //see: https://stackoverflow.com/options/11565471/removing-event-listener-which-was-added-with-bind
    this.event = {};
    this.shadowRoot = this.attachShadow({mode: "closed"});
    this.shadowRoot.appendChild(view.content.cloneNode(true));
    this.view = {};
  }

  //Fires when the element is inserted into the DOM. It's a good place to set
  //the initial role, tabindex, internal state, and install event listeners.
  //
  //NOTE: A user may set a property on an instance of an element, before its
  //prototype has been connected to this class. The _upgradeProperty() method
  //will check for any instance properties and run them through the proper
  //class setters.
  connectedCallback() {
    //Wire views here
    this.view.container = this.shadowRoot.querySelector("#container");
    this.view.labelInput = this.shadowRoot.querySelector("#labelInput");
    this.view.nameInput = this.shadowRoot.querySelector("#nameInput");
    this.view.placeholderInput = this.shadowRoot.querySelector("#placeholderInput");
    this.view.requiredSwitch = this.shadowRoot.querySelector("#requiredSwitch");

    //Reference events with bindings
    this.event.onKeyup = this._onKeyup.bind(this);
    this.event.onFocus = this._onFocusBlur.bind(this);
    this.event.onBlur = this._onFocusBlur.bind(this);
    this.event.onUpdate = this._onUpdate.bind(this);

    this.view.nameInput.addEventListener("keyup", this.event.onKeyup);

    this.view.labelInput.addEventListener("keyup", this.event.onKeyup);
    this.view.labelInput.addEventListener("focus", this.event.onFocus);
    this.view.labelInput.addEventListener("blur", this.event.onBlur);

    this.view.placeholderInput.addEventListener("keyup", this.event.onKeyup);
    this.view.placeholderInput.addEventListener("focus", this.event.onFocus);
    this.view.placeholderInput.addEventListener("blur", this.event.onBlur);

    this.view.requiredSwitch.addEventListener("update", this.event.onUpdate);

    // Let the element we're live
    this.state.connected = true;
    this._updateView();
  }

  attributeChangedCallback(attrName, oldVal, newVal) {
    switch(attrName){
      case "value":
        if(newVal !== this.value){ this.value = newVal; }
        break;
      default:
        throw new Error(`Attribute ${attrName} is not handled, you should probably do that`);
    }
  }

  //ADD TO TEMPLATE ELEMENT
  get model(){ return this._model}
  set model(value){
    value.type = "ui-input-number-form";
    this._model = value;
  }

  get value(){ return this.model; }
  set value(value){
    //Check if attribute matches property value, Sync the property with the
    //attribute if they do not, skip this step if already sync
    if(this.getAttribute("value") !== value){
      //By setting the attribute, the attributeChangedCallback() function is
      //called, which inturn calls this setter again.
      const stringValue = JSON.stringify(value);
      this.setAttribute("value", stringValue);
      //attributeChangeCallback() implicitly called
      return;
    }

    let updatedModel;
    switch(value.constructor){
      case String:
        updatedModel = JSON.parse(value);
        updatedModel.type = "ui-input-number-form";
        this.model = updatedModel;
        break;
      case Object:
        updatedModel = value;
        updatedModel.type = "ui-input-number-form";
        this.model = updatedModel;
        break;
    }

    this._updateView();
    this.dispatchEvent(new CustomEvent("update", {detail: this.model}));
  }

  get shadowRoot(){return this._shadowRoot;}
  set shadowRoot(value){ this._shadowRoot = value}

  _onKeyup(){
    this.model.name = this.view.nameInput.value;
    this.model.label = this.view.labelInput.value;
    this.model.placeholder = this.view.placeholderInput.value;
    this.dispatchEvent(new CustomEvent("update", {detail: this.model}));
  }

  _onFocusBlur(){
    this.dispatchEvent(new CustomEvent("update", {detail: this.model}));
  }

  _onUpdate(e){
    this.model.required = e.detail;
    this._updateView();
    this.dispatchEvent(new CustomEvent("update", {detail: this.model}));
  }


  _elementify(string){
    const template = document.createElement("div");
    template.innerHTML = string;
    const element = template.querySelector(":first-child");
    template.remove();
    return element;
  }

  _arraiafy(nodeList){
    const array = [];
    for(var i=0; i<nodeList.length; i++){
      array.push(nodeList[i]);
    }
    return array;
  }

  _updateView(view) {
    //No point in rendering if there isn't a model source, or a view on screen
    if(!this.model || !this.state.connected){ return; }

    switch(view){

      default:
        // Unlike the others, this uses view because its not dynamically populated (others are)
        this.view.nameInput.value = this.model.name || "";
        this.view.labelInput.value = this.model.label || "";
        this.view.placeholderInput.value = this.model.placeholder || "";
        this.view.labelInput.focus();
        this.view.requiredSwitch.setAttribute("value", this.model.required);
        break;
    }
  }

  disconnectedCallback() {
    this._removeEvents()
    this.state.connected = false;
  }

  _removeEvents(){
    this.view.container.removeEventListener("click", this.event.keyup);
  }
}

window.customElements.define("ui-input-number-form", InputNumberFormViewController);
