<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: "DougalGraphProjectSequenceInlineCrossline",

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

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

  computed: {

    config () {
      switch (this.facet) {
        case "scatter":
        default:
          return {
            editable: false,
            displaylogo: false,
            responsive: true
          };
      }
    },

    layout () {
      const base = {
        font: {
          color: this.$vuetify.theme.isDark ? "#fff" : undefined
        },
        autosize: true
      };

      switch (this.facet) {
        case "scatter":
          return {
            ...base,
            autocolorscale: true,
            title: {text: `Preplot deviation <span style="font-size:smaller;">(x̅: %{data[0].meta.avg_x} ±%{data[0].meta.std_x} m; y̅: %{data[0].meta.avg_y} ±%{data[0].meta.std_y} m)</span>`},
            xaxis: {
              title: "Crossline (m)"
            },
            yaxis: {
              title: "Inline (m)"
            },
            plot_bgcolor:"rgba(0,0,0,0)",
            paper_bgcolor:"rgba(0,0,0,0)"
          };

        case "crossline":
          return {
            ...base,
            autocolorscale: true,
            title: {text: `Crossline deviation <span style="font-size:smaller;">(x̅: %{data[0].meta.avg_x} ±%{data[0].meta.std_x} m)</span>`},
            xaxis: {
              title: "Shotpoint"
            },
            yaxis: {
              title: "Crossline (m)"
            },
            plot_bgcolor:"rgba(0,0,0,0)",
            paper_bgcolor:"rgba(0,0,0,0)"
          };

        case "2dhist":
          return {
            ...base,
            showlegend: true,
            title: {text: `Preplot deviation <span style="font-size:smaller;">(x̅: %{data[0].meta.avg_x} ±%{data[0].meta.std_x} m; y̅: %{data[0].meta.avg_y} ±%{data[0].meta.std_y} m)</span>`},
            xaxis: {
              title: "Crossline (m)",
              showgrid: true,
              zeroline: true
            },
            yaxis: {
              title: "Inline (m)",
              showgrid: true,
              zeroline: true
            },
            plot_bgcolor:"rgba(0,0,0,0)",
            paper_bgcolor:"rgba(0,0,0,0)"
          };

        case "c-o":
          return {
            ...base,
            showlegend: true,
            title: {
              text: this.data[0]?.x?.length
                ? `Final vs raw <span style="font-size:smaller;">(x̅: %{data[0].meta.avg_x} ±%{data[0].meta.std_x} m; y̅: %{data[0].meta.avg_y} ±%{data[0].meta.std_y} m)</span>`
                : `Final vs raw: no data`
            },
            xaxis: {
              title: "Crossline (m)",
              showgrid: true,
              zeroline: true
            },
            yaxis: {
              title: "Inline (m)",
              showgrid: true,
              zeroline: true
            },
            plot_bgcolor:"rgba(0,0,0,0)",
            paper_bgcolor:"rgba(0,0,0,0)"
          };
      }
    },

    data () {
      if (!this.items?.length) {
        return [];
      }

      let x, y, avg_x, avg_y, std_x, std_y;

      const items = this.items.sort( (a, b) => a.point - b.point );
      const meta = unpack(items, "meta");
      const src_number = unpack(unpack(unpack(meta, "raw"), this.gunDataFormat), "src_number");

      if (this.facet == "c-o") {
        const _items = items.filter(i => i.errorfinal && i.errorraw);
        const εf = unpack(unpack(_items, "errorfinal"), "coordinates");
        const εr = unpack(unpack(_items, "errorraw"), "coordinates");

        x = εf.map( (f, idx) => f[0] - εr[idx][0] )
        y = εf.map( (f, idx) => f[1] - εr[idx][1] )

      } else {
        const coords = unpack(unpack(items, ((row) => row?.errorfinal ? row.errorfinal : row.errorraw)), "coordinates");

        x = unpack(coords, 0);
        y = unpack(coords, 1);


      }

      // No chance of overflow
      avg_x = (x.reduce((acc, cur) => acc + cur, 0) / x.length).toFixed(2);
      avg_y = (y.reduce((acc, cur) => acc + cur, 0) / y.length).toFixed(2);
      std_x = Math.sqrt(x.reduce((acc, cur) => (cur-avg_x)**2 + acc, 0) / x.length).toFixed(2);
      std_y = Math.sqrt(y.reduce((acc, cur) => (cur-avg_y)**2 + acc, 0) / y.length).toFixed(2);

      if (this.facet == "scatter") {

        const data = [{
          type: "scatter",
          mode: "markers",
          x,
          y,
          meta: { avg_x, avg_y, std_x, std_y},
          transforms: [{
            type: "groupby",
            groups: src_number,
            styles: [
              {target: 1, value: {line: {color: "green"}}},
              {target: 2, value: {line: {color: "red"}}},
              {target: 3, value: {line: {color: "blue"}}}
            ]
          }],
        }];

        return data;

      } else if (this.facet == "crossline") {

        const s = unpack(items, "point");

        const data = [{
          type: "scatter",
          x: s,
          y: x,
          meta: { avg_x, avg_y, std_x, std_y},
          _transforms: [{
            type: "groupby",
            groups: src_number,
            styles: [
              {target: 1, value: {line: {color: "green"}}},
              {target: 2, value: {line: {color: "red"}}},
              {target: 3, value: {line: {color: "blue"}}}
            ]
          }],
        }];

        return data;

      } else if (this.facet == "2dhist" || this.facet == "c-o") {

        const bottomValue = this.$vuetify.theme.isDark
          ? ['0.0', 'rgba(0,0,0,0)']
          : ['0.0', 'rgb(165,0,38)'];
        const topValue = this.$vuetify.theme.isDark
          ? ['1.0', 'rgb(49,54,149)']
          : ['1.0', 'rgba(0,0,0,0)'];

          const colourscale = this.facet == "c-o"
            ? [bottomValue, [0.1, 'rgb(0,0,0)'], [0.9, 'rgb(255,255,255)'], topValue]
            : [
              bottomValue,
              ['0.111111111111', 'rgb(215,48,39)'],
              ['0.222222222222', 'rgb(244,109,67)'],
              ['0.333333333333', 'rgb(253,174,97)'],
              ['0.444444444444', 'rgb(254,224,144)'],
              ['0.555555555556', 'rgb(224,243,248)'],
              ['0.666666666667', 'rgb(171,217,233)'],
              ['0.777777777778', 'rgb(116,173,209)'],
              ['0.888888888889', 'rgb(69,117,180)'],
              topValue
            ];

        const data = [{
          type: "histogram2dcontour",
          ncontours: 20,
          colorscale: colourscale,
          showscale: false,
          reversescale: !this.$vuetify.theme.isDark,
          contours: {
            coloring: this.facet == "c-o" ? "fill" : "heatmap",
          },
          x,
          y,
          meta: { avg_x, avg_y, std_x, std_y}
        }];

        return data;

      }
    }
  },

  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
          });
        }
      }
    }

  },

  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>
