/*
 * Copyright (C) 2000 - 2024 Silverpeas
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * As a special exception to the terms and conditions of version 3.0 of
 * the GPL, you may redistribute this Program in connection with Free/Libre
 * Open Source Software ("FLOSS") applications as described in Silverpeas's
 * FLOSS exception.  You should have received a copy of the text describing
 * the FLOSS exception, and it is also available here:
 * "http://www.silverpeas.org/docs/core/legal/floss_exception.html"
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package org.silverpeas.components.gallery.constant;

import org.silverpeas.kernel.util.StringUtil;
import org.silverpeas.core.util.file.FileUtil;

import jakarta.activation.MimeType;
import jakarta.activation.MimeTypeParseException;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;

/**
 * Enumeration for all supported media types in the gallery component.
 */
public enum MediaMimeType {
  BMP, GIF, PNG, JPG("jpeg", "pjpeg"), TIFF("tif"), WEBP,
  MOV, MP4, FLV,
  MP3,
  ERROR;

  public static final Set<MediaMimeType> PHOTOS =
      Collections.unmodifiableSet(EnumSet.of(BMP, GIF, PNG, JPG, TIFF, WEBP));
  public static final Set<MediaMimeType> VIDEOS =
      Collections.unmodifiableSet(EnumSet.of(MOV, MP4, FLV));
  public static final Set<MediaMimeType> SOUNDS = Collections.unmodifiableSet(EnumSet.of(MP3));

  private static final Set<MediaMimeType> ALL_VALIDS = EnumSet.allOf(MediaMimeType.class);

  static {
    ALL_VALIDS.remove(ERROR);
  }

  private final String mimeType;
  private final List<String> extensions;

  MediaMimeType(String... otherExtensions) {
    String identifiedMimeType;
    try {
      identifiedMimeType = ("ERROR".equals(this.name()) ? "" :
          new MimeType(FileUtil.getMimeType("file." + this.name().toLowerCase()))).toString();
    } catch (MimeTypeParseException e) {
      identifiedMimeType = jakarta.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
    }
    mimeType = identifiedMimeType;
    extensions = new ArrayList<>();
    extensions.add(name().toLowerCase());
    Collections.addAll(extensions, otherExtensions);
  }

  /**
   * Finds from the given file the corresponding {@link MediaMimeType}
   * @param file the file
   * @return {@link MediaMimeType}
   */
  public static MediaMimeType fromFile(File file) {
    return fromMimeType(file != null ? FileUtil.getMimeType(file.getPath()) : "");
  }

  /**
   * Gets the corresponding {@link MediaMimeType} of specified one as string.
   * @param mimeType the MIME type
   * @return {@link MediaMimeType}
   */
  public static MediaMimeType fromMimeType(String mimeType) {
    if (StringUtil.isDefined(mimeType)) {
      // This test is to keep compatibility with existent galleries.
      // With IE7 uploading, it was possible to obtain this mime-type...
      if ("image/pjpeg".equals(mimeType)) {
        return JPG;
      }
      if ("video/m4v".equals(mimeType.replace("/x-", "/"))) {
        return MP4;
      }
      for (MediaMimeType mediaMimeType : ALL_VALIDS) {
        if (mediaMimeType.mimeType.equals(mimeType) ||
            mediaMimeType.mimeType.equals(mimeType.replace("x-ms-", ""))) {
          return mediaMimeType;
        }
      }
    }
    return ERROR;
  }

  public String getName() {
    return name();
  }

  public String getMimeType() {
    return mimeType;
  }

  public List<String> getExtensions() {
    return extensions;
  }

  /**
   * Indicates if the mime type is one of handled media types.
   * @return true if it is a handled one, false otherwise.
   */
  public boolean isSupportedMediaType() {
    return ALL_VALIDS.contains(this);
  }

  /**
   * Indicates if the mime type is one of handled photo types.
   * @return true if it is a handled one, false otherwise.
   */
  public boolean isSupportedPhotoType() {
    return PHOTOS.contains(this);
  }

  /**
   * Indicates if the mime type is one of handled photo types.
   * @return true if it is a handled one, false otherwise.
   */
  public boolean isSupportedVideoType() {
    return VIDEOS.contains(this);
  }

  /**
   * Indicates if the mime type is one of handled photo types.
   * @return true if it is a handled one, false otherwise.
   */
  public boolean isSupportedSoundType() {
    return SOUNDS.contains(this);
  }

  /**
   * Indicates if the mime type is a photo one and if it is readable by ImageIo.
   * @return true if it is a photo media type that is readable by ImageIo
   * @see http://docs.oracle.com/javase/6/docs/api/javax/imageio/package-summary.html
   */
  @SuppressWarnings("JavadocReference")
  public boolean isReadablePhoto() {
    return this == GIF || this == JPG || this == PNG || this == BMP || this == WEBP;
  }

  /**
   * Indicates if the mime type is one of photo and if it is previewable.
   * @return true if the mime type is one of a photo and if it is previewable, false otherwise.
   */
  public boolean isPreviewablePhoto() {
    return isReadablePhoto();
  }

  /**
   * Indicates if from the mime type can be read IPTC metadata.
   * @return true if IPTC can be read, false otherwise.
   */
  public boolean isIPTCCompliant() {
    return this == GIF || this == JPG || this == TIFF || this == WEBP;
  }

  /**
   * Gets the supported mime types according to the given media type.
   * @param mediaType the aimed media type.
   * @return a set of media mime types.
   */
  public static Set<MediaMimeType> getSupportedMimeTypes(MediaType mediaType) {
    final Set<MediaMimeType> supportedMimeTypes;
    switch (mediaType) {
      case Photo:
        supportedMimeTypes = MediaMimeType.PHOTOS;
        break;
      case Video:
        supportedMimeTypes = MediaMimeType.VIDEOS;
        break;
      case Sound:
        supportedMimeTypes = MediaMimeType.SOUNDS;
        break;
      default:
        supportedMimeTypes =  EnumSet.noneOf(MediaMimeType.class);
    }
    return supportedMimeTypes;
  }
}
