<template>
  <v-container fluid>
    <v-card>
      <v-card-title>
        <v-toolbar flat>
          <v-toolbar-title>Preplots</v-toolbar-title>
          <v-spacer></v-spacer>
          <v-text-field
            v-model="filter"
            append-icon="mdi-magnify"
            label="Filter"
            single-line
            clearable
            hint="Filter by line number, first or last shotpoint or remarks. Use ‘incr’ or ‘+’ / ‘decr’ or ‘-’ to show only incrementing / decrementing lines"
            ></v-text-field>
        </v-toolbar>
      </v-card-title>
      <v-card-text>

        <v-menu v-if="writeaccess()"
          v-model="contextMenuShow"
          :position-x="contextMenuX"
          :position-y="contextMenuY"
          absolute
          offset-y
        >
          <v-list dense v-if="contextMenuItem">
            <template v-if="!selectOn">
              <v-list-item @click="setNTBA" v-if="contextMenuItem.ntba || (contextMenuItem.num_points == contextMenuItem.na)">
                <v-list-item-title v-if="contextMenuItem.ntba"
                  title="Mark the line as part of the acquisition plan"
                >Unset NTBA</v-list-item-title>
                <v-list-item-title v-else
                  title="Mark the line as not to be acquired"
                >Set NTBA</v-list-item-title>
              </v-list-item>
              <v-list-item @click="setComplete" v-if="contextMenuItem.na && (contextMenuItem.num_points != contextMenuItem.na || contextMenuItem.tba != contextMenuItem.na)">
                <v-list-item-title v-if="contextMenuItem.tba != contextMenuItem.na"
                  title="Mark any remaining points as pending acquisition"
                >Unset line complete</v-list-item-title>
                <v-list-item-title v-else
                  title="Mark any remaining points as not to be acquired"
                >Set line complete</v-list-item-title>
              </v-list-item>
              <v-list-item @click="addToPlan" v-if="!contextMenuItem.ntba && !isPlanned(contextMenuItem)">
                <v-list-item-title>Add to plan</v-list-item-title>
              </v-list-item>
              <v-list-item @click="removeFromPlan" v-if="isPlanned(contextMenuItem)">
                <v-list-item-title>Remove from plan</v-list-item-title>
              </v-list-item>
              <v-list-item @click="showLineColourDialog">
                <v-list-item-title>Set colour…</v-list-item-title>
              </v-list-item>
            </template>
            <template v-else>
              <v-list-item @click="showLineColourDialog">
                <v-list-item-title>Set colour…</v-list-item-title>
              </v-list-item>
            </template>
            <v-divider></v-divider>
            <v-list-item>
              <v-list-item-action-text>Multi-select</v-list-item-action-text>
              <v-list-item-action><v-checkbox v-model="selectOn"></v-checkbox></v-list-item-action>
            </v-list-item>
          </v-list>
        </v-menu>

        <v-dialog
          v-model="colourPickerShow"
          max-width="300"
        >
          <v-card>
            <v-card-title>Choose line colour</v-card-title>
            <v-card-text>
              <v-color-picker
                v-model="selectedColour"
                show-swatches
                hide-canvas
                hide-inputs
                hide-mode-switch
                @update:color="selectedColour.alpha = 0.5"
              >
              </v-color-picker>
            </v-card-text>
            <v-card-actions>
              <v-btn small
                @click="selectedColour=null; setLineColour()"
              >
                Clear
              </v-btn>
              <v-spacer></v-spacer>
              <v-btn small
                @click="setLineColour"
              >
                Set
              </v-btn>
              <v-spacer></v-spacer>
              <v-btn small
                @click="colourPickerShow=false"
              >
                Cancel
              </v-btn>
            </v-card-actions>
          </v-card>
        </v-dialog>

        <v-data-table
        :headers="headers"
        :items="items"
        :items-per-page.sync="itemsPerPage"
        :server-items-length="lineCount"
        item-key="line"
        :search="filter"
        :loading="linesLoading"
        :options.sync="options"
        fixed-header
        :footer-props='{itemsPerPageOptions: [ 10, 25, 50, 100, 500, -1 ], showFirstLastPage: true}'
        :item-class="itemClass"
        :show-select="selectOn"
        v-model="selectedRows"
        @click:row="setActiveItem"
        @contextmenu:row="contextMenu"
        >

          <template v-slot:item.status="{item}">
            <dougal-line-status
              :preplot="item"
              :sequences="sequences.filter(s => s.line == item.line)"
              :sequence-href="(s) => `/projects/${$route.params.project}/log/sequence/${s.sequence}`"
              :planned-sequences="plannedSequences.filter(s => s.line == item.line)"
              :planned-sequence-href="() => `/projects/${$route.params.project}/plan`"
              :pending-reshoots="null"
              :pending-reshoot-href="null"
            >
              <template v-slot:empty>
                <div v-if="!item.ntba" class="sequence" title="Virgin"></div>
                <div v-else class="sequence ntba" title="Not to be acquired"><span>NTBA</span></div>
              </template>
            </dougal-line-status>
          </template>

          <template v-slot:item.tba="{item, value}">
            <span :class="!value && (item.na ? 'warning--text' : 'success--text')">{{ value }}</span>
          </template>

          <template v-slot:item.length="props">
            <span>{{ Math.round(props.value) }} m</span>
          </template>

          <template v-slot:item.azimuth="props">
            <span>{{ props.value.toFixed(2) }} °</span>
          </template>

          <template v-slot:item.remarks="{item}">
            <v-text-field v-if="edit && edit.line == item.line && edit.key == 'remarks'"
              type="text"
              v-model="edit.value"
              prepend-icon="mdi-restore"
              append-outer-icon="mdi-content-save-edit-outline"
              clearable
              @click:prepend="edit.value = item.remarks; edit = null"
              @click:append-outer="edit = null"
            >
            </v-text-field>
            <div v-else>
              <span v-html="$options.filters.markdownInline(item.remarks)"></span>
              <v-btn v-if="writeaccess() && edit === null"
                icon
                small
                title="Edit"
                :disabled="linesLoading"
                @click="editItem(item, 'remarks')"
              >
                <v-icon small>mdi-square-edit-outline</v-icon>
              </v-btn>
            </div>

          </template>

        </v-data-table>

      </v-card-text>
    </v-card>
  </v-container>
