/**
 *  Copyright © 2025, Luis Andrés Lange <https://javacomm.net>
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *  ----------------------------------------------------------------------------
 *
 *  Exhibit B - "Incompatible With Secondary Licenses" Notice
 *
 *  This Source Code Form is "Incompatible With Secondary Licenses",
 *  as defined by the Mozilla Public License, v. 2.0.
 *
 *  In short:
 *  - This file may be used, modified, and distributed under MPL 2.0 only.
 *  - It may NOT be relicensed under GPL, LGPL, AGPL, or any other Secondary License.
 *
 *  Rationale:
 *  - Ensures that the code remains MPL-2.0.
 *  - Avoids legal conflicts with GPL-licensed libraries (e.g., VideoLAN).
 *  - Maximizes usability for commercial and security-critical applications.
 *
 */
package net.javacomm.client.screencaster;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.javacomm.window.manager.Control;



public class ImageCaster {

  private final static Logger log = LogManager.getLogger(ImageCaster.class);

  private static ImageCaster instance;
  static {
    instance = new ImageCaster();
  }
  private FrameBuffer buffer;
  private CreatePicture createPicture;
  private SendPicture sendPicture;
  private Mousepointer mousepointer;
  private final AtomicLong lastTakenProductionTimestamp = new AtomicLong(-1L);
  private FpsListener fpsListener;
  private PropertyChangeSupport changes = new PropertyChangeSupport(this);

  private ImageCaster() {
    fpsListener = new FpsListener() {
      @Override
      public void fpsUpdated(FpsEvent event) {
        changes.firePropertyChange("imageCaster", Control.NULL, event.getFps());
      }
    };
  }



  public static ImageCaster getInstance() {
    return instance;
  }



  public void addSendListener(PropertyChangeListener listener) {
    changes.addPropertyChangeListener(listener);
  }



  /**
   * Findet gerade eine Aufzeichnung statt?
   * 
   * @return {@code true}, wenn Bilder gesendet werden
   */
  public boolean hasStarted() {
    if (sendPicture == null) return false;
    return sendPicture.isAlive();
  }



  /**
   * Die Bildschirmaufzeichnung beginnt. Diese Methode wird von der 1:1
   * Bildschirmübertragung und der Videokonferenz aufgerufen. Die Videokonferenz
   * ist die Telefonkonferenz.
   * 
   * @param userid
   *                         das Bild stammt von diesem Anwender
   * @param receiverSessions
   *                         alle Empfänger [1..n]
   */
  public void recordScreenshots(String userid, String[] receiverSessions) {
    stopRecording();
    buffer = new FrameBuffer();
    createPicture = new CreatePicture(buffer, lastTakenProductionTimestamp);
    createPicture.start();
    sendPicture = new SendPicture(buffer, lastTakenProductionTimestamp, userid, List.of(receiverSessions));
    sendPicture.addFpsListener(fpsListener);
    sendPicture.start();
    mousepointer = new Mousepointer(List.of(receiverSessions));
    mousepointer.start();
  }



  public void removeSendListener(PropertyChangeListener listener) {
    changes.removePropertyChangeListener(listener);
  }



  /**
   * 
   * Screenshots werden nicht mehr aufgezeichnet und versendet. Ein mehrmaliger
   * Aufruf bewirkt nichts Neues.
   * 
   * 
   */
  public void stopRecording() {
    if (mousepointer != null) mousepointer.interrupt();
    if (createPicture != null) createPicture.interrupt();
    if (sendPicture != null) sendPicture.interrupt();
    try {
      if (createPicture != null) createPicture.join();
    }
    catch (InterruptedException e) {
      log.error(e.getMessage());
    }
    try {
      if (sendPicture != null) sendPicture.join();
    }
    catch (InterruptedException e) {
      log.error(e.getMessage());
    }
    if (sendPicture != null) {
      sendPicture.removeFpsListener(fpsListener);
    }
    try {
      if (mousepointer != null) mousepointer.join();
    }
    catch (InterruptedException e) {
      log.info(e.getMessage(), e);
    }
  }



  /**
   * Die Empfängerlist wird aktualisiert.
   * 
   * @param receiverlist
   *                     alle Empfänger
   */
  public void updateReceiverlist(List<String> receiverlist) {
    sendPicture.setReceiverlist(receiverlist);
    mousepointer.setReceiverlist(receiverlist);
  }
}
