<template>
  <div class="color-picker">
    <div class="form-control" @click="showPopup" ref="popup-anchor" :readonly="readonly">
      <template v-if="!multi && valueCopy">
        <picker-value :ondelete="() => (valueCopy = null)" :can-delete="!required">
          <component :is="itemComponent" :item="indexedItems[valueCopy]"></component>
        </picker-value>
      </template>

      <template v-if="multi">
        <draggable :list="valueCopy" :disabled="readonly">
          <picker-value
            v-for="(id, index) in valueCopy"
            :key="index"
            :ondelete="() => valueCopy.splice(index, 1)"
            :can-delete="!readonly && (!required || valueCopy.length > 1)"
            class="multi"
          >
            <component :is="itemComponent" :item="indexedItems[id]"></component>
          </picker-value>
        </draggable>
      </template>
    </div>

    <popup ref="popup" overflow>
      <div>
        <div :class="type" v-for="(item, key) in items" :key="key">
          <label>
            <input
              type="radio"
              v-if="!multi"
              v-model="valueCopy"
              :value="item.id"
              :name="'radio' + _uid"
              @focus="scrollPopup"
              @keydown.down.prevent="down"
              @keydown.up.prevent="up"
              @keydown.enter.prevent="$event.target.click()"
            />

            <input
              type="checkbox"
              v-if="multi"
              v-model="valueCopy"
              :value="item.id"
              :name="'radio' + _uid"
              @focus="scrollPopup"
              @keydown.down.prevent="down"
              @keydown.up.prevent="up"
              @keydown.enter.prevent="$event.target.click()"
            />
            <component :is="itemComponent" :item="item"></component>
          </label>
        </div>
      </div>
    </popup>
  </div>
</template>

<style lang="scss" scoped>
// inspiration from relation-picker
.color-picker {
  position: relative;
  user-select: none;
}

.form-control {
  padding: 1px 4px;
  display: flex;
  min-height: 38px;
  height: auto;
  flex-wrap: wrap;
}
</style>

<script lang="ts">
import _orderBy from 'lodash/orderBy';
import { Component, Prop, Ref, Vue } from 'vue-property-decorator';
import { ValueSync } from '../../tools/decorators';
import { Enum, SchemaProperty } from '../../types/api';
import popup from '../popup.vue';
import colorPickerItem from './color-picker-item.vue';
import pickerValue from '../picker-value.vue';

interface ColorItem {
  id: string;
  hexColor: string;
  displayName: string;
}

@Component({
  components: {
    colorPickerItem,
    popup,
    pickerValue
  }
})
export default class ColorPicker extends Vue {
  @ValueSync('value', { type: [Array, String, Number] }) valueCopy!: Array<string> | string;
  @Prop() readonly schema!: SchemaProperty;
  @Prop({ default: false }) readonly required!: boolean;
  @Prop({ default: false }) readonly readonly!: boolean;
  @Ref('popup') readonly popup!: typeof popup;

  get multi(): boolean {
    return this.schema.type === 'array';
  }

  get type(): string {
    return this.multi ? 'checkbox' : 'radio';
  }

  get items(): ColorItem[] {
    const options = this.multi ? this.schema.items!.options : this.schema.options;
    const orderedOptions = _orderBy(options, 'order');

    return orderedOptions.map(
      (color: Enum): ColorItem => ({
        id: color.key,
        hexColor: '#' + (color.value | 0x1000000).toString(16).substr(1),
        displayName: color.displayName || color.key
      })
    );
  }

  get itemComponent() {
    return this.$options.components!.colorPickerItem;
  }

  get indexedItems() {
    const indexedItems: { [key: string]: {} } = {};

    this.items.forEach((item: ColorItem) => {
      indexedItems[item.id] = item;
    });
    return indexedItems;
  }

  // scrollPopup is copied form relation-picker, added a few ! for Typescript to make it work... No time to refactor this magic
  scrollPopup(evt: FocusEvent) {
    const inputEl = evt.target as HTMLInputElement;
    const el = inputEl!.parentElement;
    const elBcr = el!.getBoundingClientRect();
    for (var anc = el!.parentElement; anc!.offsetHeight == anc!.scrollHeight; anc = anc!.parentElement) {
      // do nothing
    }
    var scrollBcr = anc!.getBoundingClientRect();
    var scollbarSize = anc!.offsetHeight - anc!.clientHeight;
    var bottom = scrollBcr.bottom - scollbarSize;
    if (elBcr.bottom > bottom) {
      anc!.scrollTop += elBcr!.bottom - bottom;
    } else if (elBcr.top < scrollBcr.top) {
      anc!.scrollTop += elBcr.top - scrollBcr.top;
    }
  }

  showPopup(): void {
    if (!this.readonly) {
      this.popup.show(this.$refs['popup-anchor']);
    }
  }
}
</script>
