<template>
  <div>
    <demap
      class="changeMap"
      ref="demap"
      :center="[10.52673, 52.26594]"
      :zoom="5"
      @set-roi="setRoi"
      @unset-roi="unsetRoi"
      @layer-added="onLayerAdded"
    />
    <v-overlay absolute :value="cordexMaskOverlay">
      <v-card class="pa-2" width="450px">
        <v-card-title>Cordex Mask Generation</v-card-title>
        <v-card-subtitle v-if="cordexMaskOverlay"
          >Select cordex domain for mask generation<br />
          Selected layer: <b>{{ selectedCordexVectorLayer.get('title') }}</b>
        </v-card-subtitle>
        <v-card-text>
          <v-select
            :items="cordexDomains"
            :disabled="cordexMaskRequestPending"
            label="selected codex domain"
            persistent-hint
            prepend-icon="public"
            v-model="selectedCordexDomain"
            @change="resetCordexMaskData"
          ></v-select>

          <v-checkbox
            v-model="clipMaskToRoi"
            :disabled="cordexMaskRequestPending"
            label="Clip mask to geometry"
          ></v-checkbox>

          <v-alert v-if="cordexMaskAddedToMap" dense type="warning">
            Due to missing projection support, the shown mask is only an
            <strong>approximation</strong>.
          </v-alert>
          <v-alert
            v-if="cordexMaskErrorMessage.length > 0"
            dense
            type="error"
            v-text="cordexMaskErrorMessage"
          />
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn small @click="closeCordexMaskDialog"> Close </v-btn>
          <v-btn
            v-if="hasCordexMaskData()"
            small
            color="primary"
            @click="addMaskToMap"
            :disabled="cordexMaskAddedToMap || true"
            ><v-icon>layers</v-icon>Add to Map</v-btn
          >
          <v-btn
            v-if="hasCordexMaskData()"
            small
            color="primary"
            @click="downloadCordexMask"
            ><v-icon>download</v-icon>Download</v-btn
          >
          <v-btn
            v-else
            :disabled="!backendModule.isConnected()"
            small
            color="primary"
            :loading="cordexMaskRequestPending"
            @click="requestCordexMask"
          >
            <v-icon>miscellaneous_services</v-icon>Generate Mask
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-overlay>
  </div>
</template>

<style scoped>
.changeMap {
  width: 100%;
  height: 600px;
}
</style>


<script lang="ts">
import axios from 'axios';
import Demap from 'dasf-web/lib/map/Demap.vue';
import { Component, Vue, Ref, Prop } from 'vue-property-decorator';
import VectorLayer from 'ol/layer/Vector.js';
import Geometry from 'ol/geom/Geometry';
import { Layer, Tile as TileLayer } from 'ol/layer';
import { XYZ } from 'ol/source';
import {
  WorkflowSettingsObserver,
  userSetting,
} from 'dasf-web/lib/model/UserSetting';
import { ChangeWorkflowSettings } from './model/ChangeWorkflowSettings';
import DemapLegend from 'dasf-web/lib/map/legend/DemapLegend.vue';
import LayerGroup from 'ol/layer/Group';
import { createDefaultRoiAction, DemapLayerAction } from 'dasf-web/lib/map/legend/DemapLayerActions';
import LayerUtils from 'dasf-web/lib/map/utils/LayerUtils';
import BackendModule from './model/ChangeModuleMessaging';
import VectorSource from 'ol/source/Vector';
import GeoJSON from 'ol/format/GeoJSON.js';
import NetcdfRasterSource from 'dasf-web/lib/map/model/NetcdfRasterSource';
import b64a from 'base64-arraybuffer';
import TemporalImageLayer from 'dasf-web/lib/map/model/TemporalImageLayer';

@Component({
  components: { Demap },
})
export default class ChangeMap extends Vue {
  name = 'changemap';

  @Prop({ type: String, required: true }) workflowName!: string;
  @Prop({ type: ChangeWorkflowSettings, required: true })
  wfSettings!: ChangeWorkflowSettings;

  cordexMaskOverlay = false;
  readonly cordexDomains: string[] = [
    'EUR-11',
    'EUR-44',
    'SAM-44',
    'CAM-44',
    'NAM-44',
    'AFR-44',
    'WAS-44',
    'EAS-44',
    'CAS-44',
    'AUS-44',
    'ANT-44',
    'ARC-44',
    'MED-44',
    'MNA-44',
    'MNA-22',
    'EUR-11',
    'SEA-22',
  ];

  backendModule = BackendModule;
  selectedCordexDomain = this.cordexDomains[0];
  selectedCordexVectorLayer!: VectorLayer;
  cordexMaskRequestPending = false;
  cordexMaskAddedToMap = false;
  cordexMaskArrayBuffer!: ArrayBuffer;
  cordexMaskErrorMessage = '';
  clipMaskToRoi = true;

  @Ref('demap') readonly demap!: Demap;

  public mounted() {
    this.addAdditionalBaseLayer();
  }

