content: /*
   *  Licensed to the Apache Software Foundation (ASF) under one
   *  or more contributor license agreements.  See the NOTICE file
   *  distributed with this work for additional information
   *  regarding copyright ownership.  The ASF licenses this file
   *  to you under the Apache License, Version 2.0 (the
   *  "License"); you may not use this file except in compliance
   *  with the License.  You may obtain a copy of the License at
   *
   *        http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing,
   *  software distributed under the License is distributed on an
   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   *  KIND, either express or implied.  See the License for the
   *  specific language governing permissions and limitations
   *  under the License.
   */
  package org.apache.causeway.applib.value;
  
  import java.io.Serializable;
  import java.util.Optional;
  import java.util.stream.Stream;
  
  import jakarta.activation.MimeType;
  import jakarta.activation.MimeTypeParseException;
  
  import org.jspecify.annotations.Nullable;
  
  import org.apache.causeway.commons.collections.Can;
  import org.apache.causeway.commons.internal.base._Strings;
  
  import lombok.Getter;
  
  /**
   * @since 1.x {@index}
   */
  public sealed interface NamedWithMimeType
  extends
      Serializable,
      Comparable<NamedWithMimeType> 
  permits Blob, Clob {
  
      String name();
      MimeType mimeType();
      
      /**
       * @deprecated use {@link #name()} instead
       */
      @Deprecated default String getName() { return name(); }
      /**
       * @deprecated use {@link #mimeType()} instead
       */
      @Deprecated default MimeType getMimeType() { return mimeType(); }
  
      @Override
      default int compareTo(final NamedWithMimeType o) {
          int c = _Strings.compareNullsFirst(
                  this.getName(),
                  o!=null
                      ? o.getName()
                      : null);
          if(c!=0) {
              return c;
          }
  
          return _Strings.compareNullsFirst(
                  this.getMimeType().getBaseType(),
                  o!=null
                      ? o.getMimeType().getBaseType()
                      : null);
      }
  
      /**
       * Subset of MimeTypes most commonly used.
       *
       * @since 2.0
       */
      public static enum CommonMimeType {
  
          // see
          // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types
  
          AAC("audio/aac"),
          ABW("application/x-abiword"),
          ARC("application/x-freearc"),
          AVI("video/x-msvideo"),
          AZW("application/vnd.amazon.ebook"),
          BIN("application/octet-stream"),
          BMP("image/bmp"),
          BZ("application/x-bzip"),
          BZ2("application/x-bzip2"),
          CSH("application/x-csh"),
          CSS("text/css"),
          CSV("text/csv"),
          EOT("application/vnd.ms-fontobject"),
          EPUB("application/epub+zip"),
          GZ("application/gzip"),
          GIF("image/gif"),
          HTML("text/html", "htm"),
          ICO("image/vnd.microsoft.icon"),
          ICS("text/calendar"),
          JAR("application/java-archive"),
          JPEG("image/jpeg", "jpg"),
          JS("text/javascript"),
          JSON("application/json"),
          JSONLD("application/ld+json"),
          MIDI("audio/midi", "mid"),
          MJS("text/javascript"),
          MP3("audio/mpeg"),
          MPEG("video/mpeg"),
          MPKG("application/vnd.apple.installer+xml"),
          ODP("application/vnd.oasis.opendocument.presentation"),
          ODS("application/vnd.oasis.opendocument.spreadsheet"),
          ODT("application/vnd.oasis.opendocument.text"),
          OGA("audio/ogg"),
          OGV("video/ogg"),
          OGX("application/ogg"),
          OPUS("audio/opus"),
          OTF("font/otf"),
          PNG("image/png"),
          PDF("application/pdf"),
          PHP("application/php"),
          RAR("application/x-rar-compressed"),
          RTF("application/rtf"),
          SH("application/x-sh"),
          SVG("image/svg+xml"),
          SWF("application/x-shockwave-flash"),
          TAR("application/x-tar"),
          TIFF("image/tiff", "tif"),
          TS("video/mp2t"),
          TTF("font/ttf"),
          TXT("text/plain"), /*aliases*/ LOG("text/plain"), PROPERTIES("text/plain"),
          VSD("application/vnd.visio"),
          WAV("audio/wav"),
          WEBA("audio/webm"),
          WEBM("video/webm"),
          WEBP("image/webp"),
          WOFF("font/woff"),
          WOFF2("font/woff2"),
          XHTML("application/xhtml+xml"),
          XML("application/xml"), /*alias*/ XSD("application/xml"),
  
          XUL("application/vnd.mozilla.xul+xml"),
          YAML("text/vnd.yaml", "yaml", "yml"),
          ZIP("application/zip"),
          _7Z("application/x-7z-compressed", "7z"),
  
          // see
          // https://stackoverflow.com/questions/4212861/what-is-a-correct-mime-type-for-docx-pptx-etc
  
          DOC("application/msword"),
          DOT("application/msword"),
  
          DOCX("application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
          DOTX("application/vnd.openxmlformats-officedocument.wordprocessingml.template"),
          DOCM("application/vnd.ms-word.document.macroEnabled.12"),
          DOTM("application/vnd.ms-word.template.macroEnabled.12"),
  
          XLS("application/vnd.ms-excel"),
          XLT("application/vnd.ms-excel"),
          XLA("application/vnd.ms-excel"),
  
          XLSX("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
          XLTX("application/vnd.openxmlformats-officedocument.spreadsheetml.template"),
          XLSM("application/vnd.ms-excel.sheet.macroEnabled.12"),
          XLTM("application/vnd.ms-excel.template.macroEnabled.12"),
          XLAM("application/vnd.ms-excel.addin.macroEnabled.12"),
          XLSB("application/vnd.ms-excel.sheet.binary.macroEnabled.12"),
  
          PPT("application/vnd.ms-powerpoint"),
          POT("application/vnd.ms-powerpoint"),
          PPS("application/vnd.ms-powerpoint"),
          PPA("application/vnd.ms-powerpoint"),
  
          PPTX("application/vnd.openxmlformats-officedocument.presentationml.presentation"),
          POTX("application/vnd.openxmlformats-officedocument.presentationml.template"),
          PPSX("application/vnd.openxmlformats-officedocument.presentationml.slideshow"),
          PPAM("application/vnd.ms-powerpoint.addin.macroEnabled.12"),
          PPTM("application/vnd.ms-powerpoint.presentation.macroEnabled.12"),
          POTM("application/vnd.ms-powerpoint.template.macroEnabled.12"),
          PPSM("application/vnd.ms-powerpoint.slideshow.macroEnabled.12"),
  
          MDB("application/vnd.ms-access"),
  
          ;
  
          private CommonMimeType(final String primaryType, final String ... proposedFileExtensions) {
              this.mimeType = newMimeType(primaryType);
              this.proposedFileExtensions =
                      proposedFileExtensions.length>0
                          ? Can.ofArray(proposedFileExtensions)
                          : Can.ofSingleton(name().toLowerCase()); // default
          }
  
          @Getter final MimeType mimeType;
          @Getter final Can<String> proposedFileExtensions;
  
          public String getBaseType() {
              return getMimeType().getBaseType();
          }
  
          static MimeType newMimeType(final String primaryType, final String subtype) {
              try {
                  return new MimeType(primaryType, subtype);
              } catch (MimeTypeParseException e) {
                  throw new IllegalArgumentException(e);
              }
          }
  
          static MimeType newMimeType(final String baseType) {
              try {
                  return new MimeType(baseType);
              } catch (MimeTypeParseException e) {
                  throw new IllegalArgumentException(e);
              }
          }
  
          public boolean matches(final MimeType otherMimeType) {
              return mimeType.match(otherMimeType);
          }
  
          /**
           * Tries to match fileExt with any {@link CommonMimeType}.
           */
          public static Optional<CommonMimeType> valueOfFileExtension(final @Nullable String fileExt) {
              if(_Strings.isNullOrEmpty(fileExt)) {
                  return Optional.empty();
              }
              var fileExtLower = fileExt.toLowerCase();
              return Stream.of(CommonMimeType.values())
                      .filter(mime->mime.getProposedFileExtensions().contains(fileExtLower))
                      .findFirst();
          }
  
          /**
           * Parses fileName for its extension and tries to match with any {@link CommonMimeType}.
           */
          public static Optional<CommonMimeType> valueOfFileName(final @Nullable String fileName) {
              if(_Strings.isNullOrEmpty(fileName)) {
                  return Optional.empty();
              }
              final int p = fileName.lastIndexOf('.');
              if(p<0) {
                  return Optional.empty();
              }
              final int beginIndex = p + 1;
              if ((fileName.length() - beginIndex) < 0) {
                  return Optional.empty();
              }
              return valueOfFileExtension(fileName.substring(beginIndex));
          }
  
      }
  
  }
  