 
// Cache DOM elements
const inputElements = document.querySelectorAll('[data-model]');
const boundElements = document.querySelectorAll('[data-bind]');
const loopElements = document.querySelectorAll('[data-loop]');

/* --- Bind element --- */

function binder(data) {
  let scope = {}
  // Add data
  if (data) {
    for (const propName of Object.getOwnPropertyNames(data)) {
      scope[propName] = data[propName];
      setBindValue(propName, data[propName]);
    }
  }
  // Loop through input elements
  for (let el of inputElements) {
    if (el.type === 'text' || el.type === 'hidden') {
      // Get property name from each input with an attribute of 'mm-model'
      let propName = el.getAttribute('data-model');

      // Set property update logic
      setPropUpdateLogic(scope, propName);

      // Update bound scope property on input change
      scope[propName] = el.value;
      el.addEventListener('keyup', e => {
        scope[propName] = el.value;
      });
    }
  }
  return scope;
};

function setPropUpdateLogic(scope, prop) {
  if (!scope.hasOwnProperty(prop)) {
    let value;
    Object.defineProperty(scope, prop, {
      // Automatically update bound dom elements when a scope property is set to a new value
      set: (newValue) => {
        value = newValue;

        // Set input elements to new value
        for (let el of inputElements) {
          if (el.getAttribute('data-model') === prop) {
            if (el.type) {
              el.value = newValue;
            }
          }
        }
        // Set all other bound dom elements to new value
        setBindValue(prop, newValue);
      },
      get: () => {
        return value;
      },
      enumerable: true
    })
  }
}

function setBindValue(prop, newValue) {
  for (let el of boundElements) {
    if (el.getAttribute('data-bind') === prop) {
      if (!el.type) {
        el.innerHTML = newValue;
      }
    }
  }
}

/* --- For each --- */

function looper(scope) {
  for (let el of loopElements) {
    let propName = el.getAttribute('data-loop');
    let data = scope[propName];
    let html = [];
    // If data is an array (if not do nothing)
    if (data && Array.isArray(data)) {
      // If data is already computed back to the initial value
      const defaultValue = el.querySelector('[data-looped]')
      if (defaultValue)  {
        el.innerHTML = defaultValue.innerHTML;
      }

      // Add the not computed value
      html.push(`<div data-looped="${propName}" style="display: none">${el.innerHTML}</div>`);

      // Add info to replace value
      for (let i = 0; i < data.length; i++) {
        html.push(el.innerHTML.replace(/data-val="/g, 'data-index="' + i + '" data-val="'));
      }
      el.innerHTML = html.join("\n");

      // Replace value for the current loop
      const currentLoopElements = document.querySelectorAll('[data-loop=' + propName + ']');
      for (const currentElement of currentLoopElements) {
        valElements = currentElement.querySelectorAll('[data-val][data-index]');
        for (const valElement of valElements) {
          const val = scope[propName][valElement.getAttribute('data-index')][valElement.getAttribute('data-val')];
          if (val) {
            valElement.innerHTML = val;
          }
        }
      }
    }
  }
}