// Path: src/main/java/de/skuzzle/enforcer/restrictimports/parser/ImportStatement.java
// public final class ImportStatement {
// 
//     private static final String IMPORT_PREFIX = "import ";
//     private static final String STATIC_PREFIX = "static ";
//     private final String importName;
//     private final int line;
//     private final boolean staticImport;
// 
//     public ImportStatement(String importName, int line, boolean staticImport) {
//         Preconditions.checkArgument(importName != null && !importName.isEmpty(), "importName must not be empty");
//         Preconditions.checkArgument(!importName.startsWith(IMPORT_PREFIX),
//                 "importName should be the raw package name without 'import ' prefix but was: '%s'", importName);
//         Preconditions.checkArgument(!importName.startsWith(STATIC_PREFIX),
//                 "importName should be the raw package name without 'static ' prefix but was: '%s'", importName);
//         Preconditions.checkArgument(importName.trim().equals(importName),
//                 "importName has leading or trailing spaces: '%s'", importName);
//         Preconditions.checkArgument(line > 0, "line numbers should be 1-based and not start at 0");
// 
//         this.importName = importName;
//         this.line = line;
//         this.staticImport = staticImport;
//     }
// 
//     /**
//      * The physical line within the source file in which the import has occurred. Number
//      * is always 1-based!
//      *
//      * @return The line number of the matched imports.
//      */
//     public int getLine() {
//         return line;
//     }
// 
//     /**
//      * Returns the import name including the 'static ' prefix if this represents a static
//      * import.
//      *
//      * @return The full import name.
//      */
//     public String getImportName() {
//         if (staticImport) {
//             return STATIC_PREFIX + importName;
//         }
//         return importName;
//     }
// 
//     public String getFqcn() {
//         return importName;
//     }
// 
//     @Override
//     public String toString() {
//         return StringRepresentation.ofInstance(this)
//                 .add("import", importName)
//                 .add("line", line)
//                 .add("static", staticImport)
//                 .toString();
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(importName, line, staticImport);
//     }
// 
//     @Override
//     public boolean equals(Object obj) {
//         return obj == this || obj instanceof ImportStatement
//                 && Objects.equals(this.line, ((ImportStatement) obj).line)
//                 && Objects.equals(this.staticImport, ((ImportStatement) obj).staticImport)
//                 && Objects.equals(this.importName, ((ImportStatement) obj).importName);
//     }
// }


import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;
import de.skuzzle.enforcer.restrictimports.parser.ImportStatement;
package de.skuzzle.enforcer.restrictimports.parser.lang;



/**
 * SPI for plugging in import statement recognition for different languages.
 * Implementations will be looked up using java's {@link ServiceLoader}.
 *
 * @author Simon Taddiken
 */
public interface LanguageSupport {

    /**
     * Returns the {@link LanguageSupport} implementation for the given file.
     *
     * @param path The path to a file.
     * @return The {@link LanguageSupport} implementation or an empty optional if none was
     *         found.
     */
    static LanguageSupport getLanguageSupport(Path path) {
        final String extension = FileExtension.fromPath(path);
        return SupportedLanguageHolder.getLanguageSupport(extension)
                .orElseThrow(() -> new IllegalArgumentException(String.format(
                        "Could not find a LanguageSupport implementation for normalized file extension: '%s' (%s)",
                        extension, path)));
    }

    /**
     * Determines whether there exists a {@link LanguageSupport} implementation for the
     * given path.
     *
     * @param path The path to a file.
     * @return Whether such implementation exists.
     * @since 1.1.0
     */
    static boolean isLanguageSupported(Path path) {
        final Path filename = path.getFileName();
        return !Files.isDirectory(path)
                && SupportedLanguageHolder.isLanguageSupported(FileExtension.fromPath(filename));
    }

    /**
     * The set of supported file extensions. Extensions returned here are case insensitive
     * and may or may not start with a '.' (dot).
     *
     * @return The set of file extensions.
     */
    Set<String> getSupportedFileExtensions();

    /**
     * Parses the given line and returns the declared package
     *
     * @param line Line in the source file
     * @return The package declared
     */
    Optional<String> parsePackage(String line);

