class WMSSim extends Sim {
  map;
  queue;

  init;

  constructor(product, showDate) {
    super(product, showDate);
    this.queue = new HanisQueue(this.product.data.parameters.max_frames);

    this.init = true;

    setTimeout(() => {
      this.htmlContent = parseWMS(this.product);
    });
  }

  subscribe(timeTickObervable, newTimeObservable) {
    super.subscribe(timeTickObervable, newTimeObservable);
    this.init = false;
  }

  populateImageQueue(currentTime) {
    this.queue = new HanisQueue(this.product.data.parameters.max_frames);
    this.availableImages = this.allImages;
  }

  onTick(currentTime) {
    if (!this.isOpen) return;

    var updatedTimes = false;

    // add new images
    var imagesToAdd = this.availableImages.filter(
      (imgTime) => imgTime <= currentTime
    );

    this.availableImages = this.availableImages.filter(
      (imgTime) => imgTime > currentTime
    );

    while (imagesToAdd.length > 0) {
      var img = imagesToAdd.shift();
      if (img !== undefined) {
        this.queue.enqueue(img);
        updatedTimes = true;
      }
    }

    // remove images in case time reset was called
    var imagesToRemove = this.queue.items.filter(
      (imgTime) => currentTime <= imgTime
    );

    if (imagesToRemove != 0) {
      this.availableImages = [...this.availableImages, ...imagesToRemove];
      updatedTimes = true;
    }

    if (updatedTimes) {
      this.map.timeDimension.setAvailableTimes(
        this.queue.items.slice(0).reverse(),
        "replace"
      );
    }
  }

  open() {
    $("#main").html(this.htmlContent);
    this.map = this.createMap(this.product);
    this.allImages = this.map.timeDimension.getAvailableTimes();
    this.availableImages = this.allImages;
    super.open();

    if (this.init && !this.timerObserver) {
      var availableTimes = this.map.timeDimension.getAvailableTimes();
      this.map.timeDimension.setAvailableTimes(
        availableTimes.slice(0, 1),
        "intersect"
      );
    }
  }

  close() {
    super.close();
    setTimeout(() => {
      if (this.map && !this.isOpen) {
        this.map.remove();
      }
    });
  }

  createMap(product) {
    var [p1, p2, p3, p4] = product.data.bbox.coordinates;
    var leftBottom, rightTop;

    if (product.data.bbox.format !== "Lat/Lng") {
      leftBottom = L.latLng(p2, p1);
      rightTop = L.latLng(p4, p3);
    } else {
      leftBottom = L.latLng(p1, p2);
      rightTop = L.latLng(p3, p4);
    }

    var bounds = L.latLngBounds(leftBottom, rightTop);

    const timeStartAddedBuffer = luxon.DateTime.fromISO(product.data.time.start)
    .minus({ hours: product.data.parameters.max_frames })
    .toUTC()
    .toISODate()

    var mapOptions = {
      fullscreenControl: true,
      zoomDelta: 0.5,
      zoomSnap: 0.5,
      timeDimension: true,
      timeDimensionOptions: {
        timeInterval: `${timeStartAddedBuffer}/${product.data.time.end}`,
        currentTime: Date.parse(product.data.time.start),
        period: product.data.time.interval,
      },
      timeDimensionControl: true,
      timeDimensionControlOptions: {
        autoPlay: true,
        loopButton: true,
        timeSteps: 1,
        timeZones: ["utc"],
        playerOptions: {
          transitionTime: 500,
          loop: true,
        },
        minSpeed: 1,
        maxSpeed: 4,
      },
      maxBounds: bounds,
    };

    var wmsUrl = product.data.base_url;
    var wmsLayer = L.tileLayer.wms(wmsUrl, {
      layers: product.data.layer,
      format: product.data.format,
      transparent: true,
      cache: product.data.parameters.max_frames * 10,
    });
    var tdWmsLayer = L.timeDimension.layer.wms(wmsLayer);

    var map = L.map("map", mapOptions);
    map.fitBounds(bounds);
    tdWmsLayer.addTo(map);

    return map;
  }
}
