<template>
  <div ref="graph"
    class="graph-container"
  ></div>
</template>

<style scoped>
.graph-container {
  width: 100%;
  height: 100%;
}
</style>

<script>
import Plotly from 'plotly.js-dist';
import unpack from '@/lib/unpack.js';

export default {
  name: "DougalGraphProjectSequenceShotpointTiming",

  props: {
    items: Array,
    gunDataFormat: { type: String, default: "smsrc" },
    facet: { type: String, default: "bars" }
  },

  data () {
    return {
      plotted: false,
      resizeObserver: null
    };
  },

  computed: {

    config () {
      return {
        editable: false,
        displaylogo: false,
        responsive: true
      };
    },

    layout () {
      return {
        font: {
          color: this.$vuetify.theme.isDark ? "#fff" : undefined
        },
        title: {text: "Shotpoint timing %{data[0].meta.subtitle}"},
        xaxis: {
          title: "Shotpoint"
        },
        yaxis: {
          title: "Time (s)"
        },
        plot_bgcolor:"rgba(0,0,0,0)",
        paper_bgcolor:"rgba(0,0,0,0)",
        autosize: true
      };
    },

    data () {

      const items = this.items.map(i => {
        return {
          point: i.point,
          tstamp: new Date(i.tstamp)
        }
      }).sort( (a, b) => a.tstamp - b.tstamp );
      const x = [...unpack(items, "point")];
      const y = items.map( (i, idx, ary) => (ary[idx+1]?.tstamp - i.tstamp)/1000 );
      const src_number = unpack(this.items, ["meta", "raw", this.gunDataFormat, "src_number"]);

      // We're dealing with intervals not points
      x.pop(); y.pop(); src_number.pop();

      const meta = {};

      const stats = this.stats(x, y, src_number);

      // We need to do the subtitle here rather than in layout as layout knows nothing
      // about the number of arrays

      if (stats.src_ids.length == 1) {
        meta.subtitle = `<span style="font-size:smaller;">(μ = ${stats.avg.all.toFixed(2)} ±${stats.std.all.toFixed(2)} s)</span>`;
      } else {
        meta.subtitle = `<span style="font-size:smaller;">(μ = ${stats.avg.all.toFixed(2)} ±${stats.std.all.toFixed(2)} s)</span>`;
        const per_source = [];
        for (const key in stats.avg) {
          if (key == "all") continue;
          const s = `μ<sub>${key}</sub> = ${stats.avg[key].toFixed(2)} ±${stats.std[key].toFixed(2)} s`;
          per_source.push(s);
        }
        meta.subtitle += `<br><span style="font-size:smaller;">` + per_source.join("; ") + "</span>";
      }


      const trace0 = {
        type: "bar",
        x,
        y,
        transforms: [{
          type: "groupby",
          groups: src_number,
          styles: [
            {value: {showlegend: false}},
            {target: 1, value: {line: {color: "green"}}},
            {target: 2, value: {line: {color: "red"}}},
            {target: 3, value: {line: {color: "blue"}}}
          ]
        }],
        meta
      };

      switch (this.facet) {
        case "lines":
          trace0.type = "scatter";
          break;
        case "area":
          trace0.type = "scatter";
          trace0.fill = "tozeroy";
          break;
        case "bars":
        default:
          // Nothing
      }

      return [trace0]
    }
  },

  watch: {
    items (cur, prev) {
      if (cur != prev) {
        this.plot();
      }
    },

    "$vuetify.theme.isDark" () {
      this.plot();
    }
  },

  methods: {

    plot () {
      if (this.items?.length) {
        Plotly.newPlot(this.$refs.graph, this.data, this.layout, this.config);
        this.plotted = true;
      } else {
        Plotly.purge(this.$refs.graph);
        this.plotted = false;
      }
    },

    replot () {
      if (this.plotted) {
        const ref = this.$refs.graph;
        if (ref && ref.clientWidth > 0 && ref.clientHeight > 0) {
          Plotly.relayout(ref, {
            width: ref.clientWidth,
            height: ref.clientHeight
          });
        }
      }
    },

    stats (x, y, src_number) {
      const avg = {};
      const std = {};

      const avg_all = (y.reduce((acc, cur) => acc + cur, 0) / y.length);
      const std_all = Math.sqrt(y.reduce((acc, cur) => (cur-avg_all)**2 + acc, 0) / y.length);

      avg.all = avg_all;
      std.all = std_all;

      const src_ids = new Set(src_number);

      for (const src of src_ids) {
        // Ignore shots without source data
        if (!src) continue;

        const v = y.filter((i, idx) => src_number[idx] == src);
        const μ = (v.reduce((acc, cur) => acc + cur, 0) / v.length);
        const σ = Math.sqrt(v.reduce((acc, cur) => (cur-μ)**2 + acc, 0) / v.length);
        avg[src] = μ;
        std[src] = σ;
      }

      return { avg, std, src_ids };
    }

  },

  mounted () {
    this.$nextTick( () => {
      if (this.items?.length) {
        this.plot();
      }
      this.resizeObserver = new ResizeObserver(this.replot)
      this.resizeObserver.observe(this.$refs.graph);
    });
  },

  beforeDestroy () {
    if (this.resizeObserver) {
      this.resizeObserver.unobserve(this.$refs.graph);
    }
  }

}

</script>
