Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git
/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */
package com.keenwrite.util;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;

import static com.keenwrite.events.StatusEvent.clue;

/**
 * Represents the type of data encoding scheme used for a universal resource
 * indicator. Prefer to use the {@code is*} methods to check equality because
 * there are cases where the protocol represents more than one possible type
 * (e.g., a Java Archive is a file, so comparing {@link #FILE} directly could
 * lead to incorrect results).
 */
public enum ProtocolScheme {
  /**
   * Denotes a local file.
   */
  FILE( "file" ),
  /**
   * Denotes either HTTP or HTTPS.
   */
  HTTP( "http" ),
  /**
   * Denotes the File Transfer Protocol.
   */
  FTP( "ftp" ),
  /**
   * Denotes Java archive file.
   */
  JAR( "jar" ),
  /**
   * Could not determine scheme (or is not supported by the application).
   */
  UNKNOWN( "unknown" );

  private final String mPrefix;

  ProtocolScheme( final String prefix ) {
    mPrefix = prefix;
  }

  /**
   * Returns the protocol for a given URI or file name.
   *
   * @param uri Determine the protocol for this URI or file name.
   * @return The protocol for the given resource.
   */
  public static ProtocolScheme getProtocol( final String uri ) {
    try {
      return getProtocol( new URI( uri ) );
    } catch( final Exception ex ) {
      // Using double-slashes is a shorthand to instruct the browser to
      // reference a resource using the parent URL's security model. This
      // is known as a protocol-relative URL.
      return uri.startsWith( "//" ) ? HTTP : valueFrom( new File( uri ) );
    }
  }

  /**
   * Returns the protocol for a given URI or file name.
   *
   * @param uri Determine the protocol for this URI or file name.
   * @return The protocol for the given resource.
   */
  public static ProtocolScheme getProtocol( final URI uri )
    throws MalformedURLException {
    return uri.isAbsolute()
      ? valueFrom( uri )
      : valueFrom( uri.toURL() );
  }

  /**
   * Determines the protocol scheme for a given string.
   *
   * @param protocol A string representing data encoding protocol scheme.
   * @return {@link #UNKNOWN} if the protocol is unrecognized, otherwise a
   * valid value from this enumeration.
   */
  public static ProtocolScheme valueFrom( final String protocol ) {
    final var sanitized = protocol == null ? "" : protocol.toUpperCase();

    for( final var scheme : values() ) {
      // This will match HTTP/HTTPS as well as FILE*, which may be inaccurate.
      if( sanitized.startsWith( scheme.name() ) ) {
        return scheme;
      }
    }

    return UNKNOWN;
  }

  /**
   * Determines the protocol scheme for a given {@link File}.
   *
   * @param file A file having a URI that contains a protocol scheme.
   * @return {@link #UNKNOWN} if the protocol is unrecognized, otherwise a
   * valid value from this enumeration.
   */
  public static ProtocolScheme valueFrom( final File file ) {
    return valueFrom( file.toURI() );
  }

  /**
   * Determines the protocol scheme for a given {@link URI}.
   *
   * @param uri A URI that contains a protocol scheme.
   * @return {@link #UNKNOWN} if the protocol is unrecognized, otherwise a
   * valid value from this enumeration.
   */
  public static ProtocolScheme valueFrom( final URI uri ) {
    try {
      return valueFrom( uri.toURL() );
    } catch( final Exception ex ) {
      clue( ex );
      return UNKNOWN;
    }
  }

  /**
   * Determines the protocol scheme for a given {@link URL}.
   *
   * @param url The {@link URL} containing a protocol scheme.
   * @return {@link #UNKNOWN} if the protocol is unrecognized, otherwise a
   * valid value from this enumeration.
   */
  public static ProtocolScheme valueFrom( final URL url ) {
    return valueFrom( url.getProtocol() );
  }

  /**
   * Answers whether the given {@link URL} points to a remote resource.
   *
   * @param url The {@link URL} containing a protocol scheme.
   * @return {@link true} if the protocol must be fetched via HTTP or FTP.
   */
  @SuppressWarnings( "unused" )
  public static boolean isRemote( final URL url ) {
    return valueFrom( url ).isRemote();
  }

  /**
   * Answers {@code true} if the given protocol is for a local file, which
   * includes a JAR file.
   *
   * @return {@code false} the protocol is not a local file reference.
   */
  public boolean isFile() {
    return this == FILE || this == JAR;
  }

  /**
   * Answers whether the given protocol is HTTP or HTTPS.
   *
   * @return {@code true} the protocol is either HTTP or HTTPS.
   */
  public boolean isHttp() {
    return this == HTTP;
  }

  /**
   * Answers whether the given protocol is FTP.
   *
   * @return {@code true} the protocol is FTP.
   */
  public boolean isFtp() {
    return this == FTP;
  }

  /**
   * Answers whether the given protocol represents a remote resource.
   *
   * @return {@code true} the protocol is HTTP or FTP.
   */
  public boolean isRemote() {
    return isHttp() || isFtp();
  }

  /**
   * Answers {@code true} if the given protocol is for a Java archive file.
   *
   * @return {@code false} the protocol is not a Java archive file.
   */
  public boolean isJar() {
    return this == JAR;
  }

  /**
   * Prepends the protocol scheme to the given path, without a host name.
   *
   * @param path The path to decorate as a URI, including the scheme.
   * @return The
   */
  public String decorate( final String path ) {
    return getPrefix() + "://" + path;
  }

  private String getPrefix() {
    return mPrefix;
  }
}