<template>
  <div class="row items-baseline">
    <div class="col-xs-12 col-sm-auto text-weight-bold text-center q-px-md q-py-sm">
      <q-tooltip
          v-if=" $store.state.guiRuntime.safeFromWL > $store.state.simulationSetup.gui.nearFieldSetup.atWL ||
                 $store.state.guiRuntime.safeToWL < $store.state.simulationSetup.gui.nearFieldSetup.atWL "
          anchor="top middle" self="center middle"
          class="bg-amber-4 text-black shadow-4">
        Will use materials<br> spectrum range.
      </q-tooltip>
        <q-btn :loading="isRunning"
               :disable="isRunning||!isNmieLoaded"
               color="primary"
               no-caps
               :label="isNmieLoaded ? 'Run simulation' : 'Loading...'"
               @click="runNearFieldSimulation">
          <template #loading>
            <q-spinner-gears />
          </template>
        </q-btn>
    </div>
    <div class="col-xs-grow col-sm q-px-xs">
      <div class="row justify-xs-center justify-sm-start items-baseline">

        <div class="col-auto">
          <q-btn
              color="primary"
              no-caps
              @click="saveSpectrumSimulation"
          >Save</q-btn>
        </div>

      </div>
    </div>
  </div>
</template>

<script lang="ts">
import {computed, defineComponent, nextTick, watch} from 'vue'
import {useStore} from 'src/store'
import {getModeName, range, rangeInt} from 'components/utils'
import {cloneDeep} from 'lodash'
import {saveAs} from 'file-saver'
import {nearFieldPlane} from 'src/store/simulation-setup/state';