    /**
     * Extract the package names that this import statement represents. As some languages
     * allow to specify multiple imports in a single line, this method returns a list.
     * <p>
     * e.g. import java.util.List; The above should return java.util.List in a Java source
     * file.
     *
     * @param importLine Line in the source file
     * @param lineNumber The line number of the import.
     * @return Fully qualified package name that this import represents
     */
// Path: src/main/java/de/skuzzle/enforcer/restrictimports/parser/ImportStatement.java
// public final class ImportStatement {
// 
//     private static final String IMPORT_PREFIX = "import ";
//     private static final String STATIC_PREFIX = "static ";
//     private final String importName;
//     private final int line;
//     private final boolean staticImport;
// 
//     public ImportStatement(String importName, int line, boolean staticImport) {
//         Preconditions.checkArgument(importName != null && !importName.isEmpty(), "importName must not be empty");
//         Preconditions.checkArgument(!importName.startsWith(IMPORT_PREFIX),
//                 "importName should be the raw package name without 'import ' prefix but was: '%s'", importName);
//         Preconditions.checkArgument(!importName.startsWith(STATIC_PREFIX),
//                 "importName should be the raw package name without 'static ' prefix but was: '%s'", importName);
//         Preconditions.checkArgument(importName.trim().equals(importName),
//                 "importName has leading or trailing spaces: '%s'", importName);
//         Preconditions.checkArgument(line > 0, "line numbers should be 1-based and not start at 0");
// 
//         this.importName = importName;
//         this.line = line;
//         this.staticImport = staticImport;
//     }
// 
//     /**
//      * The physical line within the source file in which the import has occurred. Number
//      * is always 1-based!
//      *
//      * @return The line number of the matched imports.
//      */
//     public int getLine() {
//         return line;
//     }
// 
//     /**
//      * Returns the import name including the 'static ' prefix if this represents a static
//      * import.
//      *
//      * @return The full import name.
//      */
//     public String getImportName() {
//         if (staticImport) {
//             return STATIC_PREFIX + importName;
//         }
//         return importName;
//     }
// 
//     public String getFqcn() {
//         return importName;
//     }
// 
//     @Override
//     public String toString() {
//         return StringRepresentation.ofInstance(this)
//                 .add("import", importName)
//                 .add("line", line)
//                 .add("static", staticImport)
//                 .toString();
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(importName, line, staticImport);
//     }
// 
//     @Override
//     public boolean equals(Object obj) {
//         return obj == this || obj instanceof ImportStatement
//                 && Objects.equals(this.line, ((ImportStatement) obj).line)
//                 && Objects.equals(this.staticImport, ((ImportStatement) obj).staticImport)
//                 && Objects.equals(this.importName, ((ImportStatement) obj).importName);
//     }
// }


// Path: src/main/java/de/skuzzle/enforcer/restrictimports/parser/lang/LanguageSupport.java
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;
import de.skuzzle.enforcer.restrictimports.parser.ImportStatement;

package de.skuzzle.enforcer.restrictimports.parser.lang;



/**
 * SPI for plugging in import statement recognition for different languages.
 * Implementations will be looked up using java's {@link ServiceLoader}.
 *
 * @author Simon Taddiken
 */
public interface LanguageSupport {

    /**
     * Returns the {@link LanguageSupport} implementation for the given file.
     *
     * @param path The path to a file.
     * @return The {@link LanguageSupport} implementation or an empty optional if none was
     *         found.
     */
    static LanguageSupport getLanguageSupport(Path path) {
        final String extension = FileExtension.fromPath(path);
        return SupportedLanguageHolder.getLanguageSupport(extension)
                .orElseThrow(() -> new IllegalArgumentException(String.format(
                        "Could not find a LanguageSupport implementation for normalized file extension: '%s' (%s)",
                        extension, path)));
    }

    /**
     * Determines whether there exists a {@link LanguageSupport} implementation for the
     * given path.
     *
     * @param path The path to a file.
     * @return Whether such implementation exists.
     * @since 1.1.0
     */
    static boolean isLanguageSupported(Path path) {
        final Path filename = path.getFileName();
        return !Files.isDirectory(path)
                && SupportedLanguageHolder.isLanguageSupported(FileExtension.fromPath(filename));
    }

    /**
     * The set of supported file extensions. Extensions returned here are case insensitive
     * and may or may not start with a '.' (dot).
     *
     * @return The set of file extensions.
     */
    Set<String> getSupportedFileExtensions();

    /**
     * Parses the given line and returns the declared package
     *
     * @param line Line in the source file
     * @return The package declared
     */
    Optional<String> parsePackage(String line);

    /**
     * Extract the package names that this import statement represents. As some languages
     * allow to specify multiple imports in a single line, this method returns a list.
     * <p>
     * e.g. import java.util.List; The above should return java.util.List in a Java source
     * file.
     *
     * @param importLine Line in the source file
     * @param lineNumber The line number of the import.
     * @return Fully qualified package name that this import represents
     */
    List<ImportStatement> parseImport(String importLine, int lineNumber);