  protected addAdditionalBaseLayer(): void {
    let esriLayer: TileLayer = new TileLayer({
      source: new XYZ({
        attributions:
          'Tiles © <a href="https://services.arcgisonline.com/ArcGIS/' +
          'rest/services/World_Topo_Map/MapServer">ArcGIS</a>',
        url:
          'https://server.arcgisonline.com/ArcGIS/rest/services/' +
          'World_Topo_Map/MapServer/tile/{z}/{y}/{x}',
      }),
    });
    esriLayer.set('title', 'esri');

    this.demap.addBaseLayer(esriLayer);
  }

  //@Override from IDemapAction
  public itemSelected(feature): void {
    // let wfSet = userSetting.getWorkflowSettings(
    //   this.workflowName
    // ) as ChangeWorkflowSettings;
    console.log('map item selected');
    console.log(feature);
  }

  loadCustomFile(file: File): void {
    // throw new Error('Method not implemented.');
    console.warn('Unsupported file: ' + file.name);
  }

  public setRoi(roi: Geometry): void {
    console.log('changemap roi set', roi);
    this.wfSettings.roiWgs84 = roi;
  }

  public unsetRoi(): void {
    this.wfSettings.roiWgs84 = undefined;
  }

  public addAsRoi(layerTitle: string, layerUrl: string): void {
    // load data from url
    axios.get(layerUrl).then((response) => {
      // parse data and create vector source
      let src: VectorSource = new VectorSource({
        features: new GeoJSON().readFeatures(response.data, {
          dataProjection: 'EPSG:4326',
          featureProjection: 'EPSG:3857',
        }),
      });

      // init roi action
      let roiAction: DemapLayerAction = createDefaultRoiAction(
        this.demap.setRoi,
        this.demap.unsetRoi
      );

      // create layer from source
      let layer: VectorLayer = Demap.createVectorLayer(layerTitle, src, [roiAction]);

      // add layer to map
      this.demap.addLayer(layer);

      // trigger roi action
      roiAction.trigger(layer, null);
    });
  }

  public clearLayers() {
    // remove roi
    this.demap.unsetRoi()
    this.demap.getThematicLayerGroup().getLayers().clear();
  }

  protected onLayerAdded(layer: Layer): void {
    console.log('on layer added');
    if (Demap.isVectorLayer(layer)) {
      // we just added a new vector layer - add the cordex mask option
      let maskAction: DemapLayerAction = new DemapLayerAction();
      maskAction.actionId = 'Mask';
      maskAction.label = 'Mask';
      maskAction.icon = 'photo_filter';
      maskAction.tooltip = 'Create Cordex Mask';
      maskAction.predicate = (
        actionId: string,
        layer: Layer,
        group: LayerGroup
      ): boolean => {
        return LayerUtils.containsGeometry(layer, ['Polygon', 'MultiPolygon']);
      };
      maskAction.action = (
        action: DemapLayerAction,
        layer: Layer,
        group: LayerGroup
      ) => {
        console.log('trigger cordex mask for layer', layer);
        this.selectedCordexVectorLayer = layer as VectorLayer;
        this.cordexMaskOverlay = true;
      };

      layer.get('actions').push(maskAction);
    }
  }

  protected hasCordexMaskData(): boolean {
    return this.cordexMaskArrayBuffer != null;
  }

  protected resetCordexMaskData(): void {
    this.cordexMaskArrayBuffer = undefined;
    this.cordexMaskRequestPending = false;
    this.cordexMaskAddedToMap = false;
    this.cordexMaskErrorMessage = '';
  }

  protected closeCordexMaskDialog(): void {
    this.resetCordexMaskData();
    this.selectedCordexVectorLayer = undefined;
    this.cordexMaskOverlay = false;
  }

  protected requestCordexMask(): void {
    // convert layer feature to geojson
    let roiGeometry: Geometry = LayerUtils.extractGeometryFromLayer(
      this.selectedCordexVectorLayer
    );
    this.cordexMaskRequestPending = true;
    BackendModule.sendCordexMaskRequest(
      roiGeometry,
      this.selectedCordexDomain,
      this.clipMaskToRoi,
      (status: string, data: string) => {
        console.log('received cordex mask ', status);
        this.cordexMaskRequestPending = false;

        if (status == 'success') {
          this.cordexMaskArrayBuffer = b64a.decode(data);
        } else {
          // there was an error - show the error message
          this.cordexMaskErrorMessage = data;
          this.cordexMaskArrayBuffer = undefined;
        }
      }
    );
  }

  protected downloadCordexMask(): void {
    let filename: string = this.selectedCordexVectorLayer.get('title');
    filename = filename.toLowerCase();
    filename += '_cordex_mask_' + this.selectedCordexDomain + '.nc';
    LayerUtils.downloadAsNetcdf(this.cordexMaskArrayBuffer, filename);
  }

  protected addMaskToMap(): void {
    NetcdfRasterSource.create({ data: this.cordexMaskArrayBuffer }).then(
      (src: NetcdfRasterSource) => {
        let imageLayer = new TemporalImageLayer({
          title:
            this.selectedCordexVectorLayer.get('title') +
            ' (cordex mask: ' +
            this.selectedCordexDomain +
            ')',
          source: src,
        });
        this.demap.addLayer(imageLayer);
        this.cordexMaskAddedToMap = true;
      }
    );
  }
}
</script>