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

import { AfterViewInit, Component, OnDestroy, ViewChild } from '@angular/core';
import { OpenLayersLayerFactory, OpenLayersMapComponent, OpenLayersStyleFactory } from '@bci-web-core/maps';
import { Feature } from 'ol';
import { Coordinate } from 'ol/coordinate';
import { Point } from 'ol/geom';
import { fromLonLat, toLonLat } from 'ol/proj';
import { Style, Fill, Stroke, Circle as CircleStyle, Text } from 'ol/style';
import { BOSCH_ICONS } from '@bci-web-core/common-styles/fonts/bosch-ic';
import { BOSCH_DDS_COLORS } from '@bci-web-core/core';

interface IAnimated {
  update: () => void;
}

class Satellite implements IAnimated {
  startTimestamp: number;

  constructor(public center: Coordinate, public radius: number, public offsetDeg: number, private point: Point) {
    this.startTimestamp = new Date().getTime();
  }

  update(): void {
    const ageInMs = new Date().getTime() - this.startTimestamp;
    const periodInMs = 30000;
    const phase = ((ageInMs % periodInMs) / periodInMs + this.offsetDeg / 360) * 2 * Math.PI;

    // set satellite position using translation and rotation
    this.point.setCoordinates(fromLonLat([this.center[0], this.center[1]]));
    this.point.translate(this.radius, 0);
    this.point.rotate(phase, fromLonLat(this.center));
  }
}

@Component({
  selector: 'bci-light-dark-theme',
  templateUrl: './light-dark-theme.component.html',
  styleUrls: ['./light-dark-theme.component.scss'],
})
export class LightDarkThemeComponent implements OnDestroy, AfterViewInit {
  @ViewChild(OpenLayersMapComponent) map: OpenLayersMapComponent;

  theme = 'dark';

  private destroy = false;
  private animatedObjects: IAnimated[] = [];

  constructor(private openLayersLayerFactory: OpenLayersLayerFactory) {}

  ngOnDestroy(): void {
    this.destroy = true;
  }

  ngAfterViewInit(): void {
    const animatedFeatures = [];
    const staticFeatures = [];

    //// earth and satellites
    for (let i = 1; i <= 1000; i++) {
      const satellitePoint = new Point(fromLonLat([0, 0]));
      const satelliteFeature = new Feature(satellitePoint);
      const satelliteStyle = new Style({
        text: new Text(
          OpenLayersStyleFactory.boschFontIconOptions(BOSCH_ICONS.BoschIcSatellite, BOSCH_DDS_COLORS.boschGray80)
        ),
      });
      satelliteFeature.setStyle(satelliteStyle);
      animatedFeatures.push(satelliteFeature);
      this.animatedObjects.push(
        new Satellite(toLonLat(this.map.center), 1000000 + 10000 * i, 10 * i - (1 * i) / 10, satellitePoint)
      );
    }

    const earthFeature = new Feature(new Point(fromLonLat([0, 0])));
    earthFeature.setStyle(
      new Style({
        image: new CircleStyle({
          fill: new Fill({ color: BOSCH_DDS_COLORS.boschBlue50 }),
          radius: 30,
        }),
        text: new Text(<any>{
          ...OpenLayersStyleFactory.boschFontIconOptions(
            BOSCH_ICONS.BoschIcWorldFrame,
            BOSCH_DDS_COLORS.boschGreen50,
            true,
            80
          ),
          stroke: new Stroke({ color: BOSCH_DDS_COLORS.boschBlue80, width: 1 }),
        }),
      })
    );
    staticFeatures.push(earthFeature);

    //// define layers
    const animatedLayer = this.openLayersLayerFactory.createVectorLayer(
      this.openLayersLayerFactory.createVectorSource(animatedFeatures),
      10
    );
    this.map.addLayer(animatedLayer);

    const staticLayer = this.openLayersLayerFactory.createVectorLayer(
      this.openLayersLayerFactory.createVectorSource(staticFeatures),
      15
    );
    this.map.addLayer(staticLayer);

    // start animation
    window.requestAnimationFrame(this.update.bind(this));
  }

  // TODO: compare layer.on('postcompose') against requestAnimationFrame
  private update() {
    if (this.destroy) {
      return;
    }

    this.animatedObjects.forEach((ao) => ao.update());

    // pseudo fps limiting to reduce cpu load - not production ready!
    setTimeout(() => window.requestAnimationFrame(this.update.bind(this)), 20);
  }
}
