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

import { Feature } from 'ol';
import { Style } from 'ol/style';
import { StyleFunction } from 'ol/style/Style';
import { LsLocation } from '../model/lsLocation';
import { LocationMetadata, LocationStyle } from './location-style.service';

/**
 * Location style with information about when to apply it and handling of labels and the zIndex of the location's features.
 */
export class LocationStyleCustomized implements LocationStyle {
  applies: (location: LsLocation, metadata: LocationMetadata) => boolean;
  private _style: StyleFunction;

  get style() {
    return this._style;
  }

  set style(value: StyleFunction | Style | Style[]) {
    this._style = this.customizeStyle(value);
  }

  constructor(featureStyle: StyleFunction | Style | Style[], properties?: Partial<LocationStyleCustomized>) {
    this.style = featureStyle;
    if (!!properties) {
      Object.assign(this, properties);
    }
  }

  isMarker: () => boolean = () => false;

  showLabel: (feature: Feature, resolution: number) => boolean = () => true;

  getLabel: (feature: Feature) => string | undefined = (feature: Feature) => feature.get('label');

  getZIndex: (feature: Feature) => number | undefined = (feature: Feature) => feature.get('zIndex');

  private customizeStyle(appliedStyle: StyleFunction | Style | Style[]): StyleFunction {
    return (feature: Feature, resolution: number) => {
      let styleInstances: Style | Style[] | void;
      if (appliedStyle instanceof Function) {
        styleInstances = (appliedStyle as StyleFunction)(feature, resolution);
      } else {
        styleInstances = appliedStyle;
      }

      if (styleInstances instanceof Style) {
        this.applyTextLabel(this, styleInstances, feature, resolution);
        this.applyZIndex(this, styleInstances, feature);
      } else if (styleInstances instanceof Array) {
        this.applyTextLabel(this, styleInstances[0], feature, resolution);
        styleInstances.forEach((styleInstance) => this.applyZIndex(this, styleInstance, feature));
      }
      return styleInstances;
    };
  }

  private applyZIndex(locationStyle: LocationStyleCustomized, styleInstance: Style, feature: Feature) {
    const zIndex = locationStyle.getZIndex(feature);
    if (zIndex !== undefined) {
      styleInstance.setZIndex(zIndex);
    }
  }

  private applyTextLabel(
    locationStyle: LocationStyleCustomized,
    styleInstance: Style,
    feature: Feature,
    resolution: number
  ) {
    const label = locationStyle.showLabel(feature, resolution) ? locationStyle.getLabel(feature) : undefined;
    const textStyle = styleInstance.getText();
    if (!!textStyle && !locationStyle.isMarker()) {
      textStyle.setText(label);
    }
  }
}
