package jp.ac.osaka_u.ist.sel.similarity.commons;

import java.io.File;
import java.util.Arrays;

import jp.ac.osaka_u.ist.sel.similarity.commons.Settings.ListMode;
import jp.ac.osaka_u.ist.sel.similarity.xml.DirListXmlParser;
import jp.ac.osaka_u.ist.sel.similarity.xml.FileMapXmlParser;

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 org.apache.commons.cli.PosixParser;

/**
 * Argument parser for FCFinder.
 * 
 * @author ysk-ssk
 *
 */
public class ArgumentParser {
    /**
     * is an utility class.
     */
	private ArgumentParser() {
	}

	/**
	 * Parse arguments.
	 * 
	 * @param args
	 */
	@SuppressWarnings("static-access")
	public static boolean parseArgument(String[] args) {
		Options options = new Options();
        Option option;
        
        option = OptionBuilder.create('l');
        option.setRequired(false);
        option.setArgs(Option.UNLIMITED_VALUES);
        option.setValueSeparator(File.pathSeparatorChar);
        option.setArgName("languages");
        option.setDescription("languages which needs a parser (you can select some of " + SupportedLanguage._KEY_LANG_C + " or " + SupportedLanguage._KEY_LANG_CPP + " or " + SupportedLanguage._KEY_LANG_JAVA + ").");
        options.addOption(option);
        
        option = OptionBuilder.create('a');
        option.setRequired(false);
        option.setArgs(0);
        option.setArgName("all");
        option.setDescription("analyze files with all extensions, you need to choose 'a' or 'l' or both.");
        options.addOption(option);
        
        option = OptionBuilder.create("dl");
        option.setRequired(false);
        option.setArgs(1);
        option.setArgName("source directory list");
        option.setDescription("a text (or .xml) file which lists source directory paths.");
        options.addOption(option);

        option = OptionBuilder.create("fl");
        option.setRequired(false);
        option.setArgs(1);
        option.setArgName("source file list");
        option.setDescription("a xml file which lists source file paths(this tool does not check the extensions of files).");
        options.addOption(option);

        option = OptionBuilder.create('d');
        option.setRequired(false);
        option.setArgs(Option.UNLIMITED_VALUES);
        option.setValueSeparator(File.pathSeparatorChar);
        option.setArgName("source directories");
        option.setDescription("source directory paths.");
        options.addOption(option);

        option = OptionBuilder.create('m');
        option.setRequired(false);
        option.setArgs(1);
        option.setArgName("minimum number of tokens");
        option.setDescription("Minimum size of the number of tokens in the file(default:15).");
        options.addOption(option);

        option = OptionBuilder.create('w');
        option.setRequired(false);
        option.setArgs(1);
        option.setArgName("temporary working path");
        option.setDescription("dump a parsed files into a temporary working path.");
        options.addOption(option);
        
        option = OptionBuilder.create("jdb");
        option.setRequired(false);
        option.setArgs(1);
        option.setArgName("java database path");
        option.setDescription("set a java database path(default:./" + Settings._defaultDatabasePath + ").");
        options.addOption(option);
        
        option = OptionBuilder.create('x');
        option.setRequired(false);
        option.setArgs(Option.UNLIMITED_VALUES);
        option.setValueSeparator(File.pathSeparatorChar);
        option.setArgName("NG words");
        option.setDescription("NG words. Exclude file paths which include any in NG words.");
        options.addOption(option);

        option = OptionBuilder.create('o');
        option.setRequired(false);
        option.setArgs(1);
        option.setArgName("output csv path");
        option.setDescription("CSV file path for output results.");
        options.addOption(option);
        
		CommandLineParser parser = new PosixParser();
		CommandLine cmd = null;

		Settings settings = Settings.getInstance();
		try {
			cmd = parser.parse(options, args);
			
            if (!cmd.hasOption('l') && !cmd.hasOption('a')) {
                usage(options);
                return false;
            }
            if (cmd.hasOption('l')) {
                settings.addTargetLanguages(Arrays.asList(cmd.getOptionValues('l')));
            }
            if (cmd.hasOption('a')) {
                settings.setDetectAll(true);
            }
            
            if ((cmd.hasOption("dl") || cmd.hasOption('d')) && cmd.hasOption("fl")) {
                usage(options);
                return false;
            }
            
            if (!cmd.hasOption("dl") && !cmd.hasOption('d') && !cmd.hasOption("fl")) {
                usage(options);
                return false;
            }
            
			if (cmd.hasOption("dl")) {
			    settings.setListMode(ListMode.DIR_LIST);
				String xmlPath = cmd.getOptionValue("dl");
				if (xmlPath.endsWith(".xml")) {
					settings.addDirectories(DirListXmlParser.parseXml(xmlPath));
				} else {
					String textLines = TextReader.readText(xmlPath);
					settings.addDirectories(TokenReader.getTokenList(textLines));
				}
			}
            if (cmd.hasOption('d')) {
                settings.setListMode(ListMode.DIR_LIST);
                settings.addDirectories(Arrays.asList(cmd.getOptionValues('d')));
            }
			if (cmd.hasOption("fl")) {
                settings.setListMode(ListMode.FILE_LIST);
                String xmlPath = cmd.getOptionValue("fl");
                settings.setFileMap(FileMapXmlParser.parseXml(xmlPath));
            }
			
            if (cmd.hasOption('m')) {
                int minNOT = Integer.valueOf(cmd.getOptionValue('m'));
                settings.setMinNOT(minNOT);
            }
            if (cmd.hasOption('w')) {
                settings.setWorkingPath(cmd.getOptionValue('w'));
            }
            if (cmd.hasOption("jdb")) {
                settings.setDatabasePath(cmd.getOptionValue("jdb"));
            }
            if (cmd.hasOption('x')) {
                settings.addNGWords(Arrays.asList(cmd.getOptionValues('x')));
            }
            if (cmd.hasOption('o')) {
                settings.setCsvPath(cmd.getOptionValue('o'));
            }
		} catch (ParseException e) {
			usage(options);
			return false;
		} catch (Exception e) {
			e.printStackTrace();
			usage(options);
			return false;
		}
		return true;
	}

	/**
	 * Print usage.
	 * 
	 * @param options
	 */
	private static void usage(Options options) {
		HelpFormatter help = new HelpFormatter();
		help.printHelp("FCFinder", options, true);
	}


}
