// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import {Draft, produce} from 'immer';
import * as m from 'mithril';

import {assertExists} from '../base/logging';
import {Actions} from '../common/actions';
import {RecordConfig} from '../controller/record_config_types';

import {copyToClipboard} from './clipboard';
import {globals} from './globals';

declare type Setter<T> = (draft: Draft<RecordConfig>, val: T) => void;
declare type Getter<T> = (cfg: RecordConfig) => T;

function defaultSort(a: string, b: string) {
  return a.localeCompare(b);
}

// +---------------------------------------------------------------------------+
// | Docs link with 'i' in circle icon.                                        |
// +---------------------------------------------------------------------------+

interface DocsChipAttrs {
  href: string;
}

class DocsChip implements m.ClassComponent<DocsChipAttrs> {
  view({attrs}: m.CVnode<DocsChipAttrs>) {
    return m(
        'a.inline-chip',
        {href: attrs.href, title: 'Open docs in new tab', target: '_blank'},
        m('i.material-icons', 'info'),
        ' Docs');
  }
}

// +---------------------------------------------------------------------------+
// | Probe: the rectangular box on the right-hand-side with a toggle box.      |
// +---------------------------------------------------------------------------+

export interface ProbeAttrs {
  title: string;
  img: string|null;
  compact?: boolean;
  descr: m.Children;
  isEnabled: Getter<boolean>;
  setEnabled: Setter<boolean>;
}

export class Probe implements m.ClassComponent<ProbeAttrs> {
  view({attrs, children}: m.CVnode<ProbeAttrs>) {
    const onToggle = (enabled: boolean) => {
      const traceCfg = produce(globals.state.recordConfig, draft => {
        attrs.setEnabled(draft, enabled);
      });
      globals.dispatch(Actions.setRecordConfig({config: traceCfg}));
    };

    const enabled = attrs.isEnabled(globals.state.recordConfig);

    return m(
        `.probe${attrs.compact ? '.compact' : ''}${enabled ? '.enabled' : ''}`,
        attrs.img && m('img', {
          src: `${globals.root}assets/${attrs.img}`,
          onclick: () => onToggle(!enabled),
        }),
        m('label',
          m(`input[type=checkbox]`, {
            checked: enabled,
            oninput: (e: InputEvent) => {
              onToggle((e.target as HTMLInputElement).checked);
            },
          }),
          m('span', attrs.title)),
        attrs.compact ?
            '' :
            m('div', m('div', attrs.descr), m('.probe-config', children)));
  }
}

export function CompactProbe(args: {
  title: string,
  isEnabled: Getter<boolean>,
  setEnabled: Setter<boolean>
}) {
  return m(Probe, {
    title: args.title,
    img: null,
    compact: true,
    descr: '',
    isEnabled: args.isEnabled,
    setEnabled: args.setEnabled
  } as ProbeAttrs);
}

// +-------------------------------------------------------------+
// | Toggle: an on/off switch.
// +-------------------------------------------------------------+

export interface ToggleAttrs {
  title: string;
  descr: string;
  cssClass?: string;
  isEnabled: Getter<boolean>;
  setEnabled: Setter<boolean>;
}

export class Toggle implements m.ClassComponent<ToggleAttrs> {
  view({attrs}: m.CVnode<ToggleAttrs>) {
    const onToggle = (enabled: boolean) => {
      const traceCfg = produce(globals.state.recordConfig, draft => {
        attrs.setEnabled(draft, enabled);
      });
      globals.dispatch(Actions.setRecordConfig({config: traceCfg}));
    };

    const enabled = attrs.isEnabled(globals.state.recordConfig);

    return m(
        `.toggle${enabled ? '.enabled' : ''}${attrs.cssClass || ''}`,
        m('label',
          m(`input[type=checkbox]`, {
            checked: enabled,
            oninput: (e: InputEvent) => {
              onToggle((e.target as HTMLInputElement).checked);
            },
          }),
          m('span', attrs.title)),
        m('.descr', attrs.descr));
  }
}

// +---------------------------------------------------------------------------+
// | Slider: draggable horizontal slider with numeric spinner.                 |
// +---------------------------------------------------------------------------+

export interface SliderAttrs {
  title: string;
  icon?: string;
  cssClass?: string;
  isTime?: boolean;
  unit: string;
  values: number[];
  get: Getter<number>;
  set: Setter<number>;
  min?: number;
  description?: string;
  disabled?: boolean;
}

