package org.incava.doctorj;

import java.io.*;
import java.util.*;
import org.incava.analysis.ContextReport;
import org.incava.jagol.*;
import org.incava.lang.StringExt;
import org.incava.log.Log;


/**
 * Options for Javadoc processing, supporting:
 *
 *     doctorj             (just errors)
 *     doctorj --public    (warning level of 0; public methods)
 *     doctorj --protected (warning level of 1)
 *     doctorj --package   (warning level of 2)
 *     doctorj --private   (warning level of 3)
 *     doctorj --pedantic  (warning level at max)
 */
public class Options extends OptionSet
{
    public static int MAXIMUM_WARNING_LEVEL = 100;

    public static int MINIMUM_WARNING_LEVEL = -1;

    public static int DEFAULT_WARNING_LEVEL = -1;

    /**
     * The strictness level, for warnings.
     */
    public static int warningLevel = DEFAULT_WARNING_LEVEL;

    /**
     * Whether to use single-line (emacs) or multi-line (non-emacs) output
     * format. The emacs form is most suitable for IDEs, which expect
     * single-line output.
     */
    public static boolean emacsOutput = false;

    /**
     * The version.
     */
    public static String VERSION = "5.0.0";

    /**
     * The Java source version.
     */
    public static String source = "1.3";

    /**
     * The warning level option.
     */
    private IntegerOption warningOpt;

    /**
     * The emacs option.
     */
    private BooleanOption emacsOpt;

    /**
     * The tab width option.
     */
    private IntegerOption tabWidthOpt;

    /**
     * The verbose option.
     */
    private BooleanOption verboseOpt;

    /**
     * The list of word-list (dictionary) files.
     */
    private ListOption dictOpt;

    /**
     * The version option.
     */
    private BooleanOption versionOpt;

    /**
     * The source option.
     */
    private StringOption sourceOpt;

    private static Options instance = null;

    public static Options get()
    {
        if (instance == null) {
            instance = new Options();
        }
        return instance;
    }

    protected Options()
    {
        super("doctorj", "Analyzes and validates Java and Javadoc");

        // use the doctorj.* equivalent property for each option.

        Boolean emacs = new Boolean(emacsOutput);
        String emacsProperty = System.getProperty("doctorj.emacs");
        Log.log("emacs property: " + emacsProperty);
        if (emacsProperty != null) {
            emacs = new Boolean(emacsProperty);
            Log.log("emacs: " + emacs);
        }

        Integer warningLvl = new Integer(warningLevel);
        String warningLvlProperty = System.getProperty("doctorj.warning");
        if (warningLvlProperty != null) {
            warningLvl = new Integer(warningLvlProperty);
        }
        
        Integer tabWidth = new Integer(ContextReport.tabWidth);
        String tabWidthProperty = System.getProperty("doctorj.tabwidth");
        if (tabWidthProperty != null) {
            tabWidth = new Integer(tabWidthProperty);
        }

        Boolean verbose = new Boolean(false);
        String verboseProperty = System.getProperty("doctorj.verbose");
        if (verboseProperty != null) {
            verbose = new Boolean(verboseProperty);
        }

        List   wordLists = new ArrayList();
        String dirProperty = System.getProperty("doctorj.dir");
        Log.log("dirProperty: " + dirProperty);
        
        if (dirProperty != null) {
            Locale locale = Locale.getDefault();
            Log.log("locale: " + locale);
            
            String wordListFile = dirProperty + "/words." + locale;
            Log.log("wordListFile: " + wordListFile);
            
            wordLists.add(wordListFile);
        }
        
        String dictProperty = System.getProperty("doctorj.dictionaries");
        Log.log("dictProperty: " + dictProperty);
        
        if (dictProperty != null) {
            List     list = StringExt.listify(dictProperty);
            Iterator it   = list.iterator();
            while (it.hasNext()) {
                String s = (String)it.next();
                wordLists.add(s);
            }
        }
        
        add(emacsOpt    = new BooleanOption("emacs",     "whether to list violations in Emacs form (single line)",                 emacs));
        add(warningOpt  = new IntegerOption("warning",   "the level of warnings to be output, with -1 being to check only errors", warningLvl));
        add(tabWidthOpt = new IntegerOption("tabwidth",  "the number of spaces to treat tabs equal to",                            tabWidth));
        add(dictOpt     = new ListOption("dictionaries", "the list of dictionary (word list) files",                               wordLists));
        add(verboseOpt  = new BooleanOption("verbose",   "whether to run in verbose mode (for debugging)",                         verbose));
        add(versionOpt  = new BooleanOption("version",   "Displays the version"));
        add(sourceOpt   = new StringOption("source",     "the Java source version; either 1.3 (the default) or 1.4",               source));
        versionOpt.setShortName('v');
        
        addRunControlFile("/etc/doctorj.conf");
        addRunControlFile("~/.doctorjrc");
    }

    /**
     * Processes the run control files and command line arguments, and sets the
     * static variables. Returns the arguments that were not consumed by option
     * processing.
     */
    public String[] process(String[] args)
    {
        Log.log("args: " + args);
        String[] unprocessed = super.process(args);

        Integer tabWidthInt = tabWidthOpt.getValue();
        if (tabWidthInt != null) {
            Log.log("setting tab width: " + tabWidthInt);
            ContextReport.tabWidth = tabWidthInt.intValue();
        }
    
        Integer warningInt = warningOpt.getValue();
        if (warningInt != null) {
            Log.log("setting warning level: " + warningInt);
            warningLevel = warningInt.intValue();
        }
        
        Boolean emacsBool = emacsOpt.getValue();
        if (emacsBool != null) {
            Log.log("setting output format: " + emacsBool);
            emacsOutput = emacsBool.booleanValue();
        }
        
        Boolean verboseBool = verboseOpt.getValue();
        if (verboseBool != null) {
            Log.log("setting verbose: " + verboseBool);
            Log.verbose = verboseBool.booleanValue();
        }

        Boolean versionBool = versionOpt.getValue();
        if (versionBool != null) {
            System.out.println("doctorj, version " + VERSION);
            System.out.println("Written by Jeff Pace (jpace [at] incava [dot] org)");
            System.out.println("Released under the Lesser GNU Public License");
            System.exit(0);
        }

        List dictList = dictOpt.getValue();
        if (dictList != null) {
            Iterator it = dictList.iterator();
            while (it.hasNext()) {
                String dict = (String)it.next();
                ItemDocAnalyzer.spellChecker.addDictionary(dict);
            }
        }

        String sourceStr = sourceOpt.getValue();
        if (sourceStr != null) {
            Log.log("setting source: " + sourceStr);
            source = sourceStr;
        }

        Log.logColor(Log.BLUE, "unprocessed: " + unprocessed);
        for (int i = 0; i < unprocessed.length; ++i) {
            Log.logColor(Log.BLUE, "unprocessed[" + i + "]: " + unprocessed[i]);
        }
        
        return unprocessed;
    }

}
