/*
 * Copyright (C) 2018 Robert Bosch GmbH Copyright (C) 2018 Robert Bosch Manufacturing Solutions GmbH, Germany. All rights reserved.
 */

import { BOSCH_DDS_COLORS } from '@bci-web-core/core';
import type { FeatureLike } from 'ol/Feature';
import LineString from 'ol/geom/LineString';
import MultiPoint from 'ol/geom/MultiPoint';
import Polygon from 'ol/geom/Polygon';
import { Circle as CircleStyle, Fill, Stroke, Style, Text } from 'ol/style';
import { StyleFunction } from 'ol/style/Style';
import { GeometryType } from './open-layers-model';

export class OpenLayersEditorStyleFactory {
  /**
   * zIndex of selected features. Not using Infinity here, so that other things can still be layered on top.
   */
  private readonly selectionZIndex = 99999999;

  selectionStyles(): StyleFunction | Style[] {
    const editorStyles = this.editingStylePerGeometryType();
    // without resolution-parameter, feature was not always a feature, but sometimes a resolution...
    
    return (feature: FeatureLike) => {
      const styles: Style[] = [];
      styles.push(...editorStyles[feature.getGeometry().getType()]);
      styles[0].setText(
        new Text({
          font: 'normal 15px "Bosch-Sans", "Arial", "sans-serif"',
          placement: 'point',
          textAlign: 'left',
          offsetY: 0,
          offsetX: 12,
          overflow: true,
          text: '',
          fill: new Fill({
            color: BOSCH_DDS_COLORS.boschBlue80,
          }),
          stroke: new Stroke({
            color: '#ffffff',
            width: 2,
          }),
        })
      );
      styles.push(new Style(this.polyVerticesStyleOptions()));
      return styles;
    };
  }

  polyVerticesStyleOptions() {
    return {
      image: new CircleStyle({
        radius: 4,
        fill: new Fill({
          color: BOSCH_DDS_COLORS.boschBlue80,
        }),
      }),
      zIndex: this.selectionZIndex,
      geometry: function (feature) {
        const geometry = feature.getGeometry();
        if (geometry instanceof Polygon) {
          // return the coordinates of the vertices of all rings of the polygon
          const coordinates = [].concat(...(<Polygon>geometry).getCoordinates());
          return new MultiPoint(coordinates);
        } else if (geometry instanceof LineString) {
          // return the coordinates of the vertices of all rings of the polygon
          const coordinates = [].concat((<LineString>geometry).getCoordinates());
          return new MultiPoint(coordinates);
        } else {
          return new MultiPoint([]);
        }
      },
    };
  }

  editingStylePerGeometryType(): { [K: string]: Style[] } {
    const styles = {};
    const white = BOSCH_DDS_COLORS.boschWhite;
    const blue = BOSCH_DDS_COLORS.boschBlue80;
    const width = 3;
    styles[GeometryType.POLYGON] = [
      new Style({
        fill: new Fill({
          color: [255, 255, 255, 0.5],
        }),
        zIndex: this.selectionZIndex,
      }),
    ];
    styles[GeometryType.MULTI_POLYGON] = styles[GeometryType.POLYGON];
    styles[GeometryType.LINE_STRING] = [
      new Style({
        stroke: new Stroke({
          color: white,
          width: width + 2,
        }),
        zIndex: this.selectionZIndex,
      }),
      new Style({
        stroke: new Stroke({
          color: blue,
          width: width,
        }),
        zIndex: this.selectionZIndex,
      }),
    ];
    styles[GeometryType.MULTI_LINE_STRING] = styles[GeometryType.LINE_STRING];
    styles[GeometryType.POINT] = [
      new Style({
        image: new CircleStyle({
          radius: width * 2,
          fill: new Fill({
            color: blue,
          }),
          stroke: new Stroke({
            color: white,
            width: width / 2,
          }),
        }),
        zIndex: this.selectionZIndex,
      }),
    ];
    styles[GeometryType.MULTI_POINT] = styles[GeometryType.POINT];
    styles[GeometryType.GEOMETRY_COLLECTION] = styles[GeometryType.POLYGON].concat(styles[GeometryType.POINT]);
    styles[GeometryType.POLYGON].push(...styles[GeometryType.LINE_STRING]);
    styles[GeometryType.CIRCLE] = styles[GeometryType.POLYGON];
    return styles;
  }
}
