Input.java

package edu.odu.cs.cs350;

import java.io.*;
import java.util.*;

import edu.odu.cs.cs350.Interfaces.*;

/**
 * Input file will be invoked using command line arguments.
 * args[0] is reserved for the number of suggestions the user wants
 * to print.
 * args[1] is an optional input to load a properties file, if no
 * properties file is loaded, it will set to default properties.
 * args[i] i will be any number of files supplied in the command
 * line.
 */
public class Input implements InputInterface {

    private int nSuggestions;
    private int MinSequenceLength;
    private int MaxSubstitutions;
    private List<File> files;
    private File propertiesFile;
    private List<String> fileExtensions;
    /**Key: File; Value: tokenCount */
    private Hashtable<File, Integer> tokenCountForFiles;
    private List<TokenInterface> tokens;
    
    Input() {
        this.nSuggestions = 0;
        files = new ArrayList<File>();
        tokens = new ArrayList<TokenInterface>();
        tokenCountForFiles = new Hashtable<File, Integer>();
        propertiesFile = new File("");
        this.setFileExtensions();
        this.setMinSequenceMaxSubs();
    }

    Input(String args[]) throws Exception {
        if (args == null || args.length == 0) {
            System.err.println("Usage: java -jar build/libs/DupDetector.jar <nSuggestions> "
            		+ "<properties file>[OPTIONAL] <path/of/file1> <path/of/file2>");
            System.exit(-1);
        }
        this.files = new ArrayList<File>();
        List<String> argList = new ArrayList<String>();
        for (String string : args) argList.add(string);
        this.nSuggestions = Integer.parseInt(argList.get(0));
        argList.remove(0);

        if (argList.get(0).endsWith(".ini")) {
            this.propertiesFile = new File(argList.get(0));
            argList.remove(0);
            this.setFileExtensions(propertiesFile);
            this.setMinSequenceMaxSubs(propertiesFile);
            for (var path : argList) {
                try {
                    RecursiveSearch r = new RecursiveSearch();
                    this.files.addAll(r.findFiles(path, this.getfileExtensions()));
                } catch(FileNotFoundException e) {
                    System.out.println(e.getMessage());
                }
            }
        }
        else {
            this.setFileExtensions();
            this.setMinSequenceMaxSubs();
            for (var path : argList) {
                try {
                    RecursiveSearch r = new RecursiveSearch();
                    this.files.addAll(r.findFiles(path));
                } catch(FileNotFoundException e) {
                    System.out.println(e.getMessage());
                }
            }
        }

        this.setTokens();
    }

    /**
     * Generates the token list.
     */
    @Override
    public void setTokens() {
        this.tokens = new ArrayList<TokenInterface>();
        this.tokenCountForFiles = new Hashtable<File, Integer>();
        for (File file : this.getFiles()) {
            TokenAnalyzer t = new TokenAnalyzer(file);
            t.processSourceCode();
            tokenCountForFiles.put(file, t.getFileTokenCount());
            for (var token : t.getTokens()) {
                this.tokens.add(token);
            }
        }
    }

    /**
     * @return the list of all files that input received as
     * arguments.
     */
    @Override
    public List<File> getFiles() {
        return this.files;
    }

    /**
     * @return the list of tokens produced using the argument files.
     */
    @Override
    public List<? extends TokenInterface> getTokens() {
        return this.tokens;
    }

    /**
     * @return the number of suggestions for Output to print back
     * to the user.
     */
    @Override
    public int getNSuggestions() {
        return this.nSuggestions;
    }

    /**
     * Key: a File object
     * Value: an Integer object reprsenting the total tokens in 
     * that File.
     * @return a dictionary containing each file and the count of
     * tokens in that file.
     */
    @Override
    public Dictionary<File, Integer> getTokenCountForFiles() {
        return this.tokenCountForFiles;
    }

    /**
     * @param file any of a list of files that was passed to input
     * as an argument.
     * @return the number of tokens present in that file.
     */
    @Override
    public int getTokenCountForFile(File file) {
        return this.tokenCountForFiles.get(file);
    }

    /**
     * @return a list of strings representing the file extensions
     * to be analyzed by the program.
     */
    public List<String> getfileExtensions() {
        return this.fileExtensions;
    }

    /**
     * @return Minimum sequence length of token to be refactored.
     */
    public int getMinSequenceLength() {
        return this.MinSequenceLength;
    }

    /**
     * @return Max number of lexeme substitutions defined in the
     * properties.ini file.
     */
    public int getMaxSubstitutions() {
        return this.MaxSubstitutions;
    }

    /**
     * Sets file extension to default.
     * Default: [".h,.cpp"]
     */
    public void setFileExtensions() {
        this.fileExtensions = new ArrayList<String>();
        this.fileExtensions.add(".h");
        this.fileExtensions.add(".cpp");
    }

    /**
     * Sets the file extension to those listed in properties.ini.
     */
    public void setFileExtensions(File propertiesFile) throws Exception {
        this.fileExtensions = new ArrayList<String>();
        Properties props = new Properties();
        try(Reader reader = new FileReader(propertiesFile)){
            props.load(reader);
        }
        // after loading the .ini file, string are split by "," and stored in an array of extension
        fileExtensions = Arrays.asList(props.getProperty("CppExtensions").split(", "));
    }

    /**
     * Sets properties value to default defined in the SRD.
     */
    public void setMinSequenceMaxSubs() {
        this.MinSequenceLength = 10;
        this.MaxSubstitutions = 8;
    }

    /**
     * Sets the properties value for minimum sequence length
     * and maxs substitution defined in the properties file.
     * @param propertiesFile the properties file from the CLI.
     */
    public void setMinSequenceMaxSubs(File propertiesFile) throws Exception {
        Properties props = new Properties();
        try(Reader reader = new FileReader(propertiesFile)) {
            props.load(reader);
        }
        MinSequenceLength = Integer.valueOf(props.getProperty("MinSequenceLength"));
        MaxSubstitutions = Integer.valueOf(props.getProperty("MaxSubstitutions"));
    }
}