package de.uni_hildesheim.sse.trans.cli;

import java.io.File;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;

import de.uni_hildesheim.sse.model.varModel.IvmlKeyWords;

/**
 * Parser for parsing the command line arguments.
 * @author El-Sharkawy
 *
 */
@SuppressWarnings("static-access")
public class ArgumentsParser {

    private static final Options OPTIONS = new Options();
    
    private static final String CMD_IN = "in";
    private static final String CMD_OUT = "out";
    private static final String CMD_COMMENT = "comment";
    private static final String CMD_HELP = "h";
    private static final String CMD_VERSION = "v";
    private static final String CMD_OPTIMIZATION_ALL = "optAll";
    private static final String CMD_OPTIMIZATION_UNUSED = "optUnused";
    private static final String CMD_OPTIMIZATION_DOUBLE = "optDouble";
    private static final String CMD_OPTIMIZATION_CONSTANTS = "optConstants";
    
    static {
        createOption("inputFile", "The input file which shall be translated", CMD_IN, true);
        createOption("outputFile", "The output file, where the translated model shall be saved. "
            + "If the file extension is *.ivml, a IVML file will be written. "
            + "In any onther case, a DIMACS will will be created.", CMD_OUT, true);
        createOption(CMD_COMMENT, "An optional comment, which shall be added to the translated result", CMD_COMMENT,
            false);
        OPTIONS.addOption(CMD_HELP, "help", false, "Prints this help instead of perfoming the model translation");
        OPTIONS.addOption(CMD_VERSION, "version", true, "Optional: The version of the source model (in IVML syntax)");
        OPTIONS.addOption(CMD_OPTIMIZATION_ALL, CMD_OPTIMIZATION_ALL, false, "Optional: Shall all optimizations apllied"
            + " to the model.\nThis can only be done for a translation into DIMACS format.\n"
            + "The following arguments will be ignored (turned on):"
            + "\n - " + CMD_OPTIMIZATION_UNUSED
            + "\n - " + CMD_OPTIMIZATION_DOUBLE
            + "\n - " + CMD_OPTIMIZATION_CONSTANTS);
        OPTIONS.addOption(CMD_OPTIMIZATION_UNUSED, CMD_OPTIMIZATION_UNUSED, false, "Optional:"
            + "Will remove all unused variables");
        OPTIONS.addOption(CMD_OPTIMIZATION_DOUBLE, CMD_OPTIMIZATION_DOUBLE, false, "Optional:"
            + "Will remove duplicated constraints.");
        OPTIONS.addOption(CMD_OPTIMIZATION_CONSTANTS, CMD_OPTIMIZATION_CONSTANTS, false, "Optional:"
            + "Will remove constant \"variables\" (which are set to true or false permanetely).");
    }
    
   /**
    * Creates and option with an argument.
    * @param argName The command which shall be passed to the passed to this application, e.g -in
    * @param description A description for the user.
    * @param cmd The unique identifier of the option.
    * @param required Specification whether the parameter must be passed to this program, if <tt>false</tt> it is only
    *     optional.
    */
    private static void createOption(String argName, String description, String cmd, boolean required) {
        Option option = OptionBuilder.withArgName(argName).hasArg().withDescription(description).create(cmd);
        
        if (required) {
            option.isRequired();
        }
        
        OPTIONS.addOption(option);
    }
    
    /**
     * Parses the command line arguments passed to this program.
     * @param args The command line arguments passed to this program.
     * @return The parsed arguments.
     */
    public static Arguments parse(String[] args) {
        CommandLineParser parser = new BasicParser();
        
        Arguments arguments = new Arguments();
        
        if (args != null && args.length >= 2) {
            arguments.setHelp(false);
        }
        
        try {
            CommandLine cmd = parser.parse(OPTIONS, args);
            if (cmd.hasOption(CMD_IN)) {
                arguments.setInputFile(new File(cmd.getOptionValue(CMD_IN)));
            } else {
                arguments.setHelp(true);
            }
            if (cmd.hasOption(CMD_OUT)) {
                arguments.setOutputFile(new File(cmd.getOptionValue(CMD_OUT)));
            } else {
                arguments.setHelp(true);
            }
            if (cmd.hasOption(CMD_COMMENT)) {
                arguments.setComment(cmd.getOptionValue(CMD_COMMENT) + IvmlKeyWords.LINEFEED);
            }
            if (cmd.hasOption(CMD_VERSION)) {
                arguments.setVersion(cmd.getOptionValue(CMD_VERSION));
            }
            if (cmd.hasOption(CMD_HELP)) {
                arguments.setHelp(true);
            }
            // Optimizations
            if (cmd.hasOption(CMD_OPTIMIZATION_ALL)) {
                arguments.getOptimizationParameter().setEleminateConstants(true);
                arguments.getOptimizationParameter().setRemoveDuplicatedConstraints(true);
                arguments.getOptimizationParameter().setRemoveUnusedVariables(true);
            } else {
                if (cmd.hasOption(CMD_OPTIMIZATION_CONSTANTS)) {
                    arguments.getOptimizationParameter().setEleminateConstants(true);
                }
                if (cmd.hasOption(CMD_OPTIMIZATION_DOUBLE)) {
                    arguments.getOptimizationParameter().setRemoveDuplicatedConstraints(true);
                }
                if (cmd.hasOption(CMD_OPTIMIZATION_UNUSED)) {
                    arguments.getOptimizationParameter().setRemoveUnusedVariables(true);
                }
            }
        } catch (ParseException exp) {
            arguments.setHelp(true);
            System.err.println("Parsing failed. Reason: " + exp.getMessage());

        }
        
        return arguments;
    }
    
    /**
     * Prints out the command line options.
     */
    public static void printHelp() {
        System.out.println("KConfig ModelTranslator");
        System.out.println("Converts *.model files, produced by KConfigReader, into IVML/DIMACS files.");
        HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp("-in <inputFile> -out <destinationFile.(ivml|dimacs)> [further options]", OPTIONS);
    }
}
