package commandHelp;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

import coloring.Config;
import coloring.Xterm256;
import exceptions.InvalidColourException;
import exceptions.InvalidCommandLineException;

public class CommandList {
    
    private static String SEE_ALSO= "\nFull documentation at: http://asciigenome.readthedocs.io/\n";
    private static String CMD_HELP= "For help on individual commands use one of::\n"
            + "\n"
            + "    command -h\n"
            + "    ?command\n"
            + "    help command\n"
            + "\n"
            + "e.g. `ylim -h`";
    
    private static String reStructuredTextHelp() throws InvalidCommandLineException, InvalidColourException{

        String intro = ".. _command_reference:"
                + "\n"
                + "\n"
                + ".. This document is autogenerated by CommandList.reStructuredTextHelp().\n"
                + "   Do not edit it here. Edit source code then run tests in CommandListTest.updateReStructuredFile() to recreate "
                + "this file.\n\n";

        intro += ""
                + "Command reference\n"
                 + "=================\n\n";
        intro += "This is the documentation for the indvidual commands. "
                + "The help documented here can be invoked also at the command prompt with `command -h`, for example to "
                + "get the help for `ylim`::\n"
                + "\n"
                + "    ylim -h\n"
                + "\n"
                + "Parameters in square brakets are optional and the default argument is "
                + "indicated by the `=` sign. The syntax `...` indicate that the argument "
                + "can be repeated multiple times. For example::\n"
                + "\n"
                + "    ylim min max [track_regex = .*]...\n"
                + "\n"
                + "Means that `ylim` takes two mandatory arguments, `min` and `max`. The optional "
                + "argument, `track_regex`, defaults to `.*` and can be repated multiple times.\n";
                
        String help= "";
        for(Section sec : Section.values()){
            
            help += toTitleCase(sec.toString() + "\n") + StringUtils.repeat("-", sec.toString().length()) + "\n\n";

            for(CommandHelp x : CommandList.getCommandsForSection(sec)){
                                
                help += x.getPrintName() + "\n" + StringUtils.repeat("+", x.getPrintName().length()) + "\n\n"; 
                help += ":code:`" + (x.getName() + " " + x.getArgs()).trim() + "`\n\n";
                help += (x.getBriefDescription() + " " + x.getAdditionalDescription() + "\n\n");
            }            
        }
        // Handle special cases manually:
        help= help.replace("[incl_regex = .*]", "[incl_regex = .\\*]");
        
        help= help.replaceAll("~", " ");
        return intro + "\n\n" + help;
    }
    
    /** Run this method in Unit test to update the file commandHelp.md  
     * @throws InvalidCommandLineException 
     * @throws IOException 
     * @throws InvalidColourException 
     * */
    public static void updateCommandHelpMdFile(File destFile) throws InvalidCommandLineException, IOException, InvalidColourException{
        
        BufferedWriter wr= new BufferedWriter(new FileWriter(destFile));
        String doc= reStructuredTextHelp();
        
        // Replace ansi escapes
        doc= doc.replaceAll("\n*0: [\\s|\\S]+grey93\033\\[38;5;0;48;5;231m", "`here <http://jonasjacek.github.io/colors/>`_ ");
        
        wr.write(doc + "\n");
        wr.close();
        System.err.println("Command help file written to " + destFile.getAbsolutePath());
    }
    
    public static String fullHelp() throws InvalidCommandLineException, InvalidColourException{
        String help= "\n      N a v i g a t i o n \n\n";
        for(CommandHelp x : CommandList.getCommandsForSection(Section.NAVIGATION)){
            help += (x.printCommandHelp() + "\n");
        }
        help += "\n      F i n d \n\n";
        for(CommandHelp x : CommandList.getCommandsForSection(Section.FIND)){
            help += (x.printCommandHelp() + "\n");
        }
        help += "\n      D i s p l a y \n\n";
        for(CommandHelp x : CommandList.getCommandsForSection(Section.DISPLAY)){
            help += (x.printCommandHelp() + "\n");
        }
        
        help += "\n      A l i g n m e n t s \n\n";
        for(CommandHelp x : CommandList.getCommandsForSection(Section.ALIGNMENTS)){
            help += (x.printCommandHelp() + "\n");
        }

        for(CommandHelp x : CommandList.getCommandsForSection(Section.GENERAL)){
            help += (x.printCommandHelp() + "\n");
        }
        
        help += "\n      G e n e r a l \n\n";
        for(CommandHelp x : CommandList.getCommandsForSection(Section.GENERAL)){
            help += (x.printCommandHelp());
        }
        help += SEE_ALSO;
        return help;
    }
    
