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

import { Injectable } from '@angular/core';
import { BOSCH_DDS_COLORS } from '@bci-web-core/core';
import { Style } from 'ol/style';
import { StyleFunction } from 'ol/style/Style';
import { OpenLayersEditorStyleFactory } from '../../generic-maps/open-layers-map/open-layers-editor-style-factory';
import { OpenLayersStyleFactory } from '../../generic-maps/open-layers-map/open-layers-style-factory';
import { LsLocation } from '../model/lsLocation';
import { LocationStyleCustomized } from './location-style-customized';

/**
 * Metadata of a location required to identify a matching style.
 */
export interface LocationMetadata {
  isSelected: boolean;
}

export interface LocationStyle {
  /**
   * Whether it is applicable for a location and its metadata.
   * @param location The location to style.
   * @param metadata The locations metadata.
   * @return true if so.
   */
  applies: (location: LsLocation, metadata: LocationMetadata) => boolean;

  /**
   * The style to apply to the feature.
   */
  style: StyleFunction | Style | Style[];
}

/**
 * Service to manage styles for locations.
 */
@Injectable()
export class LocationStyleService {
  readonly selectionStyle = new OpenLayersEditorStyleFactory().selectionStyles();
  readonly locationStyleDefault = this.createPlainLocationStyle(BOSCH_DDS_COLORS.boschGray40, 50, 0.1);
  protected locationStyles: LocationStyle[] = [];
  protected fallbackStyles: LocationStyle[] = [];

  constructor() {
    this.fallbackStyles.push(
      new LocationStyleCustomized(this.selectionStyle, {
        applies: (location, metadata) => metadata.isSelected,
        getZIndex: () => undefined, // keep original selection style zIndex
      }),
      new LocationStyleCustomized(this.locationStyleDefault, {
        applies: () => true,
      })
    );
  }

  /**
   * Get matching style for a location and its metadata.
   * @param location The location to style.
   * @param metadata The location's metadata.
   * @returns Its feature's style.
   */
  getStyle(location: LsLocation, metadata: LocationMetadata): StyleFunction | Style | Style[] {
    const matchedStyle = this.locationStyles.find((locationStyle) => locationStyle.applies(location, metadata));
    if (!!matchedStyle) {
      return matchedStyle.style;
    } else {
      return this.fallbackStyles.find((locationStyle) => locationStyle.applies(location, metadata)).style;
    }
  }

  protected createPlainLocationStyle(hexColor: string, zIndex: number, alpha: number) {
    const hexAlpha = ('0' + Math.floor(alpha * 255).toString(16)).slice(-2);
    const tempStyle = OpenLayersStyleFactory.featureStyle(
      hexColor,
      hexColor,
      hexColor + hexAlpha // hex rgba only work in chrome and ff!
    );
    tempStyle.setZIndex(zIndex);
    return tempStyle;
  }
}
