#!/usr/bin/env python3
# Copyright (C) 2020-2024 Gabriele Bozzola
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <https://www.gnu.org/licenses/>.
"""The :py:mod:`~.argparse_helper` module provides helper functions to write
scripts that are controlled by command-line arguments or configuration files.
The intended way to use this module is, schematically
.. code-block:: python
    from kuibit import argparse_helper as kah
    parser = kah.init_argparse(desc="Description")
    # Next we add everything we need
    kah.add_figure_to_parser(parser)
    # Specific arguments
    parser.add_argument("--arg1", help="Specific argument")
    # Finally
    args = kah.get_args(parser)
    # args is Namespace that contains all the arguments provided via
    # command-line, configuration file, or environment variable
"""
import os
import sys
import argcomplete
import configargparse
# We use configargparse instead of argparse because it gives us much more
# flexibility.
[docs]def init_argparse(*args, **kwargs):
    """Initialize a new argparse with given arguments.
    Unknown arguments are passed to ``configargparse.ArgParser``.
    :returns: Argparse parser.
    :rtype: configargparse.ArgumentParser
    """
    parser = configargparse.ArgParser(*args, **kwargs)
    parser.add(
        "-c", "--configfile", is_config_file=True, help="Config file path"
    )
    parser.add(
        "-v", "--verbose", help="Enable verbose output", action="store_true"
    )
    parser.add_argument("--datadir", default=".", help="Data directory")
    parser.add_argument("--outdir", default=".", help="Output directory")
    parser.add_argument(
        "--ignore-symlinks",
        action="store_true",
        help="Ignore symlinks in the data directory",
    )
    parser.add_argument("--pickle-file", help="Read/write SimDir to this file")
    return parser 
[docs]def get_args(parser, args=None):
    """Process argparse arguments.
    If ``args`` is None, the command line arguments are used. Otherwise,
    ``args`` is used (useful for testing and debugging).
    :param args: List of command-line options.
    :type args: list
    :returns: Arguments as read from command line or from args.
    :rtype: argparse Namespace
    """
    if args is None:
        # Remove the name of the program from the list of arguments
        args = sys.argv[1:]
    argcomplete.autocomplete(parser)
    return parser.parse_args(args) 
[docs]def add_grid_to_parser(parser, dimensions=2):
    """Add parameters that have to do with grid configurations to the given parser.
    This function edits ``parser`` in place.
    The options added are:
    - ``resolution``
    - ``x0 (origin)``
    - ``x1 (corner)``
    - ``axis`` (for ``dimension = 1``)
    - ``plane`` (for ``dimension = 2``)
    :param parser: Argparse parser to which the grid options have to be added.
    :type parser: configargparse.ArgumentParser
    :param dimensions: Number of grid dimensions to consider (1, 2, or 3).
    :type dimensions: int
    """
    if dimensions not in (1, 2, 3):
        raise ValueError("The number of dimensions has to be 1, 2, or 3")
    parser.add_argument(
        "--resolution",
        type=int,
        default=500,
        help=(
            (
                "Resolution of the grid in number of points "
                "(default: %(default)s)"
            )
        ),
    )
    parser.add_argument(
        "-x0",
        "--origin",
        type=float,
        nargs=dimensions,
        default=[0] * dimensions,
    )
    parser.add_argument(
        "-x1",
        "--corner",
        type=float,
        nargs=dimensions,
        default=[1] * dimensions,
    )
    if dimensions == 1:
        parser.add_argument(
            "--axis",
            type=str,
            choices=["x", "y", "z"],
            default="x",
            help="Axis to plot (default: %(default)s)",
        )
    if dimensions == 2:
        parser.add_argument(
            "--plane",
            type=str,
            choices=["xy", "xz", "yz"],
            default="xy",
            help="Plane to plot (default: %(default)s)",
        ) 
[docs]def add_horizon_to_parser(
    parser, color="k", edge_color="w", alpha=1, time_tolerance=0.1
):
    """Add parameters that have to do with a apparent horizons to a given parser.
    This function edits ``parser`` in place.
    The options added are:
    - ``ah-show``
    - ``ah-color``
    - ``ah-edge-color``
    - ``ah-alpha``
    - ``ah-time-tolerance``
    :param color: Color of the horizons.
    :type color: anything accepted by the drawing package
    :param edge_color: Color of the edge of the horizons.
    :type edge_color: anything accepted by the drawing package
    :param alpha: Number between 0 and 1 that identifies the opacity of the
                  horizon.
    :type alpha: float
    :param time_tolerance: Time tolerance allowed for finding an horizon.
    :type time_tolerance: float
    :param parser: Argparse parser (generated with init_argparse())
    :type parser: configargparse.ArgumentParser
    """
    ah_group = parser.add_argument_group("Horizon options")
    ah_group.add_argument(
        "--ah-show", action="store_true", help="Plot apparent horizons."
    )
    ah_group.add_argument(
        "--ah-color",
        default=color,
        help="Color name for horizons (default is '%(default)s').",
    )
    ah_group.add_argument(
        "--ah-edge-color",
        default=edge_color,
        help="Color name for horizons boundary (default is '%(default)s').",
    )
    ah_group.add_argument(
        "--ah-alpha",
        type=float,
        default=alpha,
        help="Alpha (transparency) for apparent horizons (default: %(default)s)",
    )
    ah_group.add_argument(
        "--ah-time-tolerance",
        type=float,
        default=time_tolerance,
        help="Tolerance for matching horizon time [simulation units]"
        " (default is '%(default)s').",
    )
    return parser 
[docs]def add_grid_structure_to_parser(parser, edge_color="black", alpha=0.5):
    """Add parameters that have to do with drawing the grid structure.
    This function edits ``parser`` in place.
    The options added are:
    - ``rl-show``
    - ``rl-edge-color``
    - ``rl-alpha``
    :param edge_color: Color of the edge of the components.
    :type edge_color: anything accepted by the drawing package
    :param alpha: Number between 0 and 1 that identifies the opacity of the
                  horizon.
    :type alpha: float
    :param parser: Argparse parser (generated with ``init_argparse()``)
    :type parser: ``configargparse.ArgumentParser``
    """
    ah_group = parser.add_argument_group("Grid structure options")
    ah_group.add_argument(
        "--rl-show", action="store_true", help="Plot grid structure."
    )
    ah_group.add_argument(
        "--rl-edge-color",
        default=edge_color,
        help="Color name for refinement boundaries (default is '%(default)s').",
    )
    ah_group.add_argument(
        "--rl-alpha",
        type=float,
        default=alpha,
        help="Alpha (transparency) for refinement boundaries (default: %(default)s)",
    )
    return parser 
[docs]def get_program_name():
    """Return the name of the current script.
    :returns: Name of file executing the code.
    :rtype: str
    """
    return os.path.basename(sys.argv[0])