export class Slider implements m.ClassComponent<SliderAttrs> {
  onValueChange(attrs: SliderAttrs, newVal: number) {
    const traceCfg = produce(globals.state.recordConfig, draft => {
      attrs.set(draft, newVal);
    });
    globals.dispatch(Actions.setRecordConfig({config: traceCfg}));
  }


  onTimeValueChange(attrs: SliderAttrs, hms: string) {
    try {
      const date = new Date(`1970-01-01T${hms}.000Z`);
      if (isNaN(date.getTime())) return;
      this.onValueChange(attrs, date.getTime());
    } catch {
    }
  }

  onSliderChange(attrs: SliderAttrs, newIdx: number) {
    this.onValueChange(attrs, attrs.values[newIdx]);
  }

  view({attrs}: m.CVnode<SliderAttrs>) {
    const id = attrs.title.replace(/[^a-z0-9]/gmi, '_').toLowerCase();
    const maxIdx = attrs.values.length - 1;
    const val = attrs.get(globals.state.recordConfig);
    const min = attrs.min;
    const description = attrs.description;
    const disabled = attrs.disabled;

    // Find the index of the closest value in the slider.
    let idx = 0;
    for (; idx < attrs.values.length && attrs.values[idx] < val; idx++) {
    }

    let spinnerCfg = {};
    if (attrs.isTime) {
      spinnerCfg = {
        type: 'text',
        pattern: '(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9]){2}',  // hh:mm:ss
        value: new Date(val).toISOString().substr(11, 8),
        oninput: (e: InputEvent) => {
          this.onTimeValueChange(attrs, (e.target as HTMLInputElement).value);
        },
      };
    } else {
      spinnerCfg = {
        type: 'number',
        value: val,
        oninput: (e: InputEvent) => {
          this.onTimeValueChange(attrs, (e.target as HTMLInputElement).value);
        },
      };
    }
    return m(
        '.slider' + (attrs.cssClass || ''),
        m('header', attrs.title),
        description ? m('header.descr', attrs.description) : '',
        attrs.icon !== undefined ? m('i.material-icons', attrs.icon) : [],
        m(`input[id="${id}"][type=range][min=0][max=${maxIdx}][value=${idx}]
        ${disabled ? '[disabled]' : ''}`,
          {
            oninput: (e: InputEvent) => {
              this.onSliderChange(attrs, +(e.target as HTMLInputElement).value);
            },
          }),
        m(`input.spinner[min=${min !== undefined ? min : 1}][for=${id}]`,
          spinnerCfg),
        m('.unit', attrs.unit));
  }
}

// +---------------------------------------------------------------------------+
// | Dropdown: wrapper around <select>. Supports single an multiple selection. |
// +---------------------------------------------------------------------------+

export interface DropdownAttrs {
  title: string;
  cssClass?: string;
  options: Map<string, string>;
  sort?: (a: string, b: string) => number;
  get: Getter<string[]>;
  set: Setter<string[]>;
}

export class Dropdown implements m.ClassComponent<DropdownAttrs> {
  resetScroll(dom: HTMLSelectElement) {
    // Chrome seems to override the scroll offset on creationa, b without this,
    // even though we call it after having marked the options as selected.
    setTimeout(() => {
      // Don't reset the scroll position if the element is still focused.
      if (dom !== document.activeElement) dom.scrollTop = 0;
    }, 0);
  }

  onChange(attrs: DropdownAttrs, e: Event) {
    const dom = e.target as HTMLSelectElement;
    const selKeys: string[] = [];
    for (let i = 0; i < dom.selectedOptions.length; i++) {
      const item = assertExists(dom.selectedOptions.item(i));
      selKeys.push(item.value);
    }
    const traceCfg = produce(globals.state.recordConfig, draft => {
      attrs.set(draft, selKeys);
    });
    globals.dispatch(Actions.setRecordConfig({config: traceCfg}));
  }

  view({attrs}: m.CVnode<DropdownAttrs>) {
    const options: m.Children = [];
    const selItems = attrs.get(globals.state.recordConfig);
    let numSelected = 0;
    const entries = [...attrs.options.entries()];
    const f = attrs.sort === undefined ? defaultSort : attrs.sort;
    entries.sort((a, b) => f(a[1], b[1]));
    for (const [key, label] of entries) {
      const opts = {value: key, selected: false};
      if (selItems.includes(key)) {
        opts.selected = true;
        numSelected++;
      }
      options.push(m('option', opts, label));
    }
    const label = `${attrs.title} ${numSelected ? `(${numSelected})` : ''}`;
    return m(
        `select.dropdown${attrs.cssClass || ''}[multiple=multiple]`,
        {
          onblur: (e: Event) => this.resetScroll(e.target as HTMLSelectElement),
          onmouseleave: (e: Event) =>
              this.resetScroll(e.target as HTMLSelectElement),
          oninput: (e: Event) => this.onChange(attrs, e),
          oncreate: (vnode) => this.resetScroll(vnode.dom as HTMLSelectElement),
        },
        m('optgroup', {label}, options));
  }
}


