#!/usr/bin/env python

# -------------------------------- WebLogo --------------------------------

#  Copyright (c) 2003-2004 The Regents of the University of California.
#  Copyright (c) 2005 Gavin E. Crooks
#  Copyright (c) 2006-2011, The Regents of the University of California, through
#  Lawrence Berkeley National Laboratory (subject to receipt of any required
#  approvals from the U.S. Dept. of Energy).  All rights reserved.

#  This software is distributed under the new BSD Open Source License.
#  <http://www.opensource.org/licenses/bsd-license.html>
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are met:
#
#  (1) Redistributions of source code must retain the above copyright notice,
#  this list of conditions and the following disclaimer.
#
#  (2) Redistributions in binary form must reproduce the above copyright
#  notice, this list of conditions and the following disclaimer in the
#  documentation and or other materials provided with the distribution.
#
#  (3) Neither the name of the University of California, Lawrence Berkeley
#  National Laboratory, U.S. Dept. of Energy nor the names of its contributors
#  may be used to endorse or promote products derived from this software
#  without specific prior written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
#  POSSIBILITY OF SUCH DAMAGE.

# WebLogo Command Line Interfaceg


import atexit
import os
import sys
from contextlib import ExitStack
from io import StringIO
from optparse import OptionGroup
from os import PathLike
from typing import Any, Union

import importlib.resources as importlib_resources

from . import (
    LogoData,
    LogoFormat,
    LogoOptions,
    default_formatter,
    description,
    formatters,
    parse_prior,
    read_seq_data,
    release_description,
    seq_io,
    std_alphabets,
    std_color_schemes,
    std_sizes,
    std_units,
)
from .colorscheme import ColorScheme, SymbolColor
from .logo import _seq_formats, _seq_names
from .seq import Seq, SeqList, nucleic_alphabet
from .utils.deoptparse import DeOptionParser


# ====================== Main: Parse Command line =============================
def main() -> None:
    """WebLogo command line interface"""

    # ------ Parse Command line ------
    parser = _build_option_parser()
    (opts, args) = parser.parse_args(sys.argv[1:])
    if args:
        parser.error("Unparsable arguments: %s " % args)

    if opts.serve:
        httpd_serve_forever(opts.port)  # Never returns?    # pragma: no cover
        sys.exit(0)  # pragma: no cover

    # ------ Create Logo ------
    try:
        data = _build_logodata(opts)
        format = _build_logoformat(data, opts)

        formatter = opts.formatter
        logo = formatter(data, format)
        # logo = logo.encode()

        opts.fout.buffer.write(logo)

    except ValueError as err:
        print("Error:", err, file=sys.stderr)
        sys.exit(2)
    except KeyboardInterrupt:  # pragma: no cover
        sys.exit(0)


# End main()


def httpd_serve_forever(port: int = 8080) -> None:
    """Start a webserver on a local port."""

    import http.server as server
    import http.server as cgiserver

    class __HTTPRequestHandler(cgiserver.CGIHTTPRequestHandler):
        # Modify CGIHTTPRequestHandler so that it will run the cgi script directly,
        # instead of exec'ing
        # This bypasses the need for the cgi script to have execute permissions set,
        # since distutils install does not preserve permissions.
        def is_cgi(self) -> bool:
            self.have_fork = False  # Prevent CGIHTTPRequestHandler from using fork
            if self.path == "/create.cgi":
                self.cgi_info = "", "create.cgi"
                return True
            return False

        def is_python(
            self, path: Union[str, PathLike]
        ) -> bool:  # Let CGIHTTPRequestHandler know that cgi script is python
            return True

    # Add current directory to PYTHONPATH. This is
    # so that we can run the standalone server
    # without having to run the install script.
    pythonpath = os.getenv("PYTHONPATH", "")
    pythonpath += os.pathsep + os.path.abspath(sys.path[0])  # .split()[0]
    os.environ["PYTHONPATH"] = pythonpath

    file_manager = ExitStack()
    atexit.register(file_manager.close)
    ref = importlib_resources.files("weblogo") / "htdocs"
    path = file_manager.enter_context(importlib_resources.as_file(ref))

    os.chdir(path)

    HandlerClass = __HTTPRequestHandler
    ServerClass = server.HTTPServer
    httpd = ServerClass(("", port), HandlerClass)
    print("WebLogo server running at http://localhost:%d/" % port)

    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        sys.exit(0)