export default defineComponent({
  name: 'RunSimulationNearField',

  setup() {
    const $store = useStore()

    const isRunning = computed({
      get: ()=> $store.state.simulationSetup.nmies.nearField.isNmieRunning,
      set: val => {
        val ? $store.commit('simulationSetup/markNmieNearFieldAsStarted') : $store.commit('simulationSetup/markNmieNearFieldAsFinished')
      }
    })

    const isNmieLoaded = computed(()=>{ return $store.state.simulationSetup.nmies.nearField.instance })

    const atWL = computed(
        () => $store.state.simulationSetup.current.nearFieldSetup.atWL)
    //-------------------------------------------------------------------------//
    //---------------------  Main  --------------------------------------------//
    //-------------------------------------------------------------------------//
    function runNearFieldSimulation() {
      if (isRunning.value) {
        console.log('Some Nmie is already running!')
        return
      }
      isRunning.value = true
      void setTimeout(()=> {
        void nextTick(()=> {
          $store.commit('simulationSetup/copySetupFromGuiToCurrent')

          const host = $store.state.simulationSetup.current.hostIndex
          const plotSideResolution = $store.state.simulationSetup.current.nearFieldSetup.plotSideResolution
          const relativePlotSize = $store.state.simulationSetup.current.nearFieldSetup.relativePlotSize
          const crossSection = $store.state.simulationSetup.current.nearFieldSetup.crossSection
          try {
            if (!$store.state.simulationSetup.nmies.nearField.instance) throw 'ERROR! Scattnlay module was not loaded'
            const nmie = $store.state.simulationSetup.nmies.nearField.instance
            const layers = cloneDeep($store.state.simulationSetup.current.layers)
            const nmieStartedTime = performance.now()

            nmie.SetWavelength(atWL.value)
            nmie.ClearTarget()
            for (const layer of layers) {
              if (layer.material.nSpline) layer.n = layer.material.nSpline.at(atWL.value)
              if (layer.material.kSpline) layer.k = layer.material.kSpline.at(atWL.value)
              nmie.AddTargetLayerReIm(layer.layerWidth * host, layer.n / host, layer.k / host)
            }

            nmie.SetModeNmaxAndType(-1, -1)

            nmie.RunFieldCalculationCartesian(
                plotSideResolution,
                relativePlotSize,
                crossSection,
                0, 0, 0, 1
            )
            let Eabs_list = Array.from(nmie.GetFieldEabs())
            const Eabs = [];
            while (Eabs_list.length) Eabs.push(Eabs_list.splice(0, plotSideResolution));
            if (crossSection == nearFieldPlane.Ek) $store.commit('plotRuntime/setNearFieldEk', Eabs)
            if (crossSection == nearFieldPlane.Hk) $store.commit('plotRuntime/setNearFieldHk', Eabs)
            if (crossSection == nearFieldPlane.EH) $store.commit('plotRuntime/setNearFieldEH', Eabs)
            const nmieTotalRunTime = (performance.now() - nmieStartedTime) / 1000
            // console.log('Total simulation time:', nmieTotalRunTime, 's')
            $store.commit('simulationSetup/setNmieNearFieldTotalRunTime', nmieTotalRunTime)

          } catch (e) {
            console.log('Some error:', e)
          }
          isRunning.value = false
        })
      }, 100)
    }

    watch(isRunning, ()=>{
          console.log(isRunning.value)
    })

    // onActivated(()=>{
    //   if (isNmieLoaded.value) runNearFieldSimulation()
    // })



    return { isRunning, isNmieLoaded,
      runNearFieldSimulation,
      saveSpectrumSimulation(){
        const fileHeader = '# # You can open and plot this file using Python\n' +
            '# # (without manually removing this header, it will be skipped), see example below.\n' +
            '# import numpy as np\n' +
            '# from matplotlib import pyplot as plt\n' +
            '# data = np.genfromtxt(\'scattnlay-spectra.txt\', skip_header=21, names=True, delimiter=\', \')\n' +
            '# x = data[data.dtype.names[0]] # x-axis has units\n' +
            '# # Possible labels for spectrum data: Qsca, Qabs, Qext,\n' +
            '# # Qsca_E_dipole, etc. (see last comment before spectra data)\n' +
            '# a = data[\'Qsca\']\n' +
            '# b = data[\'Qsca_E_dipole\']\n' +
            '# c = data[\'Qsca_H_dipole\']\n' +
            '# \n' +
            '# plt.figure()\n' +
            '# plt.plot(x, a, label=\'Qsca\')\n' +
            '# plt.plot(x, b, label=\'Qsca E dipole\')\n' +
            '# plt.plot(x, c, label=\'Qsca H dipole\')\n' +
            '# plt.legend()\n' +
            '# plt.xlabel(data.dtype.names[0].replace(\'_\', \', \'))\n' +
            '# plt.ylabel(\'Normalized cross-sections\')\n' +
            '# plt.show()\n\n'
        let xTitle = 'x'
        if ( $store.state.plotRuntime.spectrumPlots.layout.xaxis ) {
          xTitle = String($store.state.plotRuntime.spectrumPlots.layout.xaxis.title)
        }

        let columnNames = '# ' + xTitle + ', Qsca, Qabs, Qext, '
        const mode_n = rangeInt($store.state.simulationSetup.current.numberOfModesToPlot, 1);
        const mode_types = range(0, 1);
        for (const n of mode_n) {
          for (const mode_type of mode_types) {
            const modeTypeName = mode_type == 0 ? 'E' : 'H'
            columnNames += 'Qsca_' + modeTypeName + '_' +getModeName(n)+', '
            columnNames += 'Qabs_' + modeTypeName + '_' +getModeName(n)+', '
            columnNames += 'Qext_' + modeTypeName + '_' +getModeName(n)+', '
          }
        }
        columnNames = columnNames.slice(0, -2)
        columnNames += '\n'
        let body = ''
        const WLs = $store.state.plotRuntime.WLsInUnits
        const Qsca = $store.state.plotRuntime.Qsca
        const Qabs = $store.state.plotRuntime.Qabs
        const Qext = $store.state.plotRuntime.Qext
        const Qsca_n = $store.state.plotRuntime.Qsca_n
        const Qabs_n = $store.state.plotRuntime.Qabs_n
        const Qext_n = $store.state.plotRuntime.Qext_n
        for (let i = 0; i < WLs.length; ++i) {
          let row = WLs[i].toString() + ', '
              + Qsca[i].toString() + ', '
              + Qabs[i].toString() + ', '
              + Qext[i].toString() + ', '
          for (const n of mode_n) {
            for (const mode_type of mode_types) {
              row += Qsca_n[mode_type][n - 1][i].toString() + ', '
              row += Qabs_n[mode_type][n - 1][i].toString() + ', '
              row += Qext_n[mode_type][n - 1][i].toString() + ', '
            }
          }
          row = row.slice(0, -2)
          row += '\n'
          body += row
        }

        const scattnlaySpectra = new Blob([fileHeader+columnNames+body],
            {type: 'text/plain;charset=utf-8',
              endings: 'native'}  //TODO test if newline is correctly written in Windows, MacOS
        )
        saveAs(scattnlaySpectra, 'scattnlay-spectra.txt');
      }
    }
  },
})
</script>
