// Options picker
import {
  OPTION_GROUP_CLASSNAME,
  TALL_CLASSNAME,
  TOOL_INFO_CLASSNAME,
  WIDE_CLASSNAME,
} from '../config.js';
import {Tool} from '../tool.js';
import {show, hide} from '../helper.js';

export class OptionsTool extends Tool {
  sectionNames = undefined;
  groups = {};

  constructor(sectionNames) {
    super();
    this.sectionNames = sectionNames;
  }

  setContainer(container) {
    super.setContainer(container);
    // Initialize
    for (const sectionName of this.sectionNames) {
      const group = this.sim.options.getSection(sectionName);
      const item = this.visitItem(group);
      this.div.appendChild(item);
    }
  }

  // For now, `showIf` must be the name of a boolean property, with optional negation
  shouldShow(option) {
    if (option.showIf === undefined) return true;
    const {name, value} = this.deconstructOption(option.showIf);
    return this.sim.getOption(name) === value;
  }

  deconstructOption(showIf) {
    let name = showIf;
    let value = true;
    if (name.startsWith('!')) {
      value = false;
      name = name.slice(1);
    }
    return {name, value};
  }

  visitItem(item, path) {
    path = [path, item.name].filter(x => !!x).join('.');
    switch (item.type) {
      case 'group': {
        const groupEl = document.createElement('div');
        groupEl.classList.add(OPTION_GROUP_CLASSNAME);
        const group = {groupEl, items: []};
        this.groups[path] = group;
        if (item.title) {
          const heading = document.createElement('h3');
          heading.innerHTML = item.title;
          groupEl.appendChild(heading);
          groupEl.items.push({itemEl: heading});
        }
        for (const next of item.items) {
          const optionEl = this.visitItem(next, path);
          group.items.push(next);
          if (this.shouldShow(next)) {
            groupEl.appendChild(optionEl);
          }
          if (next.showIf) {
            const {name} = this.deconstructOption(next.showIf);
            this.sim.onOptionSet(name, () => {
              if (this.shouldShow(next)) {
                show({
                  items: group.items,
                  item: next,
                  parentEl: groupEl,
                  itemEl: optionEl,
                });
              } else {
                hide({
                  items: group.items,
                  item: next,
                  parentEl: groupEl,
                  itemEl: optionEl,
                });
              }
            });
          }

        }
        return groupEl;
      }
      case 'boolean': {
        const button = document.createElement('button');
        button.innerHTML = item.title;
        if (item.wide === true) button.classList.add(WIDE_CLASSNAME);
        if (item.tall === true) button.classList.add(TALL_CLASSNAME);
        const value = this.sim.getOption(path);
        button.style.opacity = value ? '100%' : '50%';
        this.sim.onOptionSet(path, ({value}) => {
          button.style.opacity = value ? '100%' : '50%';
        });
        button.addEventListener('click', () => {
          const value = this.sim.getOption(path);
          this.sim.setOption(path, !value);
        });
        return button;
      }
      case 'number': {
        const div = document.createElement('div');
        const title = document.createElement('button');
        const input = document.createElement('input');
        const maxLength = item.maxLength || 8;
        div.appendChild(title);
        div.appendChild(input);
        div.classList.add(WIDE_CLASSNAME);
        title.classList.add(TOOL_INFO_CLASSNAME);
        if (item.wide) {
          title.classList.add(WIDE_CLASSNAME);
          input.classList.add(WIDE_CLASSNAME);
        }
        title.innerHTML = item.title;
        input.value = this.sim.getOption(path);

        input.addEventListener('input', () => {
          input.value = input.value.slice(0, maxLength);
        });

        input.addEventListener('change', () => {
          this.sim.setOption(path, input.value);
          // Enforce min/max if provided
          if (item.max !== undefined && this.sim.getOption(path) > item.max) {
            this.sim.setOption(path, item.max);
          }
          if (item.min !== undefined && this.sim.getOption(path) < item.min) {
            this.sim.setOption(path, item.min);
          }
        });

        this.sim.onOptionSet(path, ({value}) => {
          input.value = value;
        });

        return div;
      }
      default:
        throw new Error('Unknown option type');
    }
  }
}