# end httpd_serve_forever()


def _build_logodata(options: Any) -> LogoData:
    motif_flag = False

    fin = options.fin

    if options.upload is None:
        if fin is None:
            fin = StringIO(sys.stdin.read())
    else:
        if fin is None:
            from .logo import _from_URL_fileopen

            fin = _from_URL_fileopen(options.upload)
        else:
            raise ValueError("error: options --fin and --upload are incompatible")

    try:
        # Try reading data in transfac format first.
        from .matrix import Motif

        motif = Motif.read_transfac(fin, alphabet=options.alphabet)
        motif_flag = True
    except ValueError as motif_err:
        # Failed reading Motif, try reading as multiple sequence data.
        if options.input_parser == "transfac":
            raise motif_err  # Adding transfac as str insted of parser is a bit of a ugly kludge
        seqs = read_seq_data(
            fin,
            options.input_parser.read,
            alphabet=options.alphabet,
            ignore_lower_case=options.ignore_lower_case,
        )

    if motif_flag:
        if options.ignore_lower_case:
            raise ValueError(
                "error: option --ignore-lower-case incompatible with matrix input"
            )
        if options.reverse or options.revcomp:
            motif.reverse()
        if options.complement or options.revcomp:
            motif.complement()

        prior = parse_prior(options.composition, motif.alphabet, options.weight)
        data = LogoData.from_counts(motif.alphabet, motif.array, prior)
    else:
        if options.reverse or options.revcomp:
            seqs = SeqList([s.reverse() for s in seqs], seqs.alphabet)

        if options.complement or options.revcomp:
            if not nucleic_alphabet.alphabetic(str(seqs.alphabet)):
                raise ValueError(
                    "non-nucleic sequence cannot be complemented"
                )  # pragam: no cover
            aaa = seqs.alphabet
            seqs.alphabet = nucleic_alphabet
            seqs = SeqList(
                [Seq(s, seqs.alphabet).complement() for s in seqs], seqs.alphabet
            )
            seqs.alphabet = aaa

        a = seqs.alphabet
        assert a is not None
        prior = parse_prior(options.composition, a, options.weight)
        data = LogoData.from_seqs(seqs, prior)

    return data


def _build_logoformat(logodata: LogoData, opts: Any) -> LogoFormat:
    """Extract and process relevant option values and return a
    LogoFormat object."""

    args = {}
    direct_from_opts = [
        # Logo Data Options.
        "alphabet",
        "unit_name",
        "first_index",
        "logo_start",
        "logo_end",
        # Logo Format Options.
        "stack_width",
        "stacks_per_line",
        "logo_title",
        "logo_label",
        "show_xaxis",
        "xaxis_label",
        "annotate",
        "rotate_numbers",
        "number_interval",
        "yaxis_scale",
        "show_yaxis",
        "yaxis_label",
        "show_ends",
        "fineprint",
        "yaxis_tic_interval",
        "show_errorbars",
        "reverse_stacks",
        # Color Options.
        "color_scheme",
        "default_color",
        # Font Format Options.
        "fontsize",
        "title_fontsize",
        "small_fontsize",
        "number_fontsize",
        "text_font",
        "logo_font",
        "title_font",
        # Advanced Format Options.
        "stack_aspect_ratio",
        "show_boxes",
        "resolution",
        "scale_width",
        "debug",
        "errorbar_fraction",
        "errorbar_width_fraction",
        "errorbar_gray",
    ]

    for k in direct_from_opts:
        args[k] = opts.__dict__[k]

    # logo_size = copy.copy(opts.__dict__['logo_size'])
    #    size_from_opts = ["stack_width", "stack_height"]
    #    for k in size_from_opts :
    #        length = getattr(opts, k)
    #        if length :
    #            setattr( logo_size, k, length )
    #   args["size"] = logo_size

    if opts.colors:
        color_scheme = ColorScheme()
        for color, symbols, desc in opts.colors:
            try:
                # c = Color.from_string(color)
                color_scheme.rules.append(SymbolColor(symbols, color, desc))
            except ValueError:
                raise ValueError("error: option --color: invalid value: '%s'" % color)

        args["color_scheme"] = color_scheme

    if opts.annotate:
        args["annotate"] = opts.annotate.split(",")

    logooptions = LogoOptions()
    for a, v in args.items():
        setattr(logooptions, a, v)

    theformat = LogoFormat(logodata, logooptions)
    return theformat