</template>

<style lang="stylus" scoped>
.ntba
    background-image repeating-linear-gradient(-45deg, #ff00004d, #ff000080 10px, #d3d3d31a 10px, #d3d3d314 20px)
    cursor not-allowed
    display flex
    align-items center
    justify-content center
</style>

<script>
import { mapActions, mapGetters } from 'vuex';
import DougalLineStatus from '@/components/line-status';
import AccessMixin from '@/mixins/access';

export default {
  name: "LineList",

  components: {
    DougalLineStatus
  },

  mixins: [
    AccessMixin
  ],

  data () {
    return {
      headers: [
        {
          value: "line",
          text: "Line"
        },
        {
          value: "status",
          text: "Status"
        },
        {
          value: "fsp",
          text: "FSP",
          align: "end"
        },
        {
          value: "lsp",
          text: "LSP",
          align: "end"
        },
        {
          value: "num_points",
          text: "Points",
          align: "end"
        },
        {
          value: "na",
          text: "Virgin",
          align: "end"
        },
        {
          value: "tba",
          text: "Remaining",
          align: "end"
        },
        {
          value: "length",
          text: "Length",
          align: "end"
        },
        {
          value: "azimuth",
          text: "Azimuth",
          align: "end"
        },
        {
          value: "remarks",
          text: "Remarks"
        }
      ],
      items: [],
      selectOn: false,
      selectedRows: [],
      filter: "",
      options: {},
      lineCount: null,
      //sequences: [],
      activeItem: null,
      edit: null, // {line, key, value}
      queuedReload: false,
      itemsPerPage: 25,

      // Context menu stuff
      contextMenuShow: false,
      contextMenuX: 0,
      contextMenuY: 0,
      contextMenuItem: null,

      // Colour picker stuff
      colourPickerShow: false,
      selectedColour: null,
      styles: null
    }
  },

  computed: {
    ...mapGetters(['user', 'linesLoading', 'lines', 'sequences', 'plannedSequences'])
  },

  watch: {

    options: {
      handler () {
        this.fetchLines();
      },
      deep: true
    },

    async lines () {
      await this.fetchLines();
    },

    async edit (newVal, oldVal) {
      if (newVal === null && oldVal !== null) {
        const item = this.items.find(i => i.line == oldVal.line);

        // Get around this Vuetify ‘feature’
        // https://github.com/vuetifyjs/vuetify/issues/4144
        if (oldVal.value === null) oldVal.value = "";

        if (item && item[oldVal.key] != oldVal.value) {
          if (await this.saveItem(oldVal)) {
            item[oldVal.key] = oldVal.value;
          } else {
            this.edit = oldVal;
          }
        }
      }
    },

    filter (newVal, oldVal) {
      if (newVal?.toLowerCase() != oldVal?.toLowerCase()) {
        this.fetchLines();
      }
    },

    itemsPerPage (newVal, oldVal) {
      localStorage.setItem(`dougal/prefs/${this.user?.name}/${this.$route.params.project}/${this.$options.name}/items-per-page`, newVal);
    },

    user (newVal, oldVal) {
      this.itemsPerPage = Number(localStorage.getItem(`dougal/prefs/${this.user?.name}/${this.$route.params.project}/${this.$options.name}/items-per-page`)) || 25;
    }

  },

  methods: {

    itemClass (item) {

      const colourClass = item.meta.colour ? "bg-clr-"+item.meta.colour.slice(1) : null;
      if (colourClass && ![...this.styles.cssRules].some(i => i.selectorText == "."+colourClass)) {
        const rule = `.${colourClass} { background-color: ${item.meta.colour}; }`;
        this.styles.insertRule(rule);
      }

      return [
        item.meta.colour ? colourClass : "",
        (this.activeItem == item && !this.edit) ? 'blue accent-1 elevation-3' : ''
      ];
    },

    isPlanned(item) {
      return this.sequences.find(i => i.line == item.line && i.status == 'planned');
    },

    contextMenu (e, {item}) {
      e.preventDefault();
      this.contextMenuShow = false;
      this.contextMenuX = e.clientX;
      this.contextMenuY = e.clientY;
      this.contextMenuItem = item;
      this.$nextTick( () => this.contextMenuShow = true );
    },

    setNTBA () {
      this.removeFromPlan();
      this.saveItem({
        line: this.contextMenuItem.line,
        key: 'ntba',
        value: !this.contextMenuItem.ntba
      })
    },

    setComplete () {
      this.saveItem({
        line: this.contextMenuItem.line,
        key: 'complete',
        value: this.contextMenuItem.na && this.contextMenuItem.tba == this.contextMenuItem.na
      })
    },

    async addToPlan () {
      const payload = {
        sequence: null,
        line: this.contextMenuItem.line,
        fsp: this.contextMenuItem.fsp,
        lsp: this.contextMenuItem.lsp
      }
      const url = `/project/${this.$route.params.project}/plan`;
      const init = {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: payload
      }
      await this.api([url, init]);
    },

    async removeFromPlan () {
      const plannedLine = this.sequences.find(i => i.status == "planned" && i.line == this.contextMenuItem.line);
      if (plannedLine && plannedLine.sequence) {
        const url = `/project/${this.$route.params.project}/plan/${plannedLine.sequence}`;
        const init = {
          method: "DELETE"
        }
        await this.api([url, init]);
      }
    },

    showLineColourDialog () {
      this.selectedColour = this.contextMenuItem.meta.colour
        ? {hexa: this.contextMenuItem.meta.colour}
        : null;
      this.colourPickerShow = true;
    },

    setLineColour () {
      const items = this.selectOn ? this.selectedRows : [ this.contextMenuItem ];
      const colour = this.selectedColour ? this.selectedColour.hex+"80" : null;

      this.selectedRows = [];
      this.selectOn = false;

      for (const item of items) {
        if (colour) {
          item.meta.colour = colour;
        } else {
          delete item.meta.colour;
        }
        this.saveItem({line: item.line, key: "meta", value: item.meta});
        this.colourPickerShow = false;
      }
    },

    editItem (item, key) {
      this.edit = {
        line: item.line,
        key,
        value: item[key]
      }
    },

    async saveItem (edit) {
      if (!edit)  return;

      try {
        const url = `/project/${this.$route.params.project}/line/${edit.line}`;
        const init = {
          method: "PATCH",
          body: {
            [edit.key]: edit.value
          }
        };

        let res;
        await this.api([url, init, (e, r) => res = r]);
        return res && res.ok;
      } catch (err) {
        return false;
      }
    },

    setActiveItem (item) {
      this.activeItem = this.activeItem == item
        ? null
        : item;
    },


    async fetchLines (opts = {}) {
      const options = {
        text: this.filter,
        ...this.options
      };
      const res = await this.getLines([this.$route.params.project, options]);
      this.items = res.lines;
      this.lineCount = res.count;
    },

    ...mapActions(["api", "getLines"])
  },

  mounted () {
    this.fetchLines();

    // Initialise stylesheet
    const el = document.createElement("style");
    document.head.appendChild(el);
    this.styles = document.styleSheets[document.styleSheets.length-1];
  }

}

</script>
