<template>
  <v-card flat elevation="0">
    <v-card-title v-if="title">{{ title }}</v-card-title>
    <v-card-subtitle v-if="subtitle">{{ subtitle }}</v-card-subtitle>
    <v-card-text>

      <v-tabs v-model="viewTab">
        <v-tab>Text</v-tab>
        <v-tab>Parsed</v-tab>
      </v-tabs>

      <v-tabs-items v-model="viewTab">
        <v-tab-item>
          <v-simple-table dense class="text">
            <template v-slot:default>
              <colgroup v-if="showLineNumbers">
                <col class="line_no"/>
              </colgroup>
              <thead>
                <tr>
                  <th class="line_no">
                    <v-simple-checkbox
                      v-ripple
                      off-icon="mdi-format-list-numbered"
                      title="Show line numbers"
                      v-model="showLineNumbers"
                    >
                    </v-simple-checkbox>
                  </th>
                  <th v-for="(header, idx) in headers" :key="idx"
                    :style="`color:${header.colour};`"
                  >
                    {{ header.text }}
                  </th>
                </tr>
              </thead>
              <tbody>
                <tr v-for="(row, ridx) in rows" :key="ridx">
                  <td class="line_no"">
                    <small v-if="showLineNumbers">
                      {{ ridx + (typeof numberedLines == "number" ? numberedLines : 0)+1 }}
                    </small>
                  </td>
                  <td v-for="(cell, cidx) in row" :key="cidx"
                    :style="`background-color:${cell.colour};`"
                  >
                    {{ cell.text }}
                  </td>
                </tr>
              </tbody>
            </template>
          </v-simple-table>
        </v-tab-item>

        <v-tab-item>
          <!-- Parsed view -->
          <v-simple-table dense class="parsed">
            <template v-slot:default>
              <thead>
                <tr>
                  <th
                    title="The line along which the vessel will nominally sail"
                  >Sail line</th>
                  <th
                    title="Whether the line will be acquired in the incrementing or decrementing shot points direction"
                  >Direction</th>
                  <th
                    title="Whether the line is planned to be acquired. Some lines may be in the preplot but not intended to be shot in a particular campaign"
                  >Acquire?</th>
                  <th
                    title="The source lines that will be shot from this vessel line. Typically there is one source line per source array."
                  >Source lines</th>
                  <th
                    title="Any general remarks concerning this sail line (supports Markdown)"
                  >Remarks</th>
                </tr>
              </thead>
              <tbody>
                <tr v-for="(line, line_no) in saillines" :key="line_no">
                  <td>{{ line_no }}</td>
                  <td v-if="line.incr" title="Incrementing">▲</td>
                  <td v-else title="Decrementing">▼</td>
                  <td v-if="line.ntba" title="Not to be acquired" class="ko">✘</td>
                  <td v-else title="Line acquisition planned" class="ok">✔</td>
                  <td v-html="line.source_line.join('<br/>')"></td>
                  <td v-if="line['meta.colour']"
                    :style="`background-color:${line['meta.colour']};`"
                    v-html="$options.filters.markdown(line.remarks)"></td>
                  <td v-else
                    v-html="$options.filters.markdown(line.remarks)"></td>
                </tr>
              </tbody>
            </template>
          </v-simple-table>
        </v-tab-item>
      </v-tabs-items>

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

<style scoped>
/*.v-data-table table tbody tr td*/
.text th {
  border: 1px solid hsl(0, 0%, 33.3%);
}

.text td {
  border-inline: 1px solid hsl(0, 0%, 33.3%);
}

.parsed td {
  vertical-align: top;
}

.line_no {
  text-align: right;
  width: 4ex;
  border: none !important;
}

.ok {
  color: green;
}

.ko {
  color: red;
}
</style>

<script>
import { parse } from 'csv-parse/sync'
import { getHSLColourFor } from '@/lib/hsl'
import truncateText from '@/lib/truncate-text'

export default {
  name: "DougalSaillinesStringDecoder",

  components: {
  },

  props: {
    text: String,
    //fields: Object,
    //delimiter: String,
    headerRow: { type: [ Boolean, Number ], default: false},
    numberedLines: [ Boolean, Number ],
    maxHeight: String,
    editableFieldList: { type: Boolean, default: true },
    readonly: Boolean,
    title: String,
    subtitle: String
  },

  data () {
    return {
      delimiter: ",",
      showLineNumbers: null,
      text_: "",
      viewTab: null
    }
  },

  computed: {

    cells () {
      return parse(this.text_, {delimiter: this.delimiter, trim: true});
    },

    headers () {
      return this.cells[0]?.map(cell => ({
        text: cell,
        colour: this.getHSLColourFor(cell),
        backgroundColour: this.getHSLColourFor(cell, 0.2),
      })) ?? [];
    },

    rows () {
      return [...this.cells].slice(1).map(r =>
        r.map( (c, ι) => ({
          text: truncateText(c),
          colour: this.headers[ι]?.backgroundColour
        })));
    },

    /*
     * A saillines object looks like:
     *
     * {
     *  [sail_line]: {
     *    incr: true, // or false
     *    ntba: true, // or false
     *    remarks: "",
     *    source_line: [ 1000, 1001, …],
     *    "meta.colour": ""
     *  },
     *  …
     * }
     */
    saillines () {
      // Return an array of the column numbers
      // corresponding to `key`.
      // This file accepts duplicate column numbers,
      // notably for `source_line`.
      const key_indices = (key) =>
        this.headers.reduce( (acc, cur, ι) => {
          if (cur.text == key) {
            acc.push(ι)
          }
          return acc;
        }, []);

      // Properties of the sailline object
      const keys = [ "incr", "ntba", "remarks", "source_line", "meta.colour" ];

      function to_bool (v, missing=false) {
        return (v === undefined || v === null)
          ? missing // Missing value meaning
          : /^t(rue)|^[1-9-]+$/i.test(String(v).trim())
      }

      // To transform the input text into the required format for each field
      const transformer = (key) => {
        const transformers = {
          incr: (v) => to_bool(v, true),
          ntba: (v) => to_bool(v, false),
          remarks: (v) => (v === undefined || v === null) ? "" : String,
          source_line: Number,
        };
        return transformers[key] ?? String;
      };

      // This is the saillines object
      const lines = {};

      // The column numbers for each property
      const columns = keys.map( k => [ k, key_indices(k) ] );

      // The column number for the sail_line property, which
      // we use as a key.
      const sail_line_idx = key_indices("sail_line")[0];

      // Transform each line in the input file into a
      // sailline object (just for display purposes,
      // this is not exactly how the server will do it).
      for (const row of this.rows) {
        const sail_line = row[sail_line_idx]?.text;
        const values = columns.map(i => [
          i[0],
          i[0] == "source_line"
            ? i[1].map(idx => transformer(i[0])(row[idx]?.text))
            : transformer(i[0])(row[i[1][0]]?.text)
        ]);

        lines[sail_line] = Object.fromEntries(values);
      }

      return lines;
    }

  },

  watch: {

    text () {
      if (this.text != this.text_) {
        this.reset();
      }
    },

    numberedLines (cur, prev) {
      if (cur != prev) {
        this.showLineNumbers = typeof cur == "number" || cur;
      }
    }

  },

  methods: {


    getHSLColourFor: getHSLColourFor.bind(this),

    numberLine (number, line) {
      return `<span class="line-number">${number}</span>${line}`;
    },

    reset () {
      this.text_ = this.text.replaceAll("\r", "");
    }

  },

  mounted () {
    this.reset();
  }

}
</script>