    public static String briefHelp() throws InvalidCommandLineException, InvalidColourException{
        String help= "Available commands with brief description.\n"
                + CMD_HELP 
                + "\n"
                + "\n"
                + "      N a v i g a t i o n \n\n";
        for(CommandHelp x : CommandList.getCommandsForSection(Section.NAVIGATION)){
            help += (x.printBriefHelp());
        }
        help += "\n      F i n d \n\n";
        for(CommandHelp x : CommandList.getCommandsForSection(Section.FIND)){
            help += (x.printBriefHelp());
        }
        help += "\n      D i s p l a y \n\n";
        for(CommandHelp x : CommandList.getCommandsForSection(Section.DISPLAY)){
            help += (x.printBriefHelp());
        }
        
        help += "\n      A l i g n m e n t s \n\n";
        for(CommandHelp x : CommandList.getCommandsForSection(Section.ALIGNMENTS)){
            help += (x.printBriefHelp());
        }
        help += "\n      G e n e r a l \n\n";
        for(CommandHelp x : CommandList.getCommandsForSection(Section.GENERAL)){
            help += (x.printBriefHelp());
        }
        help += SEE_ALSO;
        return help;
    }

    
    public final static List<CommandHelp> commandHelpList() throws InvalidCommandLineException, InvalidColourException{
        List<CommandHelp> cmdList= new ArrayList<CommandHelp>();
        CommandHelp cmd= new CommandHelp();        

        cmd= new CommandHelp();
        cmd.setName("goto"); cmd.setArgs("chrom[:from[-to]] | chrom [from [to]]"); cmd.inSection= Section.NAVIGATION; 
        cmd.setBriefDescription("Go to region `chrom:from-to` or to `chrom:from` or to the start of `chrom`. "); 
        cmd.setAdditionalDescription("The region may be separated by `:` and `-` or by spaces. "
                + "The character ':' is a shortcut for `goto`. Examples::\n"
                + "\n"
                + "    goto chr8:1-1000~~~# Go to region 1-1000 on chr8\n"
                + "    goto chr8 1 1000~~~# Use spaces instead\n"
                + "    goto chr8 1-1000~~~# Same as above\n"
                + "    goto chr8 1 - 1000~# Same as above\n"
                + "    goto chr8 1 1,000~~# Comma in numbers is ok\n"
                + "    goto chr8:10~~~~~~~# Go to position 10 on chr8\n"
                + "    goto chr8~~~~~~~~~~# Go to start of chr8\n"
                + "    goto chr8 10 30 50~# Go to chr8:10-50\n"
                + "    :chr8~~~~~~~~~~~~~~# Colon ':' shortcut\n"
                + "\n");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("INT"); cmd.setArgs("from [c | to]"); cmd.inSection= Section.NAVIGATION; 
        cmd.setBriefDescription(""
                + "Go to position `from` or to region `from to` on current chromosome.");
        cmd.setAdditionalDescription(""
                + "If a list of integers is given, the first and last are taken as *from* and *to*. "
                + "This is handy to copy and paste intervals from the ruler above the prompt.\n"
                + "\n"
                + "* :code:`c` set the position of *from* at the center of the screen. \n"
                + "\n"
                + "* :code:`to` set the new window in the region delimited by *from* and *to*. \n"
                + "\n"
                + "Examples::\n"
                + "\n"
                + "    10~~~~~~~~~~~~~~~~~~~-> Will jump to position 10 \n"
                + "    10 1000~~~~~~~~~~~~~~-> Go to region 10-1000 \n"
                + "    10 250 500 750 1000~~-> Same as above again\n"
                + "    750 c~~~~~~~~~~~~~~~~-> Put the position 750 right in the middle\n"
                + "    750c~~~~~~~~~~~~~~~~~-> Same as '750 c' space is optional\n"
                + "\n");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("PERCENT"); cmd.setArgs("from [c | to]"); cmd.inSection= Section.NAVIGATION; 
        cmd.setBriefDescription(""
                + "Zoom into the current window delimited by given PERCENT of screen.");
        cmd.setAdditionalDescription(""
                + "PERCENT is a number in the range 0-1 mapping to the given "
                + "percent of the current genomic window. Similar to the `:code:INT` "
                + "command, one number moves the genomic window to the position located at PERCENT and two numbers "
                + "will zoom into the region PERCENT-PERCENT.\n"
                + "This command is useful to quickly focus an a feature of interest, such as "
                + "a ChIP-Seq peak or a variant.\n"
                + "\n"
                + "* :code:`c` set the position of *from* at the center of the screen. \n"
                + "\n"
                + "* :code:`to` set the new window in the region delimited by *from* and *to*. \n"
                + "\n"
                + "Examples::\n"
                + "\n"
                + "    0.25~~~~~~-> Jump to position at 25% of current screen.\n"
                + "    .25~~~~~~~-> Same as above.\n"
                + "    .25 .75~~~-> Zoom into the interval between 25-75% of current screen.\n"
                + "    .25 c~~~~~-> Put the position at 25% of current screen right in the middle.\n"
                + "    .25c~~~~~~-> Same as '.25 c' (space is optional).\n"
                + "\n");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("+"); cmd.setArgs("INT [k|m]"); cmd.inSection= Section.NAVIGATION; cmd.setPrintName("plus +");
        cmd.setBriefDescription("Move forward by `INT` bases. Suffix K/M recognized. ");
        cmd.setAdditionalDescription("Suffixes k (kilo) and M (mega) are expanded to x1000 and x1,000,000. "
                + "Examples::\n"
                + "\n"
                + "    +2m\n"
                + "    +10k\n"
                + "    +10.5k\n"
                + "\n"); 
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("-"); cmd.setArgs("INT [k|m]"); cmd.inSection= Section.NAVIGATION; cmd.setPrintName("minus -"); 
        cmd.setBriefDescription("Move backwards by INT bases. Suffix K/M recognized. ");
        cmd.setAdditionalDescription("Suffixes k (kilo) and M (mega) are expanded to x1000 and x1,000,000.\n"
                + "Examples::\n"
                + "\n"
                + "    -100\n"
                + "    -10k\n"
                + "    -10.5m\n"
                + "\n"); 
        cmdList.add(cmd);
        
        cmd= new CommandHelp(); 
        cmd.setName("f"); cmd.setArgs("[NUM=0.1]"); cmd.inSection= Section.NAVIGATION; cmd.setPrintName("f - forward");
        cmd.setBriefDescription("Move forward NUM times the size of the current window, 1/10 by default.");  
        cmdList.add(cmd);
        
        cmd= new CommandHelp(); 
        cmd.setName("b"); cmd.setArgs("[NUM=0.1]"); cmd.inSection= Section.NAVIGATION; cmd.setPrintName("b - backward");
        cmd.setBriefDescription("Move backward NUM times the size of the current window, 1/10 by default"); 
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("ff"); cmd.setArgs(""); cmd.inSection= Section.NAVIGATION;
        cmd.setBriefDescription("Move forward by 1/2 of a window. A shortcut for `f 0.5`");  
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("bb"); cmd.setArgs(""); cmd.inSection= Section.NAVIGATION; 
        cmd.setBriefDescription("Move backward by 1/2 of a window. A shortcut for `b 0.5`"); 
        cmdList.add(cmd);
                        
        cmd= new CommandHelp();
        cmd.setName("]"); cmd.setArgs("INT=1"); cmd.inSection= Section.NAVIGATION; 
        cmd.setBriefDescription("Move forward by INT screen columns"); 
        cmd.setAdditionalDescription("Same as **[** but moves forward. See **[** for details");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("["); cmd.setArgs("INT=1"); cmd.inSection= Section.NAVIGATION; 
        cmd.setBriefDescription("Move backwards by INT screen columns."); 
        cmd.setAdditionalDescription("The **[** character can be repeated "
                + "and each **[** will move by one column. Examples::\n"
                + "\n"
                + "    [~~~-> Move one screen column\n"
                + "    [[[~-> Move three columns\n"
                + "       [ 3~-> Same as above\n"
                + "       [3~~-> Same as above (space is optional)\n"
                + "\n");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("zi"); cmd.setArgs("[INT = 1]"); cmd.inSection= Section.NAVIGATION; 
        cmd.setBriefDescription("Zoom in INT times. Each zoom halves the window size. "); 
        cmd.setAdditionalDescription("To zoom quickly use INT=~5 or 10 e.g. `zi~10`");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("zo"); cmd.setArgs("[INT = 1]"); cmd.inSection= Section.NAVIGATION; 
        cmd.setBriefDescription("Zoom out INT times. Each zoom doubles the window size. ");
        cmd.setAdditionalDescription("To zoom quickly use INT=~5 or 10 e.g. `zo 10`");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("extend"); cmd.setArgs("[mid|window] [INT left] [INT right]"); cmd.inSection= Section.NAVIGATION; 
        cmd.setBriefDescription("Extend the current window by `INT` bases left and right.\n");
        cmd.setAdditionalDescription("\n"
                + "* :code:`window` (default): Extend the current window left and right by `INT` bases\n"
                + "\n"
                + "* :code:`mid` The new window is given by the midpoint of the current window "
                + "plus and minus `INT` bases left and right.\n"
                + "\n"
                + "If only one INT is given it is applied to both left and right. Negative INTs will shrink "
                + "instead of extend the window.");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("l"); cmd.setArgs(""); cmd.inSection= Section.NAVIGATION; cmd.setPrintName("l - left");
        cmd.setBriefDescription("Go to the Left half of the current window. ");
        cmd.setAdditionalDescription("Alternate the left and right command to quickly focus on a point of interest. ");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("r"); cmd.setArgs(""); cmd.inSection= Section.NAVIGATION; cmd.setPrintName("r - right");
        cmd.setBriefDescription("Go to the Right half of the current window. ");
        cmd.setAdditionalDescription("Alternate the left and right command to quickly focus on a point of interest. ");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("p"); cmd.setArgs(""); cmd.inSection= Section.NAVIGATION; 
        cmd.setBriefDescription("Go to the previous visited position. ");
        cmd.setAdditionalDescription("Similar to the back and forward arrows of an Internet browser.");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("n"); cmd.setArgs(""); cmd.inSection= Section.NAVIGATION; 
        cmd.setBriefDescription("Go to the next visited position. ");
        cmd.setAdditionalDescription("Similar to the back and forward arrows of an Internet browser.");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("next"); cmd.setArgs("[-back] [-start] [-c] [-zo INT=5] [track]"); cmd.inSection= Section.NAVIGATION; 
        cmd.setBriefDescription("Move to the next feature not overlapping the current coordinates. "); 
        cmd.setAdditionalDescription(""
                + "By default `next` centers the window on the next feature and zooms out.\n"
                + "\n"
                + "* :code:`-back` Search backwards. I.e. move to next feature on the left of the current position.\n"
                + "\n"
                + "* :code:`-start` Set the window right at the start of the feature, without centering and zooming out.\n"
                + "\n"
                + "* :code:`-c` Set the window so that the start of the feature is right in the middle of the window. "
                + "Useful to browse small features such as SNV and indels.\n"
                + "\n"
                + "* :code:`-zo INT` Zoom out INT times after having found the next feature. "
                + "  Ignored if the `-start` flag is set. If <= 0 the window spans exactly the feature coordinates. "
                + "  Default 5.\n"
                + "\n"
                + "* :code:`track` Track to search for next feature. Default to the first annotation track found.\n"
                + "\n"
                + "`next` starts searching immediately after the current window and loops thourgh each chromosome until a feature is found.");
 

        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("find"); cmd.setArgs("[-all] [-c] [-F] regex [track]"); cmd.inSection= Section.FIND; 
        cmd.setBriefDescription("Find the first record in `track` containing `regex`."); 
        cmd.setAdditionalDescription(""
                + "The search for `regex` starts from the *end* of the current window "
                + "(so the current window is not searched) and moves forward on the current chromosome. "
                + "At the end  of the current chromosome move to the next chromosomes and then restart at "
                + " the start of the initial one. The search stops at the first match found. If `track` is omitted "
                + "the first interval track found is searched.\n"
                + "\n"
                + "* :code:`-all`: Return the region containing **all** the regex matches.\n"
                + "\n"
                + "* :code:`-c` Match in CASE SENSITIVE mode. Default is case insensitive (changed in v1.12).\n"
                + "\n"
                + "* :code:`-F`: Interpret `regex` as a fixed, literal string instead of as a regex.\n"
                + "\n"
                + "Examples::\n"
                + "\n"
                + "    find -all ACTB genes.gtf~-> Find all the matches of ACTB. Case ignored\n"
                + "    find -c 'ACTB gene'~~~~~~-> Find the first match of 'ACTB gene'. Case sensitive\n"
                + "\n"
                + "Use single quotes to define patterns containing spaces."); 
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("seqRegex"); cmd.setArgs("[-iupac] [-c] [regex]"); cmd.inSection= Section.FIND; 
        cmd.setBriefDescription("Find regex in reference sequence and show matches as an additional track. ");
        cmd.setAdditionalDescription("Options:\n"
                + "\n"
                + "* :code:`regex` Regex to search. If missing the seq regex track is removed.\n"
                + "\n"
                + "* :code:`-iupac` Enable the interpretation of the IUPAC ambiguity code. NB: "
                + "This option simply converts IUPAC chracters to the corresponding regex.\n"
                + "\n"
                + "* :code:`-c` Enable case-sensitive matching. Default is to ignore case.\n"
                + "\n"
                + "Examples::\n"
                + "\n"
                + "    seqRegex~ACTG~~~~~~~~-> Case insensitive, actg matched\n"
                + "    seqRegex -c ACTG ~~~~-> Case sensitive, will not match actg\n"
                + "    seqRegex -iupac ARYG~-> Interpret (converts) R as [AG] and Y as [CT]\n"
                + "    seqRegex~~~~~~~~~~~~~-> Disable regex matching track\n"
                + "\n"
                + "To save matches to file, see the `print` command. This command is ignored if the reference fasta sequence is missing."
                + "");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        // cmd.setName("bookmark"); cmd.setArgs("[name] | [-rm] | [-print] | [> [file]]"); cmd.inSection= Section.FIND;
        cmd.setName("bookmark"); cmd.setArgs("[-d] [-n name] [-print] [> file] [chrom:from-to]"); cmd.inSection= Section.FIND;
        cmd.setBriefDescription("Creates a track to save positions of interest.");
        cmd.setAdditionalDescription(""
                + "Without arguments, add the current position to the bookmark track. Options:\n"
                + "\n"
                + "* :code:`chrom:from-to` Bookmark this region. If chrom is omitted, use the current chromosome.\n"
                + "\n"
                + "* :code:`-d` Remove the bookmark at coordinates [chrom:from-to].\n"
                + "\n"
                + "* :code:`-n name` Use name for this new bookmark.\n"
                + "\n"
                + "* :code:`-print` prints to screen the list of current bookmarks.\n"
                + "\n"
                + "* :code:`> file` saves the bookmark track to file.\n"
                + "\n"
                + "Examples::\n"
                + "\n"
                + "    bookmark~~~~~~~~~~~~~~-> Add the current window to bookmarks.\n"
                + "    bookmark 100 ~~~~~~~~~-> Bookmark position 100 on current chrom\n"
                + "    bookmark 100-110~~~~~~-> Bookmark position 100-110 on current chrom\n"
                + "    bookmark chr1:100 ~~~~-> Bookmark position chr1:100\n"
                + "    bookmark -d chr1:100~~-> Delete bookmark at chr1:100\n"
                + "    bookmark > books.txt~~-> Save to file books.txt\n"
                + "    bookmark -print ~~~~~~-> Show table of bookmarks\n"
                + "\n"
                + "");
        cmdList.add(cmd);

        
        cmd= new CommandHelp();
        cmd.setName("grep"); cmd.setArgs("[-i = .*] [-e = ''] [-c] [-F] [-v] [track_regex = .*]..."); cmd.inSection= Section.DISPLAY; 
        cmd.setBriefDescription("Similar to grep command, filter for features including or excluding patterns.");
        cmd.setAdditionalDescription(""
                + "Options:\n"
                + "\n"
                + "* :code:`-i regex`  Show features matching this regex.\n"
                + "\n"
                + "* :code:`-e regex` Exclude features matching this regex.\n"
                + "\n"
                + "* :code:`-c` Match in CASE SENSITIVE mode. Default is case insensitive (changed in v1.12).\n"
                + "\n"
                + "* :code:`-F` Interpret `regex` in `-i` and `-e` as a fixed, literal string instead of as a regex.\n"
                + "\n"
                + "* :code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "* :code:`track_regex` Apply to tracks matched by `track_regex`.\n"
                + "\n"
                + "*NOTES*\n"
                + "\n"
                + "* Use *single quotes* to delimit patterns containing spaces e.g. :code:`-i 'ACTB gene'`\n"
                + "\n"
                + "Regex `-i` and `-e` are applied to the raw lines as read from source file and "
                + "it is applied only to annotation tracks (GFF, BED, VCF, etc). For example::\n"
                + "\n"
                + "    grep -i RNA -e mRNA gtf gff\n"
                + "\n"
                + "Will show the rows containing 'RNA' but will hide those containing 'mRNA', applies "
                + "to tracks whose name matches 'gtf' or 'gff'."
                + ""
                + "\nWith no arguments reset to default: :code:`grep -i .* -e ^$ .*` which means show everything, hide nothing, apply to all tracks."
                );
        cmdList.add(cmd);        

        cmd= new CommandHelp();
        cmd.setName("awk"); cmd.setArgs("[-off ...] [-F sep_re] [-v VAR=var] [-V] '<script>' [track_regex = .*]..."); cmd.inSection= Section.DISPLAY; 
        cmd.setBriefDescription("Advanced feature filtering using awk syntax.");
        cmd.setAdditionalDescription("awk offers finer control then :code:`grep` to filter records in tabular format.\n"
                + "\n"
                + "Awk is column oriented. Awk splits each line into a list using a given regular "
                + "expression as delimiter (default delimiter is the TAB "
                + "character). To access an item, i.e. a column, use "
                + "the syntax :code:`$n` where *n* is the position of the item in the list, "
                + "e.g. :code:`$3` will access the third field (i.e. 3rd column). "
                + "The variable :code:`$0` holds the entire line as single string.\n"
                + "\n"
                + "Awk understands numbers and mathematical operators. "
                + "With awk you can filter records by numeric values in one or more fields since"
                + " numbers are handled as such. You can also perform arithmetic operations and filter on the results.\n"
                + "\n"
                + "*OPTIONS*\n"
                + "\n"
                + "* :code:`-off track_re ...`  Turn off awk filtering for tracks captured by the list of regexes.\n"
                + "\n"
                + "* :code:`-F <sep_re>` Use regular expression <sep_re> as column separator. Default is '\\t' (tab). "
                + "To separate on white space use e.g. '\\b' (backspace) or '\\s' (any white space). Do not use ' '. \n"
                + "\n"
                + "* :code:`-v VAR=var` Pass to awk script the variable VAR with value var. Can be repeated.\n"
                + "\n"
                + "* :code:`script` The awk script to be executed. Must wrapped in single quotes.\n"
                + "\n"
                + "* :code:`-V` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "**ADDITIONAL FEATURES**\n"
                + "\n"
                + "Function :code:`get(...)` can indistinctly be applied to GTF, GFF, SAM records and to INFO "
                + "and FORMAT fields in VCF files. Double quoting around <tag> is optional.\n"
                + "\n"
                + "* :code:`get(tag)` on **GTF**\n"
                + "\n"
                + "Return the value of tag attribute.\n"
                + "\n"
                + "* :code:`get(tag, [value_idx])` on **GFF**\n"
                + "\n"
                + "Return the value of tag attribute. If the attribute contains multiple values "
                + "return the value at index value_idx (1-based). If value_idx is missing (as default), return the entire value as it is.\n"
                + "\n"
                + "* :code:`get(tag)` on **SAM**\n"
                + "\n"
                + "Return the value of the given sam tag.\n"
                + "\n"
                + "* :code:`get(tag, [value_index])` on **VCF**\n"
                + "\n"
                + "Return the value of the given "
                + "**INFO** tag. If the tag contains multiple values, optionally return only the value at index *value_index*. "
                + "If necessary, prepend 'INFO/' to tag to disambiguate it from FORMAT tags or if the header does not "
                + "contain this tag. If the tag is of type 'Flag', return 1 if present, 0 otherwise.\n"
                + "\n"
                + "* :code:`get(tag, [sample_idx], [value_idx])` on **VCF**\n"
                + "\n"
                + "Return the value of the **FORMAT** tag for sample index *sample_idx* "
                + "(default to 1, first sample). If the tag contains multiple values, optionally return the value "
                + "at index *value_idx*. If necessary, prepend 'FMT/' to tag to disambiguate it from INFO tags "
                + "or if the header does not contain this tag.  If the tag is of type 'Flag', return 1 if present, 0 otherwise.\n"
                + "\n"
                + "* Column headers\n"
                + "\n"
                + "The following variables are replaced by the appropriate column indexes, so they "
                + "can be used to easily select columns. Make sure the track types are selected to be compatible "
                + "with the headers.\n"
                + "\n"
                + "- bam tracks::\n"
                + "\n"
                + "    $QNAME, $FLAG, $RNAME, $POS, $MAPQ, $CIGAR, $RNEXT, $PNEXT, $TLEN, $SEQ, $QUAL\n"
                + "\n"
                + "- vcf tracks::\n"
                + "\n"
                + "    $CHROM, $POS, $ID, $REF, $ALT, $QUAL, $FILTER, $INFO, $FORMAT\n"
                + "\n"
                + "- gtf and gff tracks::\n"
                + "\n"
                + "    $SEQNAME, $SOURCE, $FEATURE, $START, $END, $SCORE, $STRAND, $FRAME, $ATTRIBUTE\n"
                + "\n"
                + "- bed tracks::\n"
                + "\n"
                + "    $CHROM, $START, $END, $NAME, $SCORE, $STRAND, $THICKSTART, $THICKEND, $RGB, $BLOCKCOUNT, $BLOCKSIZES, $BLOCKSTARTS\n"
                + "\n"
                + "*EXAMPLES*\n"
                + "\n"
                + "Note the use of single quotes to wrap the actual script and the use of "
                + "double quotes inside the script.\n"
                + "\n"
                + "* Filter for lines where the 4th column is between 10 and 100. Apply only to tracks "
                + "matching '.gtf' or '.gff'::\n"
                + "\n"
                + "    awk '$4 > 10 && $4 <= 100' .gtf .gff\n"
                + "\n"
                + "* Filter for either perfect a match or by matching a regex on 3rd column. "
                + "Apply to all tracks. The second example matches regex on the entire line (similar to grep), "
                + "The third example also requires features to be on + strand::\n"
                + "\n"
                + "    awk '$3 == \"exon\" || $3 \\~ \".*_codon\"'\n"
                + "    \n"
                + "    awk '$0 \\~ \".*_codon\"'\n"
                + "    \n"
                + "    awk '($3 == \"exon\" || $3 \\~ \".*_codon\") && $7 == \"+\"'\n"
                + "\n"
                + "* Filter for features size (assuming bed format) and for values after log10 transformation. "
                + "For log10 we need to change base using ln(x)/ln(10)::\n"
                + "\n"
                + "    awk '($3 - $2) > 1000 && (log($4)/log(10)) < 3.5'\n"
                + "\n"
                + "* Remove awk filter for tracks captured by .gff and .gtf::\n"
                + "\n"
                + "    awk -off .gtf .gff\n"
                + "\n"
                + "* Return bam records where NM tag (edit distance) is > 0. Double quotes around NM are optional::\n"
                + "\n"
                + "    awk 'get(NM) > 0' .bam\n"
                + "\n"
                + "* Filter vcf records by FORMAT tag. Suppose tag AD in the *second* sample is :code:`63,7`::\n"
                + "\n"
                + "    awk 'get(AD, 2) ...' my.vcf ~~~~~# get() returns string '63,7'\n"
                + "    awk 'get(AD, 2, 1) ...' my.vcf ~~# get() returns 63\n"
                + "    awk 'get(AD, 2, 2) ...' my.vcf ~~# get() returns 7\n"
                + "    awk 'get(FMT/AD, 2) ...' my.vcf ~# If AD is also in INFO or missing in header\n"
                + "\n"
                + "* Using header variables::\n"
                + "\n"
                + "    awk '$FEATURE \\~ \"CDS\" && $START > 1234' my.gff\n"
                + "\n"
                + "With no args, turn off awk for all tracks.\n"
                + "\n"
                + "*NOTES & LIMITATIONS*\n"
                + "\n"
                + "* This is a java implementation of awk and it is independent on whether awk is "
                + "on the local system. It should behave very similar to UNIX awk and therefore it has lots of "
                + "functionalities. "
                + "In fact, awk is a programming language in itself, search Google for more. "
                + "The original code is from https://github.com/hoijui/Jawk\n"
                + "\n"
                + "* Use awk only to filter features, do not use it to edit them. If features are "
                + "changed by the awk script than nothing will be retained. This is because "
                + "the awk command first collects the output from awk, then it matches the features in "
                + "the current window with those collected from awk.\n"
                + "\n"
                + "* Each line is processed independently of the others as a separate awk execution. "
                + "This means that you cannot filter one line on the bases of previous or following lines.\n"
                + "\n"
                + "* This awk is slow, about x5-10 times slower than UNIX awk. For few thousand records "
                + "the slowdown should be acceptable. Other things being equal, use `grep` instead.\n"
                + "\n"
                + "* The default delimiter is TAB not any white space as in UNIX awk.\n"
                + "\n"
                + "* An invalid script throws an ugly stack trace to stderr. To be fixed.");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("featureColor"); cmd.setArgs("[-r/-R expression color] [-v] [track_regex = .*]..."); cmd.inSection= Section.DISPLAY; 
        cmd.setBriefDescription("Set colour for features captured by expression. ");
        cmd.setAdditionalDescription(""
                + "This command affects interval feature tracks (bed, gff, vcf, etc) "
                + "and overrides the default color "
                + "for the lines captured by "
                + "the expression. Expression is a regex or an awk script (autodetermined). "
                + "It is useful to highlight features containg a "
                + "string of interest, "
                + "such as 'CDS' in gff files, or features where a numeric field satisfy a filter.\n"
                + "\n"
                + "Options:\n"
                + "\n"
                + ":code:`-r <expression> <color>` Features matching :code:`expression` will "
                + "have color :code:`color`. "
                + "The expression is interpreted as regex or as an awk script and it "
                + "is applied to the raw lines as read from file. "
                + "This option takes exactly two arguments and can be given zero or more times.\n"
                + "\n"
                + ":code:`-R <expression> <color>` Same as :code:`-r` but sets color for features NOT "
                + "matched by regex.\n"
                + "\n"
                + ":code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + ":code:`[track_regex]` Apply to tracks captured by this list of regexes.\n"
                + "\n"
                + "Example::\n"
                + "\n"
                + "    featureColor -r CDS plum2 -r exon grey\n"
                + "    featureColor bed~~~~~~~~~-> Reset to default the track matching 'bed'\n"
                + "       featureColor -R CDS grey -> Grey all features except those matching CDS\n"
                + "    \n"
                + "    Color blue where 9th field is > 3; color red where 9th is > 6\n"
                + "    featureColor -r '$9 > 3' blue -r '$9 > 6' red\n"
                + "\n"
                + "Colors can be specified by name, name prefix, or integer in range 0-255. "
                + "Available colours:\n"
                + "\n"
                + Xterm256.colorShowForTerminal().replaceAll(" ", "~") 
                + "\n");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName(Command.featureDisplayMode.toString()); cmd.setArgs("[-expanded | -collapsed | -oneline] [-v] [track_regex = .*]..."); cmd.inSection= Section.DISPLAY; 
        cmd.setBriefDescription("Set how annotation features should be displayed.\n");
        cmd.setAdditionalDescription("\n"
                + "* :code:`-expanded/-e` Put overalpping features on different lines (default).\n"
                + "\n"
                + "* :code:`-collapsed/-c` Merge features with overlapping genomic coordinates.\n"
                + "\n"
                + "* :code:`-oneline/-o` Merge features overlapping on screen coordinates. This option makes the track "
                + "occupy only one line.\n"
                + "\n"
                + "* :code:`-v` Invert selection: apply changes to tracks not selected by list of track_regex\n"
                + "\n"
                + "* :code:`track_regex` List of regexes to select tracks. Default: .* (all tracks).\n"
                + "\n"
                + "Without arguments toggle between expanded and collapsed mode. ");
        cmdList.add(cmd);        

        cmd= new CommandHelp();
        cmd.setName("readsAsPairs"); cmd.setArgs("[-on | -off] [-v] [track_regex = .*]..."); cmd.inSection= Section.ALIGNMENTS; 
        cmd.setBriefDescription("Show SAM records as pairs.\n");
        cmd.setAdditionalDescription("If set, properly paired reads in the current window are showed "
                + "joined up by tildes.\n"
                + "\n"
                + "* :code:`-on|-off` Turn on/off the pairing mode. Or toggle between the two modes if none of these flags is set.\n"
                + "\n"
                + "* :code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "* :code:`[track_regex = .*]...` Apply to read tracks captured by these regexes.\n"
                );
        cmdList.add(cmd);        

        cmd= new CommandHelp();
        cmd.setName("filterVariantReads"); cmd.setArgs("[-r from/to] [-all] [-v] [track_regex = .*]..."); cmd.inSection= Section.ALIGNMENTS; 
        cmd.setBriefDescription("Filter reads containing a variant in the given interval.\n");
        cmd.setAdditionalDescription(":code:`filterVariantReads` selects for reads where the read sequence "
                + "mismatches with the reference sequence in the given interval on the current chromosome. "
                + "This command is useful to inspect reads supporting a putative alternate allele at a "
                + "variant site.\n"
                + "\n"
                + "NOTES\n"
                + "\n"
                + "* :code:`filterVariantReads` requires a reference fasta sequence to be set, e.g. "
                + "via the command line option :code:`-fa <ref.fa>` or with command :code:`setGenome`.\n"
                + "\n"
                + "* The CIGAR string determines a mismatch between read and reference. Consequently, there may be an inconsistency "
                + "between variant positions in reads and positions in a VCF file if some normalization "
                + "or indel realignment has been performed by the variant caller that generated the VCF. In such cases "
                + "consider enlarging the target interval.\n"
                + "\n"
                + "* The position (POS) of deletions in VCF files refer to the first non-deleted base on the reference. Therefore, "
                + "the interval to :code:`-r` should be POS+1 to filter for reads supporting a deletion (but see also the previous point).\n"
                + "\n"
                + "OPTIONS\n"
                + "\n"
                + "* :code:`-r region` Select reads mismatching in this interval. *region* can be given as: a single position, "
                + "a position plus and/or minus an offset, an interval. See examples.\n"
                + "\n"
                + "* :code:`-all` Return *all* reads intersecting the :code:`-r` interval, not just the variant ones.\n"
                + "\n"
                + "* :code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "* :code:`[track_regex = .*]...` Apply to read tracks captured by these regexes.\n"
                + "\n"
                + "EXAMPLES::\n"
                + "\n"
                + "    filterVariantReads -r 1000+10 ~~<- From 1000 to 1010\n"
                + "    filterVariantReads -r 1000-10 ~~<- From 990 to 1000\n"
                + "    filterVariantReads -r 1000+/-10 <- From 990 to 1010\n"
                + "    filterVariantReads -r 1000:1100 <- From 1000 to 1100\n"
                + "    filterVariantReads -r 1000 vars.*vcf <- Apply to tracks captured by `vars.*vcf`\n"
                + "    filterVariantReads ~~~~~~~~~~~~~<- Remove filter for all tracks\n"
                );
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("gap"); cmd.setArgs("[-on | -off] [-v] [track_regex = .*]..."); cmd.inSection= Section.DISPLAY; 
        cmd.setBriefDescription("Display features with or without a separating gap. ");
        cmd.setAdditionalDescription("With :code:`gap -on` (default) features which on screen do not have "
                + "at least one space separating them are moved to different lines. In this way it is clear where one "
                + "feature starts and ends. "
                + "If gap is unset (:code:`gap -off`) features are shown more packed.\n"
                + "\n"
                + ":code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "Example with :code:`gap -on`::\n"
                + "\n"
                + "    ||||||\n"
                + "    ~~~~~~||||||\n"
                + "\n"
                + "With :code:`gap -off` these two features look like::\n"
                + "\n"
                + "    ||||||||||||\n"
                + "\n"
                + "As elsewhere, this command is applied to all tracks captured by the list of regexes.");
        cmdList.add(cmd);        

        
        cmd= new CommandHelp();
        cmd.setName("nameForFeatures"); cmd.setArgs("[attribute_name = NULL | -na] [-v] [track_regex = .*]..."); cmd.inSection= Section.DISPLAY; 
        cmd.setBriefDescription("Select column index or GFF attribute to name features. ");
        cmd.setAdditionalDescription("If the track is of type BED :code:`attribute_name` is "
                + "expected to be a column index (first column has index 1). "
                + "If track is of type GTF/GFF, :code:`attribute_name` is the key from "
                + "the attributes column (9th column). Use attribute NULL to "
                + "reset to default choice of attribute. To suppress "
                + "printing of the name use `-na`."
                + "Applies to annotation tracks captured by the list `track_regex`.\n"
                + "\n"
                + ":code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "Example, given "
                + "the gtf feature::\n"
                + "\n"
                + "    chr1 . CDS  10 99 . + 2 gene_id \"PTGFRN\"; transcript_id \"NM_020440\";\n"
                + "\n"
                + "Use gene_name as feature name or transcript_id::\n"
                + "\n"
                + "    nameForFeatures gene_name genes.gtf .*gff\n"
                + "    PTGFRN_CCCCCCCCC\n"
                + "    \n"
                + "    nameForFeatures transcript_id genes.gtf .*gff\n"
                + "    NM_020440_CCCCCC\n"
                + "    \n"
                + "    nameForFeatures -na\n"
                + "    CCCCCCCCCCCCCCCC <- Do not show name"
                + "    \n"
                + "\n");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("trackHeight"); cmd.setArgs("[-v] INT [track_regex = .*]..."); cmd.inSection= Section.DISPLAY; 
        cmd.setBriefDescription("Set track height to INT lines of text for all tracks matching regexes. ");
        cmd.setAdditionalDescription("Setting height to zero hides the track and skips the processing altogether. "
                + "This is useful to speed up the browsing when large bam files are present. Use infoTrack "
                + "to see which tracks are hidden.\n"
                + "\n"
                + ":code:`-v` Invert selection: apply changes to tracks not selected by list of track_regex\n"
                + "\n"
                + "Example::\n"
                + "\n"
                + "    trackHeight 5 aln.*bam gtf"
                + "\n");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("bedToBedgraph"); cmd.setArgs("[-v] [track_regex = .*]..."); cmd.inSection= Section.DISPLAY; 
        cmd.setBriefDescription("Switch format from BED to BEDGRAPH and viceversa. ");
        cmd.setAdditionalDescription("Tracks captured by regex(es) are switched BED <-> BEDGRAPH\n"
                + "\n"
                + ":code:`-v` Invert selection: apply changes to tracks not selected by list of track_regex\n"
                + "\n"
                + "See also :code:`dataCol` to set the score column for bedgraph tracks\n"
                + "\n");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("ylim"); cmd.setArgs("[-v] <NUM|min|na> <NUM|min|na> [track_regex = .*]..."); cmd.inSection= Section.DISPLAY; 
        cmd.setBriefDescription("Set the y-axis limit for all tracks matched by regexes.");
        cmd.setAdditionalDescription("The first two arguments set the min and max limits. The 3rd "
                + "argument is a list of regexes to capture the tracks to reset. "
                + "Argument min and max can be:\n"
                + "\n"
                + "* :code:`NUM` Numeric, fix the limits exactly to these values\n"
                + "\n"
                + "* :code:`na` Scale tracks to their individual min and/or max\n"
                + "\n"
                + "* :code:`min` and :code:`max` Set to the min and max of **all** tracks.\n"
                + "\n"
                + ":code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "This command applies only to tracks displaying quantitative data on y-axis (e.g. bigwig, tdf), "
                + "the other tracks are unaffected. Examples::\n"
                + "\n"
                + "    ylim 0 50~~~~~~-> Set min= 0 and max= 50 in all tracks.\n"
                + "    ylim 0 na~~~~~~-> Set min to 0 and autoscale the max. Apply to all tracks\n"
                + "    ylim na na tdf~-> Autoscale min and max. Apply to all tracks matching 'tdf'\n"
                + "    ylim min max~~~-> Set to the min and max of all tracks\n"
                + "\n");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("colorTrack"); cmd.setArgs("[-v] color [track_regex = .*]..."); cmd.inSection= Section.DISPLAY; 
        cmd.setBriefDescription("Set colour for tracks matched by regex. ");
        cmd.setAdditionalDescription(""
                + "Colors can be specified by name or by a value between 0 and 255. "
                + "If only the prefix of a color name is given, the first name found starting with "
                + "the prefix is returned, e.g. 'darkv' is interpreted as 'darkviolet'. "
                + "Names are case insensitive.\n"
                + "\n"
                + "See also :code:`featureColor` for BED and GTF/GFF files\n"
                + "\n"
                + ":code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "Available colours are from the Xterm256 palette: \n"
                + "\n"
                + Xterm256.colorShowForTerminal().replaceAll(" ", "~") 
                + "\n"
                + "\n"
                + "Example::\n"
                + "\n"
                + "    colorTrack cyan1 ts.*gtf ts.*bam \n"
                + "    colorTrack 40 ~~~~~~~~~~~~~~~~~~<- By INT\n"
                + "    colorTrack darkv ~~~~~~~~~~~~~~~<- Same as darkviolet\n"
                + "\n");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("hideTitle"); cmd.setArgs("[-on | -off] [-v] [track_regex = .*]..."); cmd.inSection= Section.DISPLAY; 
        cmd.setBriefDescription("Set the display of the title line matched by track_regex. ");
        cmd.setAdditionalDescription(""
                + "Without argument -on or -off toggle between the two modes for all "
                + "tracks matched by the list of regexes.\n"
                + "\n"
                + ":code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("genotype"); cmd.setArgs("[-n 10] [-s .*] [-r pattern rplc] [-f expr] [-v] [track_regex = .*]..."); cmd.inSection= Section.DISPLAY; 
        cmd.setBriefDescription("Customise the genotype rows printed under the VCF tracks. ");
        cmd.setAdditionalDescription(""
                + "\n"
                + "\n"
                + ":code:`-n` Display up to this many samples (rows). -1 for no limit.\n"
                + "\n"
                + ":code:`-s` Select samples matching this regex.\n"
                + "\n"
                + ":code:`-r` Edit sample names to replace <pattern> with <replacement>. Names are edited only for "
                +     "display. To completely hide names replace with empty string :code:`-r .* ''`. "
                +     "To restore original names use a regex matching nothing e.g. '^$'\n"
                + "\n"
                + ":code:`-f` Filter samples using an expression in javascript syntax. See below for details.\n"
                + "\n"
                + ":code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "FILTER EXPRESSION\n"
                + "\n"
                + "Samples can be filtered by applying arbitrary expressions to the VCF records. "
                + "The VCF fields of a sample are accessed using the syntax :code:`{TAG}`.\n"
                + "\n"
                + "TAG is one of the fixed fields: CHROM, POS, ID, REF, ALT, QUAL, FILTER, or one of "
                + "the INFO or FORMAT tags. In case of ambiguity, the prefix 'INFO/' or 'FMT/' "
                + "should be used to identify the target "
                + "tag (e.g. :code:`{FMT/ID}` will access the ID field in FORMAT rather than the ID in the header).\n"
                + "\n"
                + "The value(s) in a TAG are converted to the appropriate data type (Integer, String, etc). "
                + "Tags holding more than one value are returned as arrays whose individual values "
                + "should be accessed using the syntax :code:`[index]`. "
                + "E.g. :code:`{ALT}[0]` will access the first alternate allele.\n"
                + "\n"
                + "Note that the ALT and FILTER fields are always arrays, even if only one allele is present.\n"
                + "\n"
                + "After substitution of the :code:`{TAG}` placeholders with the actual values, the expression string "
                + "is evaluated as a javascript script so any valid JS code is allowed including the common operators: "
                + ":code:`> < == != && ||`.\n"
                + "\n"
                + "Importantly, the result of the expression must be a boolean, i.e. it must evaluate to true or false.\n"
                + "\n"
                + "For each sample, the expression is evaluated for each VCF record in the current window "
                + "and if ANY record returns *true*, the sample is filtered-in. To apply the filter "
                + "to specific records either include only those records using e.g. commands :code:`grep` "
                + "or :code:`awk` or make the expression more selective, e.g. by including the POS field.\n"
                + "\n"
                + "As elsewhere in ASCIIGenome, if the argument (expression) contains spaces it "
                + "must be enclosed in single quotes and single quotes inside the expression must be escaped. "
                + "To remove the expression filter pass a blank string as argument :code:`-f ' '` (note "
                + "the white space between single quotes).\n"
                + "\n"
                + "The following tags can be used to filter on the genotype. When substituted, they evaluate to "
                + "true according to the sample genotype. Testing the :code:`{GT}` tag, e.g. "
                + ":code:`{GT} == \"0/1\"`, achieves a similar result and gives more control "
                + "but using these tags is less error prone:\n"
                + "\n"
                + "* :code:`{HOM}` genotype is homozygote.\n\n"
                + "* :code:`{HET}` genotype is heterozygote.\n\n"
                + "* :code:`{HOM_REF}` genotype is homozygote reference.\n\n"
                + "* :code:`{HOM_VAR}` homozygote for an ALT allele.\n\n"
                + "* :code:`{HET_NON_REF}` heterozygote and all alleles are non-reference.\n\n"
                + "* :code:`{CALLED}` at least one allele is not a missing value ('.' in vcf).\n\n"
                + "* :code:`{NO_CALL}` No allele is called (e.g. it appears as ./. in vcf).\n\n"
                + "* :code:`{MIXED}` genotype is comprised of both calls and no-calls.\n"
                + "\n"
                + "Examples of filters::\n"
                + "\n"
                + "    genotype -f '{DP} > 30' -> Display samples having DP > 30\n"
                + "    genotype -f '{DP} > 30 && {ID} == \"rs99\"' -> Select also for ID\n"
                + "    genotype -f '{FMT/XA} > 30 && {INFO/XA} == \"foo\"' -> Disambiguate tags\n"
                + "    genotype -f '{ALT}[0] == \"C\"' ~-> Access the first ALT allele\n"
                + "    genotype -f '{HOM_REF} == false' -> Discard if homozygote ref.\n"
                + "\n");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("editNames"); cmd.setArgs("[-t] [-v] <pattern> <replacement> [track_re=.*]..."); cmd.inSection= Section.DISPLAY; 
        cmd.setBriefDescription("Edit track names by substituting regex pattern with replacement.");
        cmd.setAdditionalDescription("Pattern and replacement are required arguments, "
                + "the default regex for track is '.*' (i.e. all tracks).\n"
                + "\n"
                + "* :code:`-t` (test) flag shows what renaming would be done without actually editing the names.\n"
                + "\n"
                + "* :code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "Use \'\' (empty string in single quotes) to replace pattern with nothing. "
                + "Examples: Given track names 'fk123_hela.bam#1' and 'fk123_hela.bed#2'::\n"
                + "\n"
                + "    editNames fk123_ '' ~~~~~~-> hela.bam#1, hela.bed#2\n"
                + "    editNames fk123_ '' bam ~~-> hela.bam#1, fk123_hela.bed#2\n"
                + "    editNames _ ' ' ~~~~~~~~~~-> fk123 hela.bam#1,  fk123 hela.bed#2\n"
                + "    editNames ^.*# cells ~~~~~-> cells#1, cells#2\n"
                + "    editNames ^ xx_ ~~~~~~~~~~-> xx_fk123_hela.bam#1, xx_fk123_hela.bed#2 (add prefix)\n"
                + "");
        cmdList.add(cmd);

        
        
        cmd= new CommandHelp();
        cmd.setName("dataCol"); cmd.setArgs("[-v] [index = 4] [track_regex = .*]..."); cmd.inSection= Section.DISPLAY; 
        cmd.setBriefDescription("Select data column for bedgraph tracks containing regex. ");
        cmd.setAdditionalDescription("First column has index 1. This command applies only to "
                + "tracks of type bedgraph.\n"
                + "\n"
                + ":code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "For example, use column 5 on tracks containing #1 and #3::\n "
                + "\n"
                + "    dataCol 5 #1 #3\n"
                + "\n");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName(Command.print.toString()); cmd.setArgs("[-n INT] [-full] [-off] [-round INT] [-hl re] [-esf] [-v] [-sys CMD] [track_regex = .*]... [>|>> file]"); cmd.inSection= Section.DISPLAY; 
        cmd.setBriefDescription("Print lines for the tracks matched by `track_regex`. ");
        cmd.setAdditionalDescription("Useful to show exactly what features are present in the current window. "
                + "Features are filtered in/out according to the :code:`grep` command. Options:\n"
                + "\n"
                + "* :code:`track_regex` Apply to tracks matched by one or more of these regexes.\n"
                + "\n"
                + "* :code:`-n INT=10` Print up to this many lines, default 10. No limit if < 0.\n"
                + "\n"
                + "* :code:`-clip` Clip lines longer than the screen width. This is the default.\n"
                + "\n"
                + "* :code:`-full` Wrap lines longer than the screen width.\n"
                + "\n"
                + "* :code:`-round INT` Round numbers to this many decimal places. "
                + "What constitutes a number is inferred from context. Default 3, do not round if < 0.\n"
                + "\n"
                + "* :code:`-hl regex` Highlight substrings matching regex. If regex matches a FORMAT tag in a VCF record, "
                + "highlight the tag itself and also the sample values corresponding to that tag. "
                + "Alternatively, regex may be a comma separated list of column indexes to highlight. "
                + "Indexes are recognized by the $ prefix. E.g. :code:`-hl '$1, $3, $10'` will highlight columns 1, 3, 10.\n"
                + "\n"
                + "* :code:`-esf` Explain SAM Flag. Add to SAM flag an abbreviated description.\n"
                + "\n"
                + "* :code:`-off` Turn off printing.\n"
                + "\n"
                + "* :code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "* :code:`-sys` Parse the raw output with the given system command(s). Use :code:`-sys null` to turn off "
                + "the system commands. These commands are executed "
                + "by :code:`bash` so bash is expected to be available on the system. The commands should read from stdin and write "
                + "to stdout, this is usually the case for Unix commands like :code:`cut`, :code:`sort`, etc. "
                + "The command string must be enclosed in single quotes, single quotes inside the string can be escaped as \\' (backslash-quote)\n"
                + "\n"
                + "* :code:`>` and :code:`>>` Write output to `file`. `>` overwrites and `>>` appends to existing file. "
                + "The %r variable in the filename is expanded to the current genomic coordinates. Writing to file overrides "
                + "options -n and -off, lines are written in full without limit.\n"
                + "\n"
                + "Without options toggle tracks between OFF and CLIP mode.\n"
                + "\n"
                + "Examples::\n"
                + "\n"
                + "    print~~~~~~~~~~~~~~~~~~~~~~~~-> Print all tracks, same as `print .*`\n"
                + "    print -off~~~~~~~~~~~~~~~~~~~-> Turn off printing for all tracks\n"
                + "    print genes.bed >> genes.txt~-> Append features in track(s) 'genes.bed' to file\n"
                + "    print -sys 'cut 1-5 | sort'~~-> Select columns with `cut` and then sort\n"
                + "    print -sys null~~~~~~~~~~~~~~-> Turn off the execution of sysy commands\n"
                );
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("setGenome"); cmd.setArgs("fasta|bam|genome"); cmd.inSection= Section.GENERAL; 
        cmd.setBriefDescription("Set genome and reference sequence.");
        cmd.setAdditionalDescription("The genome, i.e. the list of contig names and sizes, "
                + "can be extracted from the fasta reference, from a bam file or from "
                + "a genome identifier (e.g. hg19). If a fasta file is used also the "
                + "reference sequence becomes available.\n"
                + "\n"
                + "Without arguments, set the genome using the last opened fasta file, if any and "
                + "if compatible with the current tracks.");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("setConfig"); cmd.setArgs("<file|tag> | <key> <value>"); cmd.inSection= Section.GENERAL; 
        cmd.setBriefDescription("Set configuration arguments.");
        String confHelp= Config.help().replaceAll(" ", "~")
                .replaceAll("^", "~~~~").
                replaceAll("\n", "\n~~~~"); // These are to indent for code block
        cmd.setAdditionalDescription("\n"
                + "\n"
                + "If only one argument is given then the entire settings are replaced. "
                + "Configuration can be set with one of the built-in "
                + "themes: 'black_on_white', 'white_on_black', 'metal'. "
                + "Alternatively, configuration can be read from file. For examples "
                + "files see \n"
                + "https://github.com/dariober/ASCIIGenome/blob/master/resources/config/\n"
                + "\n"
                + "If two arguments are given, they are taken as a key/value pair to reset.\n"
                + "\n"
                + "Examples::\n"
                + "\n"
                + "    setConfig metal\n"
                + "    setConfig /path/to/mytheme.conf\n"
                + "       setConfig max_reads_in_stack 20000 <- Reset this param only\n"
                + "\n"
                + "Parameters and current settings::\n"
                + "\n"
                + confHelp);
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("explainSamFlag"); cmd.setArgs("INT [INT ...]"); cmd.inSection= Section.GENERAL;
        cmd.setBriefDescription("Explain the list of bitwise SAM flags. ");
        cmd.setAdditionalDescription("Decode one or more sam flags to human readable form and print them as a table. "
                + "Similar to "
                + "https://broadinstitute.github.io/picard/explain-flags.html");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("show"); cmd.setArgs("<arg>"); cmd.inSection= Section.GENERAL;
        cmd.setBriefDescription("Show or set features to display. ");
        cmd.setAdditionalDescription("The argument :code:`arg` takes the following choices:\n"
                + "\n"
                + "* :code:`genome`: Show chromosomes and their sizes as barplot provided a genome file is available.\n"
                + "\n"
                + "* :code:`trackInfo`: Show information on tracks.\n"
                + "\n"
                + "* :code:`gruler`: Toggle the display of the genomic coordinates as ruler.\n"
                + "\n"
                + "* :code:`pctRuler`: Toggle the display of the column number of the terminal "
                + "(useful for navigation within the current genomic window).\n"
                + "\n"
                + ":code:`arg` can be just a prefix of the argument name, "
                + "e.g. :code:`show ge` will be recognized as :code:`show genome`.");
        cmdList.add(cmd);
//        cmd= new CommandHelp();
//        cmd.setName("showGenome"); cmd.setArgs(""); cmd.inSection= Section.GENERAL; 
//        cmd.setBriefDescription("Print the genome dictionary with a representation of chromosome sizes. ");
//        cmd.setAdditionalDescription("Example output::\n"
//                + "\n"
//                + "    showGenome\n"
//                + "    chrM~~16571\n"
//                + "       chr1~~249250621 ||||||||||||||||||||||||||||||\n"
//                + "    chr2~~243199373 |||||||||||||||||||||||||||||\n"
//                + "    ...\n"
//                + "    chr21 48129895~~||||||\n"
//                + "    chr22 51304566~~||||||\n"
//                + "    chrX~~155270560 |||||||||||||||||||\n"
//                + "    chrY~~59373566~~|||||||\n"
//                + "\n"
//                + "");
//        cmdList.add(cmd);

//        cmd= new CommandHelp();
//        cmd.setName("infoTracks"); cmd.setArgs(""); cmd.inSection= Section.GENERAL; 
//        cmd.setBriefDescription("Print the name of the current tracks along with file name and format. ");
//        cmd.setAdditionalDescription("Hidden tracks are marked by an asterisk.");
//        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("recentlyOpened"); cmd.setArgs("[-grep = .*]"); cmd.inSection= Section.GENERAL; 
        cmd.setBriefDescription("List recently opened files. ");
        cmd.setAdditionalDescription("Files are listed with their absolute path.\n"
                + "\n"
                + "* :code:`-n INT` Return only the last INT files.\n"
                + "\n"
                + "* :code:`-grep <pattern>` Filter for files (strings) matching pattern. "
                + "Use single quotes to define patterns containing spaces, e.g. :code:`-grep 'goto chr1'`.");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("open"); cmd.setArgs("[files | URLs | indexes]..."); cmd.inSection= Section.GENERAL; 
        cmd.setBriefDescription("Add tracks from local or remote files. ");
        cmd.setAdditionalDescription("The list of files to open can be a list of file names or URLs. "
                + "For local files, glob characters (wildcard) are expanded as in Bash "
                + "(but note that currently globs in directory names are not expanded.)\n"
                + "\n"
                + "Alternatively, the files to open can be given as numeric indexes of recently opened "
                + "files (see command :code:`recentlyOpened`). The last opened file has index 1, "
                + "the second last 2, etc.\n"
                + "\n"
                + "Examples::\n"
                + "\n"
                + "    open peaks.bed genes.*.gtf~~~~~~~~<- Note use of wildecard\n"
                + "    open http://remote/host/peaks.bed <- From URL\n"
                + "    open 1 2 3 ~~~~~~~~~~~~~~~~~~~~~~~<- The three most recent files\n"
                + "");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("reload"); cmd.setArgs("[track_regex = .*]..."); cmd.inSection= Section.GENERAL; 
        cmd.setBriefDescription("Reload track files. ");
        cmd.setAdditionalDescription("*reload* is useful when an input track file is edited by external "
                + "actions and you want to reload it in the current session. This is easier than "
                + "dropping and re-opening tracks with *dropTracks ... && open ...* since track "
                + "formattings and filters are preserved.\n"
                + "\n"
                + "A track is dropped if it cannot be reloaded, for example when the sequence disctionary "
                + "has become incompatible with the current one.\n"
                + "\n"
                + "Examples::\n"
                + "\n"
                + "    reload~~~~~~~<- reload all tracks\n"
                + "    reload .bam~~<- reload files matching '.bam'");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("dropTracks"); cmd.setArgs("[-t] [-v] track_regex [track_regex]..."); cmd.inSection= Section.GENERAL; 
        cmd.setBriefDescription("Drop tracks matching any of the listed regexes.");
        cmd.setAdditionalDescription(""
                + "* :code:`-t` (test) flag only shows which tracks would be removed but do not remove them.\n"
                + "\n"
                + "* :code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "Examples::\n"
                + "\n"
                + "    dropTracks bam\n"
                + "");
        cmdList.add(cmd);

        
        cmd= new CommandHelp();
        cmd.setName("orderTracks"); cmd.setArgs("[track_regex]..."); cmd.inSection= Section.GENERAL; 
        cmd.setBriefDescription("Reorder tracks according to the list of regexes or sort by name.");
        cmd.setAdditionalDescription("Not all the tracks need to be listed, the missing ones "
                + "follow the listed ones in unchanged order. Without arguments sort "
                + "track by tag name.\n"
                + "For example, given the track list: `[hela.bam#1, hela.bed#2, hek.bam#3, hek.bed#4]`::\n"
                + "\n"
                + "    orderTracks #2 #1~~~->~[hela.bed#2, hela.bam#1, hek.bam#3, hek.bed#4]\n"
                + "    orderTracks bam bed~->~[hela.bam#1, hek.bam#3, hela.bed#2, hek.bed#4]\n"
                + "    orderTracks . bam ~->~'bam' tracks go last\n"
                + "    orderTracks~~~~~~~~~->~name sort~[hela.bam#1, hela.bed#2, hek.bam#3, hek.bed#4]\n"
                + "");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("posHistory"); cmd.setArgs("[-n INT=10]"); cmd.inSection= Section.GENERAL; 
        cmd.setBriefDescription("List the visited positions.");
        cmd.setAdditionalDescription("Recorded positions include the current and the previous "
                + "sessions of ASCIIGenome.\n"
                + "\n"
                + ":code:`-n INT` Show only the last INT positions. Show all if <= 0.");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("history"); cmd.setArgs("[-n INT] [-grep = .*]"); cmd.inSection= Section.GENERAL; 
        cmd.setBriefDescription("List the executed commands. ");
        cmd.setAdditionalDescription("Commands executed in previous sessions of ASCIIGenome are in \\~/.asciigenome_history\n"
                + "\n"
                + "* :code:`-n INT` Return only the last INT commands.\n"
                + "\n"
                + "* :code:`-grep <pattern>` Filter for commands (strings) matching pattern. "
                + "Use single quotes to define patterns containing spaces, e.g. :code:`-grep 'goto chr1'`");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName(Command.rpm.getCmdDescr()); cmd.setArgs("[-on | -off] [-v] [track_regex = .*]"); cmd.inSection= Section.ALIGNMENTS; 
        cmd.setBriefDescription("Set display to reads per million for BAM and TDF files.\n");
        cmd.setAdditionalDescription("\n"
                + "* :code:`-on | -off` Set mode on/off. Without arguments toggle between on and off.\n"
                + "\n"
                + "* :code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "* :code:`track_regex` List of regexes to capture target tracks.");
        cmdList.add(cmd);        

        cmd= new CommandHelp();
        cmd.setName("samtools"); cmd.setArgs("[-f INT=0] [-F INT=4] [-q INT=0] [-v] [track_re = .*] ..."); cmd.inSection= Section.ALIGNMENTS; 
        cmd.setBriefDescription("Apply samtools filters to alignment tracks captured by the list of track regexes.");
        cmd.setAdditionalDescription("Useful for stranded RNA-Seq and BS-Seq: bit flag 4096 "
                + "is selects reads mapping to TOP STRAND.\n"
                + "\n"
                + "* :code:`-F` Filter out flags with these bits set. NB: 4 is always set.\n"
                + "\n"
                + "* :code:`-f` Require alignment to have these bits sets.\n"
                + "\n"
                + "* :code:`-q` Require alignments to have MAPQ >= than this.\n"
                + "\n"
                + "* :code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "Examples::\n"
                + "\n"
                + "    samtools -q 10~~~~~~~~~~~-> Set mapq for all tracks. -f and -F reset to default\n"
                + "    samtools -F 1024 foo bar -> Set -F for all track containing re foo or bar\n"
                + "    samtools -f 4096 ~~~~~~~~-> Select TOP STRAND reads\n"
                + "    samtools -F 4096 ~~~~~~~~-> Select BOTTOM STRAND reads\n"
                + "    samtools~~~~~~~~~~~~~~~~~-> Reset all to default.\n"
                + "");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName(Command.BSseq.getCmdDescr()); cmd.setArgs("[-on | -off] [-v] [track_regex = .*]..."); cmd.inSection= Section.ALIGNMENTS; 
        cmd.setBriefDescription("Set bisulfite mode for read tracks matched by regex.");
        cmd.setAdditionalDescription("In bisulfite mode, the characters M and m mark methylated bases "
                + "(i.e. unconverted C to T) and U and u are used for unmethylated bases "
                + "(i.e. C converted to T). Upper case is used for reads on  forward strand, small case for reverse.\n"
                + "\n"
                + "* :code:`-on | -off` Set mode. Without arguments toggle between on and off.\n"
                + "\n"
                + "* :code:`-v` Invert selection: apply changes to the tracks not selected by list of track_regex\n"
                + "\n"
                + "* :code:`track_regex` List of regexes to capture target tracks.\n"
                + "\n"
                + "Ignored without reference fasta sequence.");
        cmdList.add(cmd);        

        //cmd= new CommandHelp();
        //cmd.setName("pileup"); cmd.setArgs("[track_regex = .*]..."); cmd.inSection= Section.ALIGNMENTS; 
        //cmd.setBriefDescription("Print pileup of nucleotide counts.");
        //cmd.setAdditionalDescription("...");
        //cmdList.add(cmd);        
        
        cmd= new CommandHelp();
        cmd.setName("save"); cmd.setArgs("[>>] [filename = chrom_start_end.txt']"); cmd.inSection= Section.GENERAL; 
        cmd.setBriefDescription("Save screenshot to file as text or pdf format.");
        cmd.setAdditionalDescription("The default file name is generated from the current coordinates and the default format is plain text. "
                + "If the file name has extension '.pdf' then save as pdf. To append to an existing file use :code:`>>`. "
                + "The string :code:`%r` in the file name is replaced with the current coordinates. "
                + "Examples::\n"
                + "\n"
                + "    save mygene.txt~~~~-> Save to mygene.txt as text\n"
                + "    save >> mygene.txt~-> Append to mygene.txt\n"
                + "    save~~~~~~~~~~~~~~~-> Save to chrom_start-end.txt as text\n"
                + "    save .pdf~~~~~~~~~~-> Save to chrom_start-end.pdf as pdf\n"
                + "    save mygene.%r.pdf~-> Save to mygene.chr1_100-200.pdf as pdf\n"
                + "\n");
        cmdList.add(cmd);

//        cmd= new CommandHelp();
//        cmd.setName("sessionSave"); cmd.setArgs("filename"); cmd.inSection= Section.GENERAL; 
//        cmd.setBriefDescription("Experimental: Save the current settings to file suitable to be reloaded by ASCIIGenome.");
//        cmd.setAdditionalDescription("`sessionSave` writes to file a set of commands to reproduce the current "
//                + "settings: tracks, colors, heights etc. It's not meant to be a perfect replica, rather it's a "
//                + "shortcut to avoid re-typing commands. Example::\n"
//                + "\n"
//                + "    sessionSave session.txt\n"
//                + "\n"
//                + "Quit session and reload with::\n"
//                + "\n"
//                + "    ASCIIGenome -x session.txt\n"
//                + "");
//        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("sys"); cmd.setArgs("[-L] command"); cmd.inSection= Section.GENERAL; 
        cmd.setBriefDescription("Execute a system command.");
        cmd.setAdditionalDescription(""
                + "By default the given :code:`command` is executed as a string passed to "
                + "Bash as :code:`bash -c string`. With the :code:`-L` option the command is "
                + "executed literally as it is. Note that with the :code:`-L` option globs "
                + "are not expanded by Java. Examples::\n"
                + "\n"
                + "    sys pwd~~~~~~~~~~~~~~~~~~~~~~~~~~<- Print working directory name\n"
                + "    sys ls *.bam ~~~~~~~~~~~~~~~~~~~~<- List files ending in .bam\n"
                + "    sys bcftools view -h vars.vcf.gz <- Print vcf header\n"
                + "");
        cmdList.add(cmd);
        
        cmd= new CommandHelp();
        cmd.setName("q"); cmd.setArgs(""); cmd.inSection= Section.GENERAL; 
        cmd.setBriefDescription("Quit");
        cmd.setAdditionalDescription("");
        cmdList.add(cmd);

        cmd= new CommandHelp();
        cmd.setName("h"); cmd.setArgs(""); cmd.inSection= Section.GENERAL; 
        cmd.setBriefDescription(":code:`help`, :code:`h`, :code:`-h`, and :code:`?` show this help.\n"
                + CMD_HELP);
        cmd.setAdditionalDescription("");
        cmdList.add(cmd);
                
        // Make sure there are no undocumented cmds
        List<String> documented= new ArrayList<String>();
        for(CommandHelp x : cmdList){
            if(documented.contains(x.getName())){
                System.err.println(x.getName() + " already documented!");
                throw new InvalidCommandLineException();
            }
            documented.add(x.getName());
        }
        for(String x : CommandList.cmds()){
            if(!documented.contains(x)){
                System.err.println("Undocumented command: " + x);
                // throw new InvalidCommandLineException();
            }
        }
        
        return cmdList;
            
        }

    protected static List<CommandHelp> getCommandsForSection(Section section) throws InvalidCommandLineException, InvalidColourException{
        List<CommandHelp> cmdList= new ArrayList<CommandHelp>();
        for(CommandHelp x : commandHelpList()){
            if(x.inSection.equals(section)){
                cmdList.add(x);
            }
        }
        return cmdList;
    }
    
    
    /* Known commnds */
    public static final List<String> cmds(){
        List<String> paramList= new ArrayList<String>();
        paramList.add("q");
        paramList.add("h");
        paramList.add("f");
        paramList.add("b");
        paramList.add("ff");
        paramList.add("bb");
        paramList.add("]");
        paramList.add("[");
        paramList.add("zi");
        paramList.add("zo");
        paramList.add("extend");
        paramList.add("l");
        paramList.add("r");
        paramList.add("goto");
        paramList.add("INT");
        paramList.add("PERCENT");
        paramList.add("+");
        paramList.add("-");
        paramList.add("p");
        paramList.add("n");
        paramList.add("next");
        paramList.add("find");
        paramList.add("seqRegex");
        paramList.add("bookmark");
        paramList.add("grep");
        paramList.add("awk");
        paramList.add("filterVariantReads");
        paramList.add("nameForFeatures");
        paramList.add("gap");
        paramList.add("trackHeight");
        paramList.add("bedToBedgraph");
        paramList.add("colorTrack");
        paramList.add("featureColor");
        paramList.add(Command.featureDisplayMode.getCmdDescr());
        paramList.add("readsAsPairs");
        paramList.add("hideTitle");
        paramList.add("genotype");
        paramList.add("editNames");
        paramList.add("ylim");
        paramList.add("dataCol");
        paramList.add(Command.print.getCmdDescr());
        paramList.add("setGenome");
        paramList.add("explainSamFlag");
        paramList.add("show");
        paramList.add("open");
        paramList.add("reload");
        paramList.add("recentlyOpened");
        paramList.add("dropTracks");
        paramList.add("orderTracks");
        paramList.add("posHistory");
        paramList.add("history");
        paramList.add(Command.rpm.getCmdDescr());
        paramList.add("samtools");
        paramList.add(Command.BSseq.getCmdDescr());
        paramList.add("save");
        paramList.add("sys");
        paramList.add("setConfig");
    
        return paramList;
    }

    public static String getHelpForCommand(String commandName) throws InvalidColourException {
        try {
            for(CommandHelp x : CommandList.commandHelpList()){
                if(x.getName().equals(commandName)){
                    return x.printCommandHelp();
                }
            }
        } catch (InvalidCommandLineException e1) {
            e1.printStackTrace();
        }
        return "";
    }

    private static String toTitleCase(String x){
        x= x.toLowerCase();
        return x.substring(0, 1).toUpperCase() + x.substring(1);
    }
}