# ========================== OPTIONS ==========================
def _build_option_parser() -> DeOptionParser:
    defaults = LogoOptions()
    parser = DeOptionParser(
        usage="%prog [options]  < sequence_data.fa > sequence_logo.eps",
        description=description,
        version=release_description,
        add_verbose_options=False,
    )

    io_grp = OptionGroup(
        parser,
        "Input/Output Options",
    )
    data_grp = OptionGroup(
        parser,
        "Logo Data Options",
    )
    trans_grp = OptionGroup(
        parser, "Transformations", "Optional transformations of the sequence data."
    )

    format_grp = OptionGroup(
        parser,
        "Logo Format Options",
        "These options control the format and display of the logo.",
    )
    color_grp = OptionGroup(
        parser,
        "Color Options",
        "Colors can be specified using CSS2 syntax. e.g. 'red', '#FF0000', etc",
    )
    font_grp = OptionGroup(
        parser,
        "Font Format Options",
        "These options provide control over the font sizes and types.",
    )
    advanced_grp = OptionGroup(
        parser,
        "Advanced Format Options",
        "These options provide fine control over the display of the logo.",
    )
    server_grp = OptionGroup(
        parser, "WebLogo Server", "Run a standalone webserver on a local port."
    )

    parser.add_option_group(io_grp)
    parser.add_option_group(data_grp)
    parser.add_option_group(trans_grp)
    parser.add_option_group(format_grp)
    parser.add_option_group(color_grp)
    parser.add_option_group(font_grp)
    parser.add_option_group(advanced_grp)
    parser.add_option_group(server_grp)

    # ========================== IO OPTIONS ==========================

    io_grp.add_option(
        "-f",
        "--fin",
        dest="fin",
        action="store",
        type="file_in",
        default=None,
        help="Sequence input file (default: stdin)",
        metavar="FILENAME",
    )

    io_grp.add_option(
        "",
        "--upload",
        dest="upload",
        action="store",
        default=None,
        help="Upload input file from URL",
        metavar="URL",
    )

    io_grp.add_option(
        "-D",
        "--datatype",
        dest="input_parser",
        action="store",
        type="dict",
        default=seq_io,
        choices=_seq_formats(),
        help="Type of multiple sequence alignment or position"
        " weight matrix file: (%s)" % ", ".join(_seq_names()),
        metavar="FORMAT",
    )

    io_grp.add_option(
        "-o",
        "--fout",
        dest="fout",
        type="file_out",
        default=sys.stdout,
        help="Output file (default: stdout)",
        metavar="FILENAME",
    )

    io_grp.add_option(
        "-F",
        "--format",
        dest="formatter",
        action="store",
        type="dict",
        choices=formatters,
        metavar="FORMAT",
        help="Format of output: eps (default), png, png_print, pdf, jpeg, svg, "
        "logodata, csv",
        default=default_formatter,
    )

    # ========================== Data OPTIONS ==========================

    data_grp.add_option(
        "-A",
        "--sequence-type",
        dest="alphabet",
        action="store",
        type="dict",
        choices=std_alphabets,
        help="The type of sequence data: 'protein', 'rna' or 'dna'.",
        metavar="TYPE",
    )

    data_grp.add_option(
        "-a",
        "--alphabet",
        dest="alphabet",
        action="store",
        help="The set of symbols to count, e.g. 'AGTC'. "
        "All characters not in the alphabet are ignored. "
        "If neither the alphabet nor sequence-type are specified then weblogo "
        "will examine the input data and make an educated guess. "
        "See also --sequence-type, --ignore-lower-case",
    )

    data_grp.add_option(
        "-U",
        "--units",
        dest="unit_name",
        action="store",
        choices=list(std_units.keys()),
        type="choice",
        default=defaults.unit_name,
        help="A unit of entropy ('bits' (default), 'nats', 'digits'), or a unit of"
        "free energy ('kT', 'kJ/mol', 'kcal/mol'), or 'probability' for"
        " probabilities",
        metavar="UNIT",
    )

    data_grp.add_option(
        "",
        "--composition",
        dest="composition",
        action="store",
        type="string",
        default="auto",
        help="The expected composition of the sequences: 'auto' (default), "
        "'equiprobable', 'none' (do not perform any compositional "
        "adjustment), a CG percentage, a species name (e.g. 'E. coli', "
        "'H. sapiens'), or an explicit distribution (e.g. \"{'A':10, 'C':40,"
        " 'G':40, 'T':10}\"). The automatic option uses a typical "
        "distribution for proteins and equiprobable distribution for "
        "everything else. ",
        metavar="COMP.",
    )

    data_grp.add_option(
        "",
        "--weight",
        dest="weight",
        action="store",
        type="float",
        default=None,
        help="The weight of prior data.  Default depends on alphabet length",
        metavar="NUMBER",
    )

    data_grp.add_option(
        "-i",
        "--first-index",
        dest="first_index",
        action="store",
        type="int",
        default=1,
        help="Index of first position in sequence data (default: 1)",
        metavar="INDEX",
    )

    data_grp.add_option(
        "-l",
        "--lower",
        dest="logo_start",
        action="store",
        type="int",
        help="Lower bound of sequence to display",
        metavar="INDEX",
    )

    data_grp.add_option(
        "-u",
        "--upper",
        dest="logo_end",
        action="store",
        type="int",
        help="Upper bound of sequence to display",
        metavar="INDEX",
    )

    # ========================== Transformation OPTIONS ==========================

    # FIXME Add test?
    trans_grp.add_option(
        "",
        "--ignore-lower-case",
        dest="ignore_lower_case",
        action="store_true",
        default=False,
        help="Disregard lower case letters and only count upper case letters"
        " in sequences.",
    )

    trans_grp.add_option(
        "",
        "--reverse",
        dest="reverse",
        action="store_true",
        default=False,
        help="reverse sequences",
    )

    trans_grp.add_option(
        "",
        "--complement",
        dest="complement",
        action="store_true",
        default=False,
        help="complement nucleic sequences",
    )

    trans_grp.add_option(
        "",
        "--revcomp",
        dest="revcomp",
        action="store_true",
        default=False,
        help="reverse complement nucleic sequences",
    )

    # ========================== FORMAT OPTIONS ==========================

    format_grp.add_option(
        "-s",
        "--size",
        dest="stack_width",
        action="store",
        type="dict",
        choices=std_sizes,
        metavar="LOGOSIZE",
        default=defaults.stack_width,
        help="Specify a standard logo size (small, medium (default), large)",
    )

    format_grp.add_option(
        "-n",
        "--stacks-per-line",
        dest="stacks_per_line",
        action="store",
        type="int",
        help="Maximum number of logo stacks per logo line. (default: %default)",
        default=defaults.stacks_per_line,
        metavar="COUNT",
    )

    format_grp.add_option(
        "-t",
        "--title",
        dest="logo_title",
        action="store",
        type="string",
        help="Logo title text.",
        default=defaults.logo_title,
        metavar="TEXT",
    )

    format_grp.add_option(
        "",
        "--label",
        dest="logo_label",
        action="store",
        type="string",
        help="A figure label, e.g. '2a'",
        default=defaults.logo_label,
        metavar="TEXT",
    )

    format_grp.add_option(
        "-X",
        "--show-xaxis",
        action="store",
        type="boolean",
        default=defaults.show_xaxis,
        metavar="YES/NO",
        help="Display sequence numbers along x-axis? (default: %default)",
    )

    format_grp.add_option(
        "-x",
        "--xlabel",
        dest="xaxis_label",
        action="store",
        type="string",
        default=defaults.xaxis_label,
        help="X-axis label",
        metavar="TEXT",
    )

    format_grp.add_option(
        "",
        "--annotate",
        dest="annotate",
        action="store",
        type="string",
        default=None,
        help="A comma separated list of custom stack annotations, "
        "e.g. '1,3,4,5,6,7'.  Annotation list must be same length as "
        "sequences.",
        metavar="TEXT",
    )

    format_grp.add_option(
        "",
        "--rotate-numbers",
        dest="rotate_numbers",
        action="store",
        type="boolean",
        default=defaults.rotate_numbers,
        help="Draw X-axis numbers with vertical orientation (default: %default).",
        metavar="YES/NO",
    )

    format_grp.add_option(
        "",
        "--number-interval",
        dest="number_interval",
        action="store",
        type="float",
        default=defaults.number_interval,
        help="Distance between numbers on X-axis (default: %s)"
        % defaults.number_interval,
        metavar="NUMBER",
    )

    format_grp.add_option(
        "-S",
        "--yaxis",
        dest="yaxis_scale",
        action="store",
        type="float",
        help="Height of yaxis in units. (Default: Maximum value with "
        "uninformative prior.)",
        metavar="NUMBER",
    )

    format_grp.add_option(
        "-Y",
        "--show-yaxis",
        action="store",
        type="boolean",
        dest="show_yaxis",
        default=defaults.show_yaxis,
        metavar="YES/NO",
        help="Display entropy scale along y-axis? (default: %default)",
    )

    format_grp.add_option(
        "-y",
        "--ylabel",
        dest="yaxis_label",
        action="store",
        type="string",
        help="Y-axis label (default depends on plot type and units)",
        metavar="TEXT",
    )

    format_grp.add_option(
        "-E",
        "--show-ends",
        action="store",
        type="boolean",
        default=defaults.show_ends,
        metavar="YES/NO",
        help="Label the ends of the sequence? (default: %default)",
    )

    format_grp.add_option(
        "-P",
        "--fineprint",
        dest="fineprint",
        action="store",
        type="string",
        default=defaults.fineprint,
        help="The fine print (default: weblogo version)",
        metavar="TEXT",
    )

    format_grp.add_option(
        "",
        "--ticmarks",
        dest="yaxis_tic_interval",
        action="store",
        type="float",
        default=defaults.yaxis_tic_interval,
        help="Distance between ticmarks (default: %default)",
        metavar="NUMBER",
    )

    format_grp.add_option(
        "",
        "--errorbars",
        dest="show_errorbars",
        action="store",
        type="boolean",
        default=defaults.show_errorbars,
        metavar="YES/NO",
        help="Display error bars? (default: %default)",
    )

    format_grp.add_option(
        "",
        "--reverse-stacks",
        dest="reverse_stacks",
        action="store",
        type="boolean",
        default=defaults.show_errorbars,
        metavar="YES/NO",
        help="Draw stacks with largest letters on top? (default: %default)",
    )

    # ========================== Color OPTIONS ==========================
    # TODO: Future Feature
    # color_grp.add_option( "-K", "--color-key",
    #    dest= "show_color_key",
    #    action="store",
    #    type = "boolean",
    #    default= defaults.show_color_key,
    #    metavar = "YES/NO",
    #    help="Display a color key (default: %default)")

    color_scheme_choices = list(std_color_schemes.keys())
    color_scheme_choices.sort()
    color_grp.add_option(
        "-c",
        "--color-scheme",
        dest="color_scheme",
        action="store",
        type="dict",
        choices=std_color_schemes,
        metavar="SCHEME",
        default=None,  # Auto
        help="Specify a standard color scheme (%s)" % ", ".join(color_scheme_choices),
    )

    color_grp.add_option(
        "-C",
        "--color",
        dest="colors",
        action="append",
        metavar="COLOR SYMBOLS DESCRIPTION ",
        nargs=3,
        default=[],
        help="Specify symbol colors, e.g. --color black AG 'Purine' "
        "--color red TC 'Pyrimidine' ",
    )

    color_grp.add_option(
        "",
        "--default-color",
        dest="default_color",
        action="store",
        metavar="COLOR",
        default=defaults.default_color,
        help="Symbol color if not otherwise specified.",
    )

    # ========================== Font options =========================

    font_grp.add_option(
        "",
        "--fontsize",
        dest="fontsize",
        action="store",
        type="float",
        default=defaults.fontsize,
        help="Regular text font size in points (default: %s)" % defaults.fontsize,
        metavar="POINTS",
    )

    font_grp.add_option(
        "",
        "--title-fontsize",
        dest="title_fontsize",
        action="store",
        type="float",
        default=defaults.title_fontsize,
        help="Title text font size in points (default: %s)" % defaults.title_fontsize,
        metavar="POINTS",
    )

    font_grp.add_option(
        "",
        "--small-fontsize",
        dest="small_fontsize",
        action="store",
        type="float",
        default=defaults.small_fontsize,
        help="Small text font size in points (default: %s)" % defaults.small_fontsize,
        metavar="POINTS",
    )

    font_grp.add_option(
        "",
        "--number-fontsize",
        dest="number_fontsize",
        action="store",
        type="float",
        default=defaults.number_fontsize,
        help="Axis numbers font size in points (default: %s)"
        % defaults.number_fontsize,
        metavar="POINTS",
    )

    font_grp.add_option(
        "",
        "--text-font",
        dest="text_font",
        action="store",
        type="string",
        default=defaults.text_font,
        help="Specify font for labels (default: %s)" % defaults.text_font,
        metavar="FONT",
    )

    font_grp.add_option(
        "",
        "--logo-font",
        dest="logo_font",
        action="store",
        type="string",
        default=defaults.text_font,
        help="Specify font for logo (default: %s)" % defaults.logo_font,
        metavar="FONT",
    )

    font_grp.add_option(
        "",
        "--title-font",
        dest="title_font",
        action="store",
        type="string",
        default=defaults.title_font,
        help="Specify font for title (default: %s)" % defaults.title_font,
        metavar="FONT",
    )

    # ========================== Advanced options =========================

    advanced_grp.add_option(
        "-W",
        "--stack-width",
        dest="stack_width",
        action="store",
        type="float",
        default=defaults.stack_width,
        help="Width of a logo stack (default: %s)" % defaults.stack_width,
        metavar="POINTS",
    )

    advanced_grp.add_option(
        "",
        "--aspect-ratio",
        dest="stack_aspect_ratio",
        action="store",
        type="float",
        default=defaults.stack_aspect_ratio,
        help="Ratio of stack height to width (default: %s)"
        % defaults.stack_aspect_ratio,
        metavar="POINTS",
    )

    advanced_grp.add_option(
        "",
        "--box",
        dest="show_boxes",
        action="store",
        type="boolean",
        default=False,
        metavar="YES/NO",
        help="Draw boxes around symbols? (default: no)",
    )

    advanced_grp.add_option(
        "",
        "--resolution",
        dest="resolution",
        action="store",
        type="float",
        default=96,
        help="Bitmap resolution in dots per inch (DPI).  (Default: 96 DPI,"
        " except png_print, 600 DPI) Low resolution bitmaps (DPI<300)"
        " are antialiased.",
        metavar="DPI",
    )

    advanced_grp.add_option(
        "",
        "--scale-width",
        dest="scale_width",
        action="store",
        type="boolean",
        default=True,
        metavar="YES/NO",
        help="Scale the visible stack width by the fraction of symbols in the"
        " column?  (I.e. columns with many gaps of unknowns are narrow.)  "
        "(Default: yes)",
    )

    advanced_grp.add_option(
        "",
        "--debug",
        action="store",
        type="boolean",
        default=defaults.debug,
        metavar="YES/NO",
        help="Output additional diagnostic information. (Default: %default)",
    )

    advanced_grp.add_option(
        "",
        "--errorbar-fraction",
        dest="errorbar_fraction",
        action="store",
        type="float",
        default=defaults.errorbar_fraction,
        help="Sets error bars display proportion (default: %s)"
        % defaults.errorbar_fraction,
        metavar="NUMBER",
    )

    advanced_grp.add_option(
        "",
        "--errorbar-width-fraction",
        dest="errorbar_width_fraction",
        action="store",
        type="float",
        default=defaults.errorbar_width_fraction,
        help="Sets error bars width display proportion (default: %s)"
        % defaults.errorbar_width_fraction,
        metavar="NUMBER",
    )

    advanced_grp.add_option(
        "",
        "--errorbar-gray",
        dest="errorbar_gray",
        action="store",
        type="float",
        default=defaults.errorbar_gray,
        help="Sets error bars' gray scale percentage (default: %s)"
        % defaults.errorbar_gray,
        metavar="NUMBER",
    )

    # ========================== Server options =========================
    server_grp.add_option(
        "",
        "--serve",
        dest="serve",
        action="store_true",
        default=False,
        help="Start a standalone WebLogo server for creating sequence logos.",
    )

    server_grp.add_option(
        "",
        "--port",
        dest="port",
        action="store",
        type="int",
        default=8080,
        help="Listen to this local port. (Default: %default)",
        metavar="PORT",
    )

    return parser

    # END _build_option_parser


##############################################################