// +---------------------------------------------------------------------------+
// | Textarea: wrapper around <textarea>.                                      |
// +---------------------------------------------------------------------------+

export interface TextareaAttrs {
  placeholder: string;
  docsLink?: string;
  cssClass?: string;
  get: Getter<string>;
  set: Setter<string>;
  title?: string;
}

export class Textarea implements m.ClassComponent<TextareaAttrs> {
  onChange(attrs: TextareaAttrs, dom: HTMLTextAreaElement) {
    const traceCfg = produce(globals.state.recordConfig, draft => {
      attrs.set(draft, dom.value);
    });
    globals.dispatch(Actions.setRecordConfig({config: traceCfg}));
  }

  view({attrs}: m.CVnode<TextareaAttrs>) {
    return m(
        '.textarea-holder',
        m('header',
          attrs.title,
          attrs.docsLink && [' ', m(DocsChip, {href: attrs.docsLink})]),
        m(`textarea.extra-input${attrs.cssClass || ''}`, {
          onchange: (e: Event) =>
              this.onChange(attrs, e.target as HTMLTextAreaElement),
          placeholder: attrs.placeholder,
          value: attrs.get(globals.state.recordConfig)
        }));
  }
}

// +---------------------------------------------------------------------------+
// | CodeSnippet: command-prompt-like box with code snippets to copy/paste.    |
// +---------------------------------------------------------------------------+

export interface CodeSnippetAttrs {
  text: string;
  hardWhitespace?: boolean;
}

export class CodeSnippet implements m.ClassComponent<CodeSnippetAttrs> {
  view({attrs}: m.CVnode<CodeSnippetAttrs>) {
    return m(
        '.code-snippet',
        m('button',
          {
            title: 'Copy to clipboard',
            onclick: () => copyToClipboard(attrs.text),
          },
          m('i.material-icons', 'assignment')),
        m('code', attrs.text),
    );
  }
}


interface CategoriesCheckboxListParams {
  categories: Map<string, string>;
  title: string;
  get: Getter<string[]>;
  set: Setter<string[]>;
}

export class CategoriesCheckboxList implements
    m.ClassComponent<CategoriesCheckboxListParams> {
  updateValue(
      attrs: CategoriesCheckboxListParams, value: string, enabled: boolean) {
    const traceCfg = produce(globals.state.recordConfig, draft => {
      const values = attrs.get(draft);
      const index = values.indexOf(value);
      if (enabled && index === -1) {
        values.push(value);
      }
      if (!enabled && index !== -1) {
        values.splice(index, 1);
      }
    });
    globals.dispatch(Actions.setRecordConfig({config: traceCfg}));
  }

  view({attrs}: m.CVnode<CategoriesCheckboxListParams>) {
    const enabled = new Set(attrs.get(globals.state.recordConfig));
    return m(
        '.categories-list',
        m('h3',
          attrs.title,
          m('button.config-button',
            {
              onclick: () => {
                const config = produce(globals.state.recordConfig, draft => {
                  attrs.set(draft, Array.from(attrs.categories.keys()));
                });
                globals.dispatch(Actions.setRecordConfig({config}));
              }
            },
            'All'),
          m('button.config-button',
            {
              onclick: () => {
                const config = produce(globals.state.recordConfig, draft => {
                  attrs.set(draft, []);
                });
                globals.dispatch(Actions.setRecordConfig({config}));
              },
            },
            'None')),
        m('ul.checkboxes',
          Array.from(attrs.categories.entries()).map(([key, value]) => {
            const id = `category-checkbox-${key}`;
            return m(
                'label',
                {'for': id},
                m('li',
                  m('input[type=checkbox]', {
                    id,
                    checked: enabled.has(key),
                    onclick: (e: InputEvent) => {
                      const target = e.target as HTMLInputElement;
                      this.updateValue(attrs, key, target.checked);
                    }
                  }),
                  value));
          })));
  }
}
