// DinoWorks Component Script 2022-09-05
// Last Updated : 2022-09-05



// 사용자 정의 요소 공통 Class
class CustomElement extends HTMLElement {
  // properties (protected)
  _component = null;        // custom Elememt(component)
  _shadow = null;           // shadow dom root
  _data = {};               // data from custom Element (attr, data-, json-)
  _name = '';               // class name (CustomElement)
  _componentClass = '';     // component css 디자인용 class명
  _pathRoot = ''            // component 파일의 root 경로
  _style = null;            // shadow DOM 에 추가할 css file 객체
  _script = null;           // shadow DOM 에 추가할 javascript file 객체
  _template = ``;           // shadow DOM 에 추가할 html template 객체

  // The constructor() method is run when the element is created, before its injected into the UI.
  constructor() {
    super();
    this._component = this;
    this.attachShadow({mode: 'open'});
    this._shadow = this.shadowRoot;
    this._name = this.constructor.name;
    this._componentClass = '';
    for (let i = 0; i < this._name.length; i++) {
      if (this._name[i] === this._name[i].toUpperCase()) {
        this._componentClass += (i === 0) ? this._name[i].toLocaleLowerCase() : '-' + this._name[i].toLocaleLowerCase();
      } else {
        this._componentClass += this._name[i];
      }
    }
    this._pathRoot = './component';
    this._style = this.getStyle();
    this._script = this.getScript();

    this.setInitialCondition();
  }

  // 다시 렌더링 하는 경우 변경(재실행)되어야 하는 내용 정리
  setInitialCondition() {
    this._data = this.getAttributeData();
    this._template = this.createTemplate();
  }

  // The connectedCallback() method is run when the element is injected into the DOM, and again whenever it’s moved or appended elsewhere.
  connectedCallback() {
    this.render();
  }

  // The disconnectedCallback() method is run whenever the element is removed from the DOM.
  disconnectedCallback() {
    this.empty();
  }

  getAttributeData() {
    const component = this._component;
    let data = {attr: {}, bind: {}, prop: {}, json: {}, on: {}};

    for (let i = 0; i < component.attributes.length; i++) {
      let key = component.attributes[i].name;
      let value = component.attributes[i].value;

      // data 처리 (attr, bind-attr, data-attr, json-attr, on-attr)
      if (key.indexOf('bind-') !== -1) {
        data.bind[key.replace('bind-', '')] = value;
      } else if (key.indexOf('data-') !== -1) {
        data.prop[key.replace('data-', '')] = value;
      } else if (key.indexOf('json-') !== -1) {
        try {
          data.json[key.replace('json-', '')] = JSON.parse(value);
        } catch(e) {
          console.warn(e, this);
        }
      } else if (key.indexOf('on-') !== -1) {
        data.on[key.replace('on-', 'on')] = value;
      } else {
        data.attr[key] = value;
      }
    }

    return data;
  }

  getStyle() {
    const pathRoot = this._pathRoot;
    const name = this._name;
    const style = document.createElement('link');
    style.setAttribute('rel', 'stylesheet');
    style.setAttribute('href', pathRoot + '/' + name + '.css');

    return style;
  }

  getScript() {
    const pathRoot = this._pathRoot;
    const name = this._name;
    const script = document.createElement('script');
    script.setAttribute('type', 'text/javascript');
    script.setAttribute('src', pathRoot + '/' + name + '.js');

    return script;
  }

  createTemplate() {
    // 개별 하위 내용에서 구현
    const template = document.createElement('template');
    template.innerHTML = `<div>Template is not defined.</div>`;

    return template.content.cloneNode(true);
  }

  setHook() {
    const component = this._component;
    const shadow = this._shadow;
    let hook = this._data.bind;
    const observer = new MutationObserver(setState);
    observer.observe(component, {
      childList: false,
      subtree: false,
      attributeOldValue: true,
    });

    // Attr 변화 체크
    function setState(mutationList, observer) {
      // console.log(mutationList[0]);
      // console.log(mutationList[0].type, mutationList[0].attributeName, mutationList[0].oldValue);
      for (let i = 0; i < mutationList.length; i++) {
        if (mutationList[i].type === "attributes" && (mutationList[i].attributeName.replace('bind-', '') in hook) === true) {
          let newValue = component.getAttribute(mutationList[i].attributeName);
          let oldValue = mutationList[i].oldValue;
          let key = mutationList[i].attributeName.replace('bind-', '');
          // console.log(oldValue);
          shadow.querySelector('input').setAttribute(key, newValue);
        }
      }
    }
  }

