<template>
  <v-container fluid>

    <v-card>
      <v-card-title>
        <v-progress-linear indeterminate v-if="loading"></v-progress-linear>
        <v-toolbar flat>
          <v-toolbar-title>
            <template v-if="$route.params.sequence">
              <v-btn icon small
                :disabled="sequenceIndex >= (sequences.length - 1)"
                :to="{name: 'shotlog', params: { sequence: (sequences[sequences.length-1]||{}).sequence }}"
                title="Go to the first sequence"
              >
                <v-icon dense>mdi-chevron-double-left</v-icon>
              </v-btn>
              <v-btn icon small
                :disabled="sequenceIndex >= (sequences.length - 1)"
                :to="{name: 'shotlog', params: { sequence: (sequences[sequenceIndex+1]||{}).sequence }}"
                title="Go to the previous sequence"
              >
                <v-icon dense>mdi-chevron-left</v-icon>
              </v-btn>
            </template>

            Sequence {{sequenceNumber}}
            <small :class="statusColour" v-if="sequence">({{sequence.status}})</small>

            <template v-if="$route.params.sequence">
              <v-btn icon small
                :disabled="sequenceIndex==0"
                :to="{name: 'shotlog', params: { sequence: (sequences[sequenceIndex-1]||{}).sequence }}"
                title="Go to the next sequence"
              >
                <v-icon dense>mdi-chevron-right</v-icon>
              </v-btn>
              <v-btn icon small class="mr-1"
                :disabled="sequenceIndex==0"
                :to="{name: 'shotlog', params: { sequence: (sequences[0]||{}).sequence }}"
                title="Go to the last sequence"
              >
                <v-icon dense>mdi-chevron-double-right</v-icon>
              </v-btn>
            </template>
          </v-toolbar-title>

          <a v-if="$route.params.sequence"
            :href="`/projects/${$route.params.project}/log/sequence/${$route.params.sequence}`"
            title="View the event log for this sequence"
          >
            <v-icon
              right
              color="blue"
            >mdi-format-list-bulleted-type</v-icon>
          </a>

          <v-spacer></v-spacer>
          <v-text-field
            v-model="filter"
            append-icon="mdi-magnify"
            label="Filter shots"
            single-line
            clearable
            hint="Filter by point, line, time, etc."
            ></v-text-field>
        </v-toolbar>
      </v-card-title>
      <v-card-text>

        <v-container fluid>
          <v-row>
            <v-col cols="6" class="pa-0">
              <v-card outlined tile height="100%" class="flex-grow-1">
                <v-card-subtitle>
                  Acquisition remarks
                </v-card-subtitle>
                <v-card-text v-html="$options.filters.markdown(remarks)">
                </v-card-text>
              </v-card>
            </v-col>
            <v-col cols="6" class="pa-0">
              <v-card outlined tile height="100%" class="flex-grow-1">
                <v-card-subtitle>
                  Processing remarks
                </v-card-subtitle>
                <v-card-text v-html="$options.filters.markdown(remarks_final)">
                </v-card-text>
              </v-card>
            </v-col>
          </v-row>

          <template v-if="sequence">
          <v-row>
            <v-col v-for="(col, idx) in infoColumns" :key="idx" cols="3">
              <b :title="col.title">{{col.text}}:</b> {{ col.value }}
            </v-col>
          </v-row>
          </template>

          <v-row>
            <v-col cols=12 md=6 lg=4>
              <div style="height:300px;">
                <dougal-graph-project-sequence-inline-crossline
                  :items="shots"
                  gun-data-format="smsrc"
                  facet="2dhist"
                >
                </dougal-graph-project-sequence-inline-crossline>
              </div>
            </v-col>

            <v-col cols=12 md=6 lg=4>
              <div style="height:300px;">
                <dougal-graph-project-sequence-inline-crossline
                  :items="shots"
                  gun-data-format="smsrc"
                  facet="crossline"
                >
                </dougal-graph-project-sequence-inline-crossline>
              </div>
            </v-col>

            <v-col cols=12 md=6 lg=4>
              <div ref="" style="height:300px;">
                <dougal-graph-project-sequence-shotpoint-timing
                  :items="shots"
                  facet="area"
                >
                </dougal-graph-project-sequence-shotpoint-timing>
              </div>
            </v-col>

            <v-col cols=12 md=6 lg=4 >
              <div ref="" style="height:300px;">
                <dougal-graph-project-sequence-inline-crossline
                  v-if="sequence && (sequence.status == 'final' || sequence.status == 'pending')"
                  :items="shots"
                  facet="c-o"
                >
                </dougal-graph-project-sequence-inline-crossline>
              </div>
            </v-col>
          </v-row>

        </v-container>

        <v-card outlined tile class="flex-grow-1">
          <v-card-subtitle>
            Shot log
          </v-card-subtitle>
          <v-card-text>

            <v-data-table
              :headers="shotlogHeaders"
              :items="shots"
              item-key="point"
              :search="filter"
              :custom-sort="customSorter"
              fixed-header
              show-expand
              @click:row="onRowClicked"
            >

              <template v-slot:item.position="{item}">
                <a v-if="position(item).latitude"
                  :href="`/projects/${$route.params.project}/map#z15x${position(item).longitude}y${position(item).latitude}:+seqrp;+psll:${position(item).longitude},${position(item).latitude}:S${String(item.sequence).padStart(3, '0')} ${item.point}`"
                  title="View on map"
                  :target="`/projects/${$route.params.project}/map`"
                  @click.stop
                >
                  <small>{{ format_position(position(item)) }}</small>
                </a>
              </template>

              <template v-slot:item.ε_inline="{item}">
                {{ ε(item).inline }}
              </template>

              <template v-slot:item.ε_crossline="{item}">
                {{ ε(item).crossline }}
              </template>

              <template v-slot:item.co_inline="{item}">
                {{ co(item).inline }}
              </template>

              <template v-slot:item.co_crossline="{item}">
                {{ co(item).crossline }}
              </template>

              <template v-slot:expanded-item="{ headers, item }">
                <td :colspan="headers.length" class="pa-0">
                  <v-card flat>
                    <v-card-subtitle>Gun data</v-card-subtitle>
                    <v-card-text v-if="item.meta.raw.smsrc">
                      <v-container>
                        <v-row>
                          <v-col>
                            Source fired: {{ gun_data(item).src_number }}
                          </v-col>
                          <v-col>
                            Subarrays: {{ gun_data(item).num_subarray }}
                          </v-col>
                          <v-col>
                            Total guns: {{ gun_data(item).num_guns }}
                          </v-col>
                          <v-col>
                            Active guns: {{ gun_data(item).num_active }}
                          </v-col>
                          <v-col>
                            Autofires: {{ gun_data(item).num_auto }}
                          </v-col>
                          <v-col>
                            No fires: {{ gun_data(item).num_nofire }}
                          </v-col>
                        </v-row>
                        <v-row>
                          <v-col>
                            Average delta: {{ gun_data(item).avg_delta }} ±{{ gun_data(item).std_delta }} ms
                          </v-col>
                          <v-col>
                            Delta errors: {{ gun_data(item).num_delta }}
                          </v-col>
                          <v-col>
                            Source volume: {{ gun_data(item).volume }} in³
                          </v-col>
                          <v-col>
                            Manifold pressure: {{ gun_data(item).manifold }} psi
                          </v-col>
                          <v-col>
                            Mask: {{ gun_data(item).mask }}
                          </v-col>
                          <v-col>
                            Trigger mode: {{ gun_data(item).trg_mode }}
                          </v-col>
                        </v-row>
                        <v-row>
                          <v-col cols=12>
                            <v-expansion-panels>
                              <v-expansion-panel>
                                <v-expansion-panel-header>
                                  Individual gun data
                                </v-expansion-panel-header>
                                <v-expansion-panel-content>
                                  <v-simple-table>
                                    <template v-slot:default>
                                      <thead>
                                        <th>String</th>
                                        <th>Gun</th>
                                        <th>Source</th>
                                        <th>Mode</th>
                                        <th>Detect</th>
                                        <th>Autofire</th>
                                        <th>Aimpoint</th>
                                        <th>Fire time</th>
                                        <th>Delay</th>
                                        <th>Depth</th>
                                        <th>Pressure</th>
                                        <th>Volume</th>
                                        <th>Filltime</th>
                                      </thead>
                                      <tbody>
                                        <tr v-for="(gun_values, idx_gun) in gun_data(item).guns"
                                          :key="idx_gun"
                                        >
                                          <td v-for="(val, idx) in gun_values" v-if="idx != 6"
                                            :key="idx"
                                            :class="typeof val === 'number' ? 'text-right' : 'text-left'"
                                          >{{ gun_value_formatter(val, idx) }}</td>
                                        </tr>
                                      </tbody>
                                    </template>
                                  </v-simple-table>
                                </v-expansion-panel-content>
                              </v-expansion-panel>
                            </v-expansion-panels>
                          </v-col>
                        </v-row>
                      </v-container>
                    </v-card-text>
                    <v-card-text v-else>
                      No gun data available
                    </v-card-text>
                  </v-card>
                </td>
              </template>


            </v-data-table>

          </v-card-text>
        </v-card>

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

