#!/usr/bin/env --split-string=${JDK_HOME}/bin/java @Makeshift/java_arguments @Makeshift/java_javac_arguments \c [SS]

// This command runs directly from the present source file, it needs no compiling.

import Breccia.Web.imager.CleaningOptions;
import java.io.Console;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;

import static Breccia.Web.imager.Project.sourceSibling;
import static java.lang.System.err;
import static java.lang.System.out;
import static java.lang.System.exit;
import static java.nio.file.Files.exists;
import static java.nio.file.Files.isDirectory;
import static java.nio.file.Files.isRegularFile;
import static java.nio.file.FileVisitResult.CONTINUE;


/** A shell command to clean a Web image.
  *
  *     @see <a href='http://reluk.ca/project/Breccia/Web/imager/bin/web-image-clean.brec.xht'>
  *       The `web-image-clean` command</a>
  */
public final class WebImageCleanCommand extends SimpleFileVisitor<Path> { // [AFN]


    /** @param argsN Nominal arguments, aka options.
      * @param argsP Positional arguments.
      */
    private WebImageCleanCommand( final  List<String> argsN, final List<String> argsP ) {
        opt.initialize( argsN );
        toAsk = !opt.toForce();
        final int n = argsP.size();
        if( n != 1 ) {
            err.println( commandName + ": Expecting 1 argument, found " + n );
            exitWithUsage( err, 1 ); }
        boundaryPath = Path.of(argsP.get(0)).toAbsolutePath().normalize(); }



    /** Takes a `web-image-clean` command from the shell and executes it.
      */
    public static void main( final String[] arguments ) throws IOException {
        final var argsN = new ArrayList<String>();
        final var argsP = new ArrayList<String>();
        for( final String arg: arguments ) {
            exitOnDemand( arg );
            (arg.charAt(0) == '-' ? argsN : argsP).add( arg ); }
        if( !new WebImageCleanCommand(argsN,argsP).run() ) exit( 1 ); }



   // ━━━  F i l e   V i s i t o r  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━


    public @Override FileVisitResult visitFile( final Path file, BasicFileAttributes _a )
          throws IOException {
        clean( file );
        return CONTINUE; }



////  P r i v a t e  ////////////////////////////////////////////////////////////////////////////////////


    private final Path boundaryPath;



    /** @param f The path of a potential image file.
      */
    private void clean( final Path f ) throws IOException {
        if( !f.getFileName().toString().endsWith( ".brec.xht" )) return; // Not an image file.
        if( isRegularFile( sourceSibling( f ))) return;                  // Not an orphan.
        boolean toDelete = true;
        if( toAsk ) for( ;; ) {
            out.print( "Delete orphan image file " + f + "? (n, y, !)  " );
            final String answer = console.readLine(); /* The user must press the `Enter` key.
              Unfortunately Java makes no provision for single character (e.g. ‘raw’) input. */
            if( "n".equals( answer )) toDelete = false;
            else if( "!".equals( answer )) toAsk = false;
            else if( !"y".equals( answer )) continue;
            break; }
        if( toDelete ) {
            opt.out(toAsk? 2:1).println( "Deleting orphan image file " + f );
            Files.delete( f );
            ++count; }}



    private static final String commandName = "web-image-clean";



    private static final Console console = System.console(); /* It yields ‘the unique Console object’,
      a single object, as source code confirms (JDK 18), which allows for the `static` modifier here. */



    private int count; // Of orphan image files deleted.



    private static void exitOnDemand( final String arg ) {
        if( arg.equals("-?") || arg.equals("-help") ) exitWithUsage( out, 0 ); }



    private static void exitWithUsage( final PrintStream sP, final int status ) {
        sP.println( "Usage: " + commandName + " [<options>] <boundary path>" );
        sP.println( "       " + commandName + " -help | -?" );
        sP.println( "Options, one or more of:" );
        sP.println( "    -force" );
        sP.println( "    -speak" );
        sP.println( "    -stifle" );
        sP.println( "    -verbosity=0|1|2" );
        exit( status ); }



    private final CleaningOptions opt = new CleaningOptions( commandName );



    /** @return True on success, false on failure.
      */
    private boolean run() throws IOException {
        if( isDirectory( boundaryPath )) Files.walkFileTree( boundaryPath, WebImageCleanCommand.this );
        else {
            if( !exists( boundaryPath )) {
                err.println( commandName + ": No such file or directory: " + boundaryPath );
                return false; }
            clean( boundaryPath ); }
        if( count > 0 ) {
            final PrintStream sP = opt.out( toAsk? 2:1 );
            sP.print( count );
            sP.print( " orphan image file" );
            if( count > 1 ) sP.print( 's' );
            sP.println( " deleted" ); }
        return true; }



    private boolean toAsk; } // To ask before deleting, that is.



// NOTES
// ─────
//   AFN  Atypical file naming is allowed here, as explained in `./breccia-web-image`.
//
//   SS · Long-form option `--split-string` is for Emacs, as explained in `./breccia-web-image`.



                                                  // Copyright © 2022, 2024  Michael Allan.  Licence MIT.