  setEvent() {
    // console.log('CustomElement: setEvent');
  }

  empty() {
    const shadow = this._shadow;
    while(shadow.firstChild) {
      shadow.firstChild.remove();
    }
  }

  render() {
    this.setInitialCondition();  // (재)렌더링시 콘텐츠 초기화

    const shadow = this._shadow;
    const style = this._style;
    const template = this._template;
    const script = this._script;

    this.empty();                               // 기존 내용 삭제 후 다시 렌더링(재 렌더링 대비)
    shadow.appendChild(this._style);
    shadow.appendChild(this._template);
    shadow.appendChild(this._script);
    this.setEvent();
    this.setHook();

    // console.log('rendering completed : ' + this._name);
  }
}



// input-text Tag 정의
class DinoInputText extends CustomElement {
  constructor() {
    super();
  }

  createTemplate() {
    const shadow = this._shadow;
    const template = document.createElement('template');
    const data = this._data;
    const componentClass = this._componentClass;
    let attrTemplate = ``;

    for (let key in data.attr) {
      let value = data.attr[key];
      attrTemplate += (attrTemplate === '') ? '' : ' ';
      attrTemplate += `${key}="${value}"`;
    }
    for (let key in data.bind) {
      let value = data.bind[key];
      key = key.replace('bind-', '');
      attrTemplate += (attrTemplate === '') ? '' : ' ';
      attrTemplate += `${key}="${value}"`;
    }
    for (let key in data.on) {
      let value = data.on[key];
      key = key.replace('on-', 'on');
      attrTemplate += (attrTemplate === '') ? '' : ' ';
      attrTemplate += `${key}="${value}"`;
    }

    // template 정의
    template.innerHTML = `
<div class="${componentClass}">
  <a href="#" class="before">11</a>
  <input type="text"
    ${attrTemplate}
  />
  <a href="#" class="after">22</a>
  <p class="guide">33</p>
  <p class="message">33</p>
</div>
`;

    return template.content.cloneNode(true);
  }

  setEvent() {
    const component = this._component;
    const shadow = this._shadow;

  }

}
customElements.define('dino-input-text', DinoInputText);



// select Tag 정의
class DinoSelect extends CustomElement {
  constructor() {
    super();
  }

  createTemplate() {
    const shadow = this._shadow;
    const template = document.createElement('template');
    let data = this._data;
    let attrTemplate = ``;
    let optionTemplate = ``;

    for (let key in data.attr) {
      let value = data.attr[key];
      attrTemplate += (attrTemplate === '') ? '' : ' ';
      attrTemplate += `${key}="${value}"`;
    }
    for (let key in data.bind) {
      let value = data.bind[key];
      key = key.replace('bind-', '');
      attrTemplate += (attrTemplate === '') ? '' : ' ';
      attrTemplate += `${key}="${value}"`;
    }
    for (let key in data.on) {
      let value = data.on[key];
      key = key.replace('on-', 'on');
      attrTemplate += (attrTemplate === '') ? '' : ' ';
      attrTemplate += `${key}="${value}"`;
    }
    for (let key in data.json.option) {
      let value = data.json.option[key];
      let selected = '';
      if (data.prop.value !== undefined && data.prop.value === key) {
        selected = ' selected="selected"';
      }
      optionTemplate += (optionTemplate === '') ? '' : '\n';
      optionTemplate += `<option value="${key}"${selected}>${value}</option>`;
    }


    // template 정의
    template.innerHTML = `
<div class="input-group">
  <select ${attrTemplate}>
    ${optionTemplate}
  </select>
  <p>RED</p>
  <dino-input-text></dino-input-text>
  <dino-input-text></dino-input-text>
  <dino-input-text></dino-input-text>
</div>
`;

    return template.content.cloneNode(true);
  }

  setEvent() {
    const component = this._component;
    const shadow = this._shadow;


  }
}

customElements.define('dino-select', DinoSelect);