<script>
import { mapActions, mapGetters } from 'vuex';
import DougalGraphProjectSequenceInlineCrossline from '@/components/graphs/project/sequence/inline-crossline';
import DougalGraphProjectSequenceShotpointTiming from '@/components/graphs/project/sequence/shotpoint-timing';

export default {
  name: "SequenceSummary",

  components: {
    DougalGraphProjectSequenceInlineCrossline,
    DougalGraphProjectSequenceShotpointTiming
  },

  data () {
    return {
      filter: null,
      loading: false,
      shotlogHeaders: [
        {
          value: "point",
          text: "Point",
          sort: this.sorterFor("point", this.number_sort)
        },
        {
          value: "sailline",
          text: "Sail line",
          sort: this.sorterFor("sailline", this.number_sort)
        },
        {
          value: "line",
          text: "Source line",
          sort: this.sorterFor("line", this.number_sort)
        },
        {
          value: "tstamp",
          text: "Timestamp",
          sort: this.sorterFor("tstamp", this.string_sort)
        },
        {
          value: "position",
          text: "φ, λ",
          sort: this.sorterFor(["geometryfinal", "geometryraw", "geometrypreplot"],
                               this.sorterFor("coordinates",
                                              this.sequentialSort([0, 1], this.number_sort)))
        },
        {
          value: "ε_inline",
          text: "ε inline",
          align: "end",
          sort: this.sorterFor(["errorfinal", "errorraw"],
                               this.sorterFor("coordinates",
                                              this.sorterFor(1, this.number_sort)))
        },
        {
          value: "ε_crossline",
          text: "ε crossline",
          align: "end",
          sort: this.sorterFor(["errorfinal", "errorraw"],
                               this.sorterFor("coordinates",
                                              this.sorterFor(0, this.number_sort)))
        },
        {
          value: "co_inline",
          text: "c-o inline",
          align: "end",
          sort: (a, b) => this.number_sort(this.co(a).inline, this.co(b).inline)
        },
        {
          value: "co_crossline",
          text: "c-o crossline",
          align: "end",
          sort: (a, b) => this.number_sort(this.co(a).crossline, this.co(b).crossline)
        },
        {
          value: 'data-table-expand'
        },
      ],
      shots: []
    };
  },

  computed: {
    sequenceNumber () {
      return this.$route.params.sequence;
    },

    sequence () {
      return this.sequences.find(i => i.sequence == this.sequenceNumber);
    },

    sequenceIndex () {
      if ("sequence" in this.$route.params) {
        const index = this.sequences.findIndex( i => i.sequence == this.$route.params.sequence );
        if (index != -1) {
          return index;
        }
      }
      // return undefined
    },

    remarks () {
      return this.sequence?.remarks || "Nil.";
    },

    remarks_final () {
      return this.sequence?.remarks_final || "Nil.";
    },

    statusColour () {
      switch (this.sequence?.status) {
        case "final":
          return "green--text";
        case "raw":
          return "orange--text";
        case "ntbp":
          return "red--text";
        default:
          return "";
      }
    },

    infoColumns () {
      return [
        {
          text: "FSP",
          title: "First shotpoint",
          value: this.sequence.fsp ?? "n/a"
        },
        {
          text: "FPSP",
          title: "First prime shotpoint",
          value: this.sequence.fsp_final ?? "n/a"
        },
        {
          text: "LPSP",
          title: "Last prime shotpoint",
          value: this.sequence.lsp_final ?? "n/a"
        },
        {
          text: "LSP",
          title: "Last shotpoint",
          value: this.sequence.lsp ?? "n/a"
        },
        {
          text: "Start time",
          value: this.sequence.ts0,
        },
        {
          text: "FPSP time",
          title: "First prime shotpoint time",
          value: this.sequence.ts0_final ?? "n/a",
        },
        {
          text: "LPSP time",
          title: "Last prime shotpoint time",
          value: this.sequence.ts1_final ?? "n/a",
        },
        {
          text: "End time",
          value: this.sequence.ts1,
        },
        {
          text: "Length",
          value: this.sequence.length.toFixed(0)+" m"
        },
        {
          text: "Azimuth",
          value: this.sequence.azimuth.toFixed(4).padStart(8, "0")+"°"
        },
        {
          text: "Shots acquired",
          value: this.sequence.num_points
        },
        {
          text: "Shots missed",
          value: this.sequence.missing_shots
        },
        {
          text: "Total duration",
          value: this.format_duration(this.sequence.duration)
        },
        {
          text: "Prime duration",
          value: this.format_duration(this.sequence.duration_final) ?? "n/a"
        }

      ];
    },

    ...mapGetters(["sequencesLoading", "sequences"])
  },

  watch: {

    sequencesLoading () {
      this.loading == this.loading || this.sequencesLoading;
    },

    sequence () {
      this.getSequence();
    }

  },

  methods: {

    /** Apply fn to a[keys], b[keys]
     *
     * If keys is an array, use the first
     * attribute that exists in each of a
     * and b (may not be the same attribute)
     */
    sorterFor (keys, fn) {
      if (Array.isArray(keys)) {
        return (a, b) => fn(a[keys.find(k => k in a)], b[keys.find(k => k in b)]);
      } else {
        return (a, b) => fn(a[keys], b[keys]);
      }
    },

    /** Apply fn to each member of keys
     * until the comparison returns non-zero.
     */
    sequentialSort (keys, fn) {
      return (a, b) => {
        for (const key of keys) {
          const res = fn(a[key], b[key]);
          if (res != 0) {
            return res;
          }
        }
        return 0;
      }
    },

    number_sort (a, b) {
      return a - b;
    },

    string_sort (a, b) {
      return a > b
        ? 1
        : a < b
          ? -1
          : 0;
    },

    customSorter (items, sortBy, sortDesc) {

      /** Get the sorter for a given column from shotlogHeaders
       */
      const getFieldSorter = (key) => {
        return this.shotlogHeaders.find(i => i.value == key)?.sort;
      }

      /** Conditionally invert a comparator
       */
      function inverter (fn, desc) {
        return desc
          ? (a, b) => fn(a, b) * -1
          : fn;
      }

      for (const idx in sortBy) {
        const sortKey = sortBy[idx];
        const desc = sortDesc[idx];

        const fn = inverter(getFieldSorter(sortKey), desc);

        items.sort(fn);
      }

      return items;
    },

    onRowClicked (data, row) {
      row.expand(!row.isExpanded);
    },

    async getSequence (seq = this.sequence) {

      // NOTE:
      // We are intentionally not using Vuex here, given that at this time
      // no other component (except Graphs?) this endpoint's data.
      // NB: Graphs does use this endpoint but there doesn't seem to be
      // any point in keeping the data in memory anyway in case the user
      // decides to navigate from the shotlog to the graphs or vice-versa.

      try {
        this.loading = true;
        const url = `/project/${this.$route.params.project}/sequence/${this.$route.params.sequence}`;
        this.shots = await this.api([url])
      } catch {
      } finally {
        this.loading = false;
      }
    },

    format_duration (duration) {
      if (duration) {
        let t = ["hours", "minutes", "seconds"].map(k =>
          (duration[k] ?? 0).toFixed(0).padStart(2, "0")).join(":");

        if (duration.days) {
          t = duration.days+" d "+t;
        }

        return t;
      }
    },

    format_position (position) {
      return `${position.latitude.toFixed(6).padStart(9, "0")}, ${position.longitude.toFixed(6).padStart(10, "0")}`;
    },

    position (item) {
      const coords = (item.geometryfinal ?? item.geometryraw)?.coordinates;
      if (coords) {
        return {
          longitude: coords[0],
          latitude: coords[1]
        };
      }
      return {};
    },

    ε (item) {
      const coords = (item.errorfinal ?? item.errorraw)?.coordinates;
      if (coords) {
        return {
          crossline: coords[0]?.toFixed(2),
          inline: coords[1]?.toFixed(2)
        }
      }
      return {};
    },

    co (item) {
      const raw = item.errorraw?.coordinates;
      const final = item.errorfinal?.coordinates;
      if (raw && final) {
        return {
          crossline: (final[0] - raw[0]).toFixed(2),
          inline: (final[1] - raw[1]).toFixed(2),
        }
      } else {
        return {
          crossline: "n/a",
          inline: "n/a"
        }
      }
    },

    gun_data (item) {
      return item?.meta?.raw?.smsrc ?? {};
    },

    gun_value_formatter (value, index) {
      const ms = (v) => v.toFixed(2)+" ms";
      const transformers = [];
      transformers[7] = ms;
      transformers[8] = ms;
      transformers[9] = ms;
      transformers[10] = (v) => v.toFixed(1)+" m";
      transformers[11] = (v) => v+" psi";
      transformers[12] = (v) => v+" in³";
      transformers[13] = ms;

      const transformer = transformers[index];
      return transformer ? transformer(value) : value;
    },

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

  mounted () {
    this.getSequence();
  }

}

</script>
