/**
 *  Copyright © 2025, Luis Andrés Lange <https://javacomm.net>
 *
 *  Previously released under Apache License 2.0; now licensed under MPL 2.0.
 *
 *  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.restserver;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
import net.javacomm.database.DatabaseException;
import net.javacomm.database.WebdatabaseImpl;
import net.javacomm.share.Constants;



@Path("/chat")
public class ChatFileDownload {

  final static Logger log = LogManager.getLogger(ChatFileDownload.class);
  private WebdatabaseImpl database;

  public ChatFileDownload() {
    database = (WebdatabaseImpl) WebdatabaseImpl.getInstance();
  }



  /**
   * Lies einen Datenblock aus. Der Datenblock gehört zu einer Datei in einem
   * Besprechungsraum.
   * 
   * 
   * @param anlage
   *               dieser Referenzschlüssel auf die Datei
   * @param chunk
   *               dieser Referenzschlüssel auf den Datenblock innerhalb der Datei
   * 
   * @return der gelesene Datenblock als Stream
   */
  @GET
  @Path("/anlage")
  @Produces(MediaType.APPLICATION_OCTET_STREAM)
  public InputStream getAnlage(@HeaderParam("number") Long anlage, @QueryParam("chunk") Integer chunk) {
    InputStream stream;
    try {
      stream = database.fetchAnlageAsStream(anlage, chunk);
    }
    catch (DatabaseException e) {
      log.info(e.getMessage());
      throw new WebApplicationException();
    }
    return stream;
  }



  /**
   * Lies einen Datenblock aus. Der Datenblock gehört zu einer Datei in einem
   * Private Chat.
   * 
   * 
   * @param anlage
   *               dieser Referenzschlüssel auf die Datei
   * @param chunk
   *               dieser Referenzschlüssel auf den Datenblock innerhalb der Datei
   * 
   * @return der gelesene Datenblock als Stream
   */
  @GET
  @Path("/anlage/private")
  @Produces(MediaType.APPLICATION_OCTET_STREAM)
  public InputStream fetchPrivateChunk(@HeaderParam("number") Long anlage,
      @QueryParam("chunk") Integer chunk) {
    InputStream stream;
    try {
      stream = database.fetchPrivateChunk(anlage, chunk);
    }
    catch (DatabaseException e) {
      log.info(e.getMessage());
      throw new WebApplicationException();
    }
    return stream;
  }



  /**
   * Der Anwender überträgt alle Attribue der Anlage/Datei. Der Rückgabewert ist
   * ein Schlüssel/Identifier auf die Anlage.
   * 
   * @param multiPart
   *                  alle Attribute
   * 
   * @return Identifier auf die Anlage/Datei
   * @throws SQLException
   */
  @POST
  @Path("save/chatfile/attribute")
  @Produces(MediaType.TEXT_PLAIN)
  public Long postAttributes(FormDataMultiPart multiPart) {
    Long id = null;
    Long filesize = Long.valueOf(multiPart.getField("FILESIZE").getValue());
    String chatid = multiPart.getField("CHATID").getValue();
    String absolute = multiPart.getField("ABSOLUTE").getValue();
    String filename = multiPart.getField("FILENAME").getValue();
    if (filesize > Constants.MAX_FILESIZE) {
      Response response = Response.status(Status.INTERNAL_SERVER_ERROR)
          .entity(
              String.valueOf(filesize) + " > " + String.valueOf(Constants.MAX_FILESIZE) + " - Filesize to big"
          ).type(MediaType.TEXT_PLAIN).build();

      throw new WebApplicationException(response);
    }
    try {
      id = database.saveChatfile(Long.valueOf(filesize), chatid, absolute, filename);
    }
    catch (DatabaseException e) {
      log.warn(e.getMessage());
      throw new WebApplicationException();
    }
    return id;
  }



  /**
   * Ermittle die Dateigröße der Anlage. Die Größe wird für die Berechnung der
   * Fortschritssanzeige in der GUI benötigt. Die Größe ist gleich 100% in der
   * Anzeige.
   * 
   * @param anlage
   *               dieser Datenbankschlüssel verweist auf eine Anlage/Datei in
   *               einem Besprechungsraum
   * @return die Dateigröße einer Anlage
   */
  @GET
  @Path("/anlage/size")
  @Produces(MediaType.TEXT_PLAIN)
  public long getFilesize(@HeaderParam("anlage") long anlage) {
    long filesize;
    try {
      filesize = database.fetchChatAnlageSize(anlage);
    }
    catch (DatabaseException e) {
      log.info(e.getMessage());
      throw new WebApplicationException();
    }
    return filesize;
  }



  /**
   * Ermittle die Dateigröße der Anlage. Die Größe wird für die Berechnung der
   * Fortschritssanzeige in der GUI benötigt. Die Größe ist gleich 100% in der
   * Anzeige.
   * 
   * @param anlage
   *               dieser Datenbankschlüssel verweist auf eine Anlage/Datei in
   *               einem Private Chat
   * @return die Dateigröße einer Anlage
   */
  @GET
  @Path("/anlage/private/size")
  @Produces(MediaType.TEXT_PLAIN)
  public long getPrivateFilesize(@HeaderParam("anlage") long anlage) {
    long filesize;
    try {
      filesize = database.fetchPrivateAnlageSize(anlage);
    }
    catch (DatabaseException e) {
      log.info(e.getMessage());
      throw new WebApplicationException();
    }
    return filesize;
  }



  /**
   * Hole alle Datenblöcke einer Datei.
   * 
   * @param anlage
   *               Datei/Attachment
   * @return {@code ArrayList<Long>}, alle Chunknummern in einem Json Array
   */
  @GET
  @Path("/anlage/chunknumbers")
  @Produces(MediaType.TEXT_PLAIN)
  public String fetchChatChunknumbers(@HeaderParam(value = "anlage") long anlage) {
    ArrayList<Long> numbers;
    try {
      numbers = database.fetchChunknumbers(anlage);
    }
    catch (DatabaseException e) {
      log.error(e.getMessage());
      throw new WebApplicationException();
    }
    return Wrapper.toString(numbers);
  }



  /**
   * Hole alle Datenblöcke einer Datei.
   * 
   * @param anlage
   *               Datei/Attachment
   * @return {@code ArrayList<Long>}, alle Chunknummern in einem Json Array
   */
  @GET
  @Path("/anlage/chunknumbers/private")
  @Produces(MediaType.TEXT_PLAIN)
  public String fetchPrivateChunknumbers(@HeaderParam(value = "anlage") long anlage) {
    ArrayList<Long> numbers;
    try {
      numbers = database.fetchPrivateChunknumbers(anlage);
    }
    catch (DatabaseException e) {
      log.error(e.getMessage());
      throw new WebApplicationException();
    }
    return Wrapper.toString(numbers);
  }

}
