"""
    Help text for arguments/scripts
"""
from argparse import RawTextHelpFormatter, SUPPRESS, OPTIONAL, ZERO_OR_MORE
from textwrap import wrap

BASE_DOC_URL = "https://omnineuro.readthedocs.io/en/latest/"


class CustomTextHelpFormatter(RawTextHelpFormatter):
    def _split_lines(self, text, width):
        """Wraps paragraphs with textwrap.wrap with max width 120."""
        # set width to 120 if larger
        if width > 120:
            width = 120
        # remove leading "\n" if it exists
        if text[0:1] == "\n":
            text = text[1:]
        # split on paragraphs
        paragraphs = text.split("\n\n")
        # wrap text
        formatted_text = list()
        for p in paragraphs:
            formatted_text += wrap(p, width)
            formatted_text += [""]
        # return formatted text
        return formatted_text

    def _get_help_string(self, action):
        help_desc = action.help
        if "%(default)" not in action.help:
            if action.default is not None:  # Don't show default if None
                if action.default is not SUPPRESS:
                    defaulting_nargs = [OPTIONAL, ZERO_OR_MORE]
                    if action.option_strings or action.nargs in defaulting_nargs:
                        help_desc += " (default: %(default)s)"
        return help_desc


# Below help text descriptions for each argument found in all omni scripts.
# NOTE: To insert these into the docs, you can use the custom `add_argument` directive
# that this project has. The `add_argument` directive does not take these help descriptions
# in directly. Instead, it grabs the arguments from the parser variable generated by
# each script (See the generate_parser function in each script).
#
# For example, to insert the `synthpreproc_bids_sidecar` help description. You would invoke
# the following in the documentation:
#
#   .. add_argument:: omni.scripts.synthpreproc bids_sidecar
#
# This invocation corresponds to the following help text:
#
# -b BIDS_SIDECAR, --bids_sidecar BIDS_SIDECAR
#                        ``BIDS_SIDECAR_FILENAME`` is a path to a .json formatted file that contains information about
#                        the input EPI data set. It is anticipated that most users will convert raw DICOM data to NIFTI
#                        format using the utility, dcm2niix. During initial data conversion, calling dcm2niix using the
#                        ``-b BIDS_SIDECAR_FILENAME`` optional input will produce the requisite .json file.
#
# The reason for pulling argument help text from the scripts and not from the defined strings below, is twofold:
#
#    1.) Adding argument help from the script is more easily readable, since a single argument description can be used
#        in multiple scripts.
#    2.) Pulling argument help from the script, allows us to get other argument metadata, such as flag names, default
#        values, etc.

# Common help text
# These should be set as the default_help text in arguments.py


# see arg_log_file
common_log_file = """
``LOG_FILE`` is the path to a text file chronicling the details of
each inevitably successful step along your path to registration nirvana.
"""

# see arg_ref
common_ref = """
``REF`` sets which anatomical image is used as the reference
image during registration. Valid options are 'T1' or 'T2'.
"""

# see arg_program
common_program = """
At various stages of preprocessing different images
need to be approximately aligned to one another. For instance, when creating a
synthetic image, an initial "guess" for the appropriate affine alignment
parameters that bring T1w, T2w and EPI images into approximate registration are
required. The user can select between two widely used registration utilities to
perform this estimate: FSL's ``FLIRT``, and AFNI's ``3dAllineate`` by setting
``PROGRAM`` equal to ``fsl`` or ``afni``.
"""

# see arg_sigma_t2
common_sigma_t2 = """
Gaussian kernel width expressed in millimeters used to
smooth T2w image used for an initial very coarse distortion correcting warp.
Before estimating the synthetic EPI image a low spatial resolution warp is used
to adjust the EPI image to maximize alignment to the anatomical images. Using a
T2w image alone as a target for non-linear warping becomes highly unreliable for
detailed corrections. However in our experience, using a T2w image to for an
initial low spatial resolution unwarping target slightly increases the quality
of the initial estimate of the synthetic EPI (at the very least it doesn't seem
to hurt any).
"""

# see arg_data_resolution
common_data_resolution = """
A number representing the desired isotropic dimensions in millimeters of the final output data set. Not setting
``DATA_RESOLUTION`` uses the native resolution of the input EPI data as the resolution of the final aligned output.
"""

# see arg_atlas
common_atlas = """
``ATLAS`` selects the final image space to which output data
are aligned. Available built-ins are ``mni`` and ``trio``. You can
also specify a path to atlas file, but you will also need to specify
the ``atlas_label`` argument. When this argument is omitted, the MNI
atlas is selected.
"""

# see arg_epi
common_epi = """
The file name of an EPI data set (e.g., task, rest or diffusion weighted). This data set must contain multiple frames.
Any desired frame-wise alignment and slice timing correction should already be performed.
"""

# see arg_debias_params_anat
common_debias_params_anat = """
``DEBIAS_PARAMS_ANAT`` is a string representing BSpline model parameters used to estimate the low spatial frequency
intensity modulating bias field present in the T1w and T2w anatomical images. The ``N4BiasFieldCorrection`` algorithm
is used to estimate this bias field. The DEBIAS_PARAMS_ANAT string is passed directly into the ``-b`` parameter of the
``N4BiasFieldCorrection`` utility. Type ``N4BiasFieldCorrection -h`` in the command line for more information on this
parameter.
"""

# see arg_debias_params_func
common_debias_params_func = """
``DEBIAS_PARAMS_FUNC`` is a string representing BSpline model parameters used to estimate the low spatial frequency
intensity modulating bias field present in the EPI images. The ``DEBIAS_PARAMS_FUNC`` string is passed directly into
the ``-b`` parameter of the ``N4BiasFieldCorrection`` utility. Type ``N4BiasFieldCorrection -h`` in the command
line for more information on this parameter.
"""

# see arg_dilation_size
common_dilation_size = """
``DILATION_SIZE`` is the size of the structural element used to dilate the anatomical weight
mask.
"""

# see arg_bet_method
common_bet_method = """
When ``BET_METHOD`` is ``T1``, the subjects T1w image
is used to create the binary brain mask, using the BET tool. When ``BET_METHOD`` is
``Norm``, the voxel-wise Euclidean norm of the (normalized and pre-aligned) T1w
and T2w (sqrt(T1w.^2 + T2w.^2))) images is used as input to the ``BET`` tool.
"""

# see arg_fractional_intensity_threshold_anat
common_fractional_intensity_threshold_anat = """
``FRACTIONAL_INTENSITY_THRESHOLD_ANAT`` is a key parameter used in creating binary
brain masks using the ``BET`` and ``BET2`` utilities. This option sets the fractional
intensity threshold used for the anatomical images selected by the ``--bet_method``
option. For more information type 'bet -h' in the command line.
"""

# see arg_fractional_intensity_threshold_func
common_fractional_intensity_threshold_func = """
``FRACTIONAL_INTENSITY_THRESHOLD_FUNC`` sets the threshold used by the BET utility
when creating a binary brain mask for the distorted EPI data sets. Type ``bet -h``
in the command line for more information.
"""

# see arg_subsample
common_subsample = """
``SUBSAMPLE`` is a list of integers (at
least one value) describing the subsampling sequence used when performing
simultaneous slice time and motion correction. The number of elements in this
list of integers must match the number of integers used for the ``-l`` or ``--loops``
parameters.
"""

# see arg_loops
common_loops = """
The ``LOOPS`` parameter is a
list of integers (the same size as the list of integers used for the ``--subsample``
parameter) that dictates the number of refining iterations at the corresponding
subsampling resolution.
"""

# see arg_initial_synth_model
common_initial_synth_model = """
``INITIAL_SYNTH_MODEL`` is a string
describing the radial basis function model used for the initial synthetic EPI
image estimate. In an abundance of caution, to avoid potential overfitting early
on, we suggest using a relatively simple model for the first estimate.
"""

# see arg_initial_warp_field
common_initial_warp_field = """
``INITIAL_WARP_FIELD`` is a string specifying the initial warp field used for
Synth's alternating minimization optimization process. It is meant for use as a
way of inputting field map estimates to seed Synth's optimization process.
"""

# see arg_final_synth_model
common_final_synth_model = """
``FINAL_SYNTH_MODEL`` is a string that describes the radial basis function model used to construct the final synthetic
EPI image.
"""

# see arg_bandwidth
common_bandwidth = """
The ``BANDWIDTH`` parameter is used to model
the difference in effective resolution between typically high resolution source
T1w/T2w image and typically low resolution EPI image. ``BANDWIDTH`` specifically
correspond the bandwidth the Epanachnikov blurring kernel used in the synthetic
image model. See ``omni_synthtarget`` documentation for more information.
"""

# see arg_skip_affine
common_skip_affine = """
Enabling this flag will disable affine registration between the
the target EPI image and the set of T1w and T2w anatomical images. Why might
this option be useful? Well, suppose you are abso-posi-lutely certain that the
subject in the scanner did not move at all during data acquisition. Then you
could disable  affine registration and attempt to measure correct just the
distortions caused by field inhomogeneity, and maybe even empirically measure
the structure of EPI distortion arising from different sources. Other uses may
exist, but probably best to leave this option alone.
"""

# see arg_skip_synthtarget_affine
common_skip_synthtarget_affine = """
Enabling this flag will disable the affine registration component of the
SynthTarget program. This option essentially disables the joint registration
component of the SynthTarget algorithm, which alternates finding a solution
between the affine parameters and synthetic image regression parameters. Note
that this is NOT related to the non-linear transform part of the Synth algorithm.
"""

# see arg_resolution_pyramid
common_resolution_pyramid = """
Internally ``omni_synthtarget`` (which
creates a synthetic EPI image that is affine aligned to the input EPI) performs
its magic working from low to high resolution. This process tends to stabilize
estimates by avoiding solutions that are local minima. ``RESOLUTION_PYRAMID`` is a
list of values describing the isotropic voxel size used at each level of the
resolution pyramid.
"""

# see arg_noise_mask_iterations
common_noise_mask_iterations = """
``NOISE_MASK_ITERATIONS`` is an integer that sets the number of refining
iterations used in the the noise mask generating LDA procedure. The initial
'guess' for what voxels contain valid signal is typically a binary brain only
mask derived from the subjects anatomical images and then aligned to the EPI
image. This initial guess is then refined using an iterative temporal linear
discriminant analysis approach. In our our experiments a stable noise mask is
typically achieved in 8-10 iterations. For good measure, we set the default
value just a little higher than this. The appropriate number of iterations may
vary depending on the data type (resting state vs diffusion type EPI data) as
well as the number of samples (frames) present in the data. If you want to make
every second count, you can probably reduce the default without causing too much
havoc. If the synthetic images produced by omni_synthpreproc do not appear
sufficiently accurate for your tastes, we advise that you look closely at the
noise mask volumes that are being estimated for your data set to make sure that
voxels that are being labelled as noise are sensible. Do this by loading up the
EPI data in your favorite viewer and using the estimated noise mask images as an
overlay.
"""

# see arg_noise_mask_dilation_size
common_noise_mask_dilation_size = """
``NOISE_MASK_DILATION_SIZE`` is an integer value that determines how many voxels
to dilate the noise mask before writing it to a file. This option can be used to
create more "conservative" noise masks that label voxels as suspect by simply by
virtue of their proximity to real noise voxels. It is left to the user to
contemplate the morality of this guilt-by-association approach.
"""

# see arg_noise_mask_sigma
common_noise_mask_sigma = """
``NOISE_MASK_SIGMA`` defines the standard deviation of a Gaussian kernel used to
smooth the binary noise mask before writing it to a file. This option is helpful
for creating weight volumes rather than simply binary labels. Gaussian smoothing
is performed after any noise mask dilation """

common_tone_curve = """
Enabling this flag will apply a final constrast enhancing "tone curve" adjustment is to the synthetic
image. Enabling this option can improve (sometimes drastically) the visual similarity between synthetic and target
images. The reason for this option is as follows:

A consequence of image distortion or any differences in spatial resolution or between the input_images and the
target_image is that voxel intensities in a synthetic image will tend to be biased toward the overall mean of the target
image. The visual effect of this bias is that overall contrast is reduced. To address this, SynthTarget includes the
option to pass the final synthetic images through an invertible tone curve operation that attempts to maximize the
similarity of the synthetic and target images. Tone curves are typically sigmoidal (for increasing contrast) or
cubic-looking (for decreasing contrast) non-linear functions. Both types of shapes can be well-modeled by an
appropriately parameterized cumulative beta distribution assuming the voxel intensities of the two images lie between 0
and 1. When the tone curve flag is set, SynthTarget estimates the parameters of the tone curve adjustment that will
maximize the linear correlation coefficient between the target and synthetic images. See also, the -u flag.
"""

common_tone_curve_mask = """
This file contains a binary (0,1) mask aligned to the input images. It is used to indicate the  portion region where
maximizing contrast similarity between target and synthetic images is most important. Only voxels indicated by 1s are
included when determining the optimal tone curve (-c, --tone_curve).
"""

common_err_tol = """
Typically this value should remain untouched by the users who do not crave adventure. One reason for changing this value
is if you have decided not to rescale the target image so that all values lie between 0 and 1.
"""

common_step_size = """
Gradient step size for optimization. Increasing the step size may
speed convergence, but may come at the cost of reduced accuracy. Decreasing the step size slows convergence an if
MAX_ITERATIONS (-i parameter) is not increased appropriately may result in no convergence at all.
"""

common_max_iterations = """
Maximum number of optimizing iterations that will be run to estimate the synthetic image model parameters.
"""

common_moco = """
Motion correction method to use. Current options are `allineate` and `realign4d`. 3dAllineate is much faster than
realign4d, but does not do slice time correction.
"""

# see arg_use_allineate
common_use_allineate = """
This flag sets up the framewise alignment to use 3dAllineate. This may be a preferred over the default
SpaceTimeRealign algorithm since it is much, much faster. When you have many temporal frames in your
dataset, it is advisable to turn this flag on. NOTE: this flag is deprecated since 3dAllineate
is now the default option and doesn't really do anything. See the ``--moco`` flag instead.
"""

# Specific argument help text
# These are for help descriptions that may be specific towards a particular script

synthpreproc_bids_sidecar = """
``BIDS_SIDECAR_FILENAME`` is a path to a .json formatted file that contains
information about the input EPI data set. It is anticipated that most users will
convert raw DICOM data to NIFTI format using the utility, dcm2niix. During
initial data conversion, calling dcm2niix using the ``-b BIDS_SIDECAR_FILENAME``
optional input will produce the requisite .json file.
"""

synthpreproc_func = """
``FUNC`` is a path to the EPI data that you would like to preprocess and align to the subject's anatomical (T1w/T2w)
images and reference atlas (MNI). This can be an un-aligned raw EPI data.
"""

synthpreproc_t1 = """
``T1_FILENAME`` is a path to a subject's T1w anatomical image file. This can be an un-aligned raw image file.
"""

synthpreproc_t2 = """
``T2_FILENAME`` is a path to a subject's T2w anatomical image file. This can be an un-aligned raw image file.
"""

synthpreproc_output_path = """
``OUTPUT_PATH`` is a directory that will store the organized preprocessed output as well as the intermediary and
derivative files created while preprocessing a data set.
"""

synthtarget_target_image = """
The first positional argument consists of a file name for an image that will be approximated by a synthetic image.
This will most likely be a single reference EPI image taken from a resting state, task, or diffusion weighted data set.
"""

synthtarget_interaction_model = """
The second positional argument is a string enclosed by single quotations specifying the radial basis function model
that will be used to construct the synthetic image from the input and target images.

Example 1: A simple case in which a single input image is used to construct a synthetic target image using a six
component radial basis function decomposition: 'rbf(0;6)'

Here the 'rbf' refers to the kind of intensity model to be used (radial basis function), the zero refers to the source
image to which the the RBF decomposition is applied, the 6 refers to the number of radial basis function components
(evenly spaced intensity bins) to use.

Example 2: A case in which two input images are used to construct the synthetic target image. The first input image is
decomposed into 12 radial basis function components and the second image is decomposed into 4 radial basis function
components: 'rbf(0;12) + rbf(1;4)'

Example 3: A case in which two input images are used to construct the synthetic target image. The first image is
decomposed into 4 radial basis components and the second is decomposed into 7 components. This time, we wish to model
potential interactions between the two input images. Conceptually, this allows for the intensity mapping between one
input image and the target image to vary as a function of the voxel intensity of the second input
image: 'rbf(0;4)+rbf(1;7)+rbf(0;4)*rbf(1;7)'
"""

synthtarget_input_images = """
The last, is a list of target image file names. The images represented in these files contains the information that
will be used in order to construct the synthetic image. The most common (but certainly not the only) use case is likely
to involve construction a synthetic EPI image from information contained in a subject's pre-aligned T1w and T2w
anatomical images.
"""

synthtarget_regression_weight_mask = """
A file name representing a user-specified regression weight image that is used to reduce the contribution of noisy or
highly distorted areas of the image when constructing the synthetic image. This file should contain a single image with
the same dimensions as the those that make up those used as input images. Higher values indicate that a voxel should
contribute more to the synthetic image estimate.

For example: often regions of an EPI image exhibit significant signal dropout or distortion. When used as a target
image, a problem arises because, even when an undistorted input image and a target image are reasonably well aligned,
there are some areas where there is no true correspondence between the images, e.g., frontal polar or inferotemporal
field map distortion, or just plain old signal dropout in the EPI. By downweighting these regions with the regresson
mask, their influence on the synthetic image estimate is reduced.

While the user is free to construct whatever weight volume best serves their purposes, a good place to start is with
the omni_synthnoisemask utility, which takes care of a great deal of the legwork and book keeping required to create
a good weight image.
"""

synthtarget_output_prefix = """
SynthTarget estimates affine alignment parameters that optimally register source and target images. A text file
containing the affine matrix is saved as OUTPUT_PREFIX.affine. A text file containing the coefficients for the radial
basis function model that produces the synthetic image is saved as OUTPUT_PREFIX.regress.

A pre-existing affine matrix may be useful in the following situations:

1) It can be used as an initial estimate for another iteration of SynthTarget (see -a option).

2) It can be used as an unchanging affine alignment solution when re-estimating a synthetic image (-a option
combined with --no_register flag). This can be particularly useful when re-estimating a synthetic image from a partially
undistorted target image. For example, suppose you have created an initial synthetic target image based on an orignal
distorted target image. You then correct the distortion by some amount using your favorite non-linear warping software.
You can then re-estimate an improved synthetic image based on the partially undistorted target image without needing to
reestimate the affine parameter (which tends to increase processing time).
"""

synthtarget_regression_output = """
The file REGRESSION_OUTPUT.nii.gz stores the unblurred estimate of the synthetic image. If the input images are high
resolution anatimical T1w and T2w images and the target image is a low resolution EPI, then this image can be
considered a super-resolution version of the EPI image estimated at the resolution of the input images. While
interesting to look at, it should not be used as a non-linear registration target. This is because the non-linear
registration target should have and effective spatial resolution that is similar to the image that is being aligned to
it. Thus, the appropriate image to use as a registration target is the one output by the -f flag (or in some cases, the
-b flag).
"""

synthtarget_synth_image = """
The file SYNTH_IMAGE.nii.gz stores a full synthetic image that is aligned to the input image(s). The key difference
between this image and the one output by the -r option is that this image has the Epanachnikov blurring operator
applied. This image is the real undistorted synthetic target image.
"""

synthtarget_synth_image_target_space = """
The file SYNTH_IMAGE_TARGET_SPACE.nii.gz stores a version of the synthetic target image that is affine aligned to the
original target image. This image is similar to that produced by the -b option and differs only by an affine operation.
For the purposes of non-linear registration, this file is the most likely the one that will be of most use to the user.
"""

synthtarget_bandwidth = """
Bandwidth for the Epanachnikov blurring kernel. In the case where
input images consist of high resolution anatomical T1w and T2w images and the target image is a relatively low
resolution EPI image, the difference in spatial resolution must be modeled. SynthTarget accomplishes this with an
Epanachikov blurring operator which is convolved with the radial basis function decomposed components of the input
images. In principle, the optimal bandwidth parameter should be derivable from theory. In practice though the the
effective spatial resolution of the images is not always determined by the native image resolution. For instance, if the
target image is an EPI image made by averaging several frames together, then there is additional blurring compared to an
image made from a single frame. Thus, the bandwidth parameter is user-modifiable. Some guidance on values: We have found
that when the input images are captured at 1mm isotropic resolution, and target image (EPI) is made by averaging several
frames captured at a native 4 mm isotropic resolution, then a bandwidth parameter of 16 works well. When native EPI
resolution is increased to 2.6 mm isotropic voxels, a bandwidth parameter of 10 seems to work well.
"""

synthtarget_no_register = """
When this flag is enabled, SynthTarget does not attempt to optimize the affine registration parameters
and only the linear model parameters mapping the radial basis function components of the input images to the target
image are calculated. This option is useful when input and target images are already very well-aligned and you just want
to construct a synthetic estimated from the current alignment (or an initial affine alignment estimate passed in using
the -a flag).
"""

synthtarget_output_intmat = """
Enabling this flag saves the radial basis function decomposition of the input images to the current
working directory. This file is in hdf5 format and will be quite large! It can be converted into a NIFTI format file
using the omni_intmat2nifti utility. The result will be a 4D NIFTI file in which each frame depicts a component of the
radial basis function model used to construct the synthetic target image. Examining the output of this command can be
very helpful for understanding or troubleshooting SynthTarget performance.
"""

synthnoisemask_anat_bet_mask_epispace = """
The file name of a binary brain mask defined by the subjects undistorted
anatomical images (e.g., T1w or T2w or some composite of them) that has been affine aligned to the EPI data set referred
to by the  first, ``epi``, argument.

    * It provides a very rough initial labeling of EPI voxels that are likely to be valid and relatively noiseless.

    * It labels the region of the EPI image in which we are interested in detecting noise. That is, the primary use case
for ``omni_synthnoisemask`` is to detect noisy voxels **in the area where the brain should be.**
"""

synthnoisemask_output = """
Path to output file containing the estimated noise mask.
"""

# omni_synthregressionmask arguments
# see arg_synthregressionmask_dil_anat_bet_mask
synthregressionmask_dil_anat_weight_mask = """
The file name of a **dilated** brain only mask aligned to an anatomical (typically T1w or T2w) image. Only voxels within
this mask will contribute anything at all to the final weighting image. Generally this mask should represent the entire
brain as well as a portion of the skull (and perhaps a little beyond that too). This is meant to exclude voxels far
outside of the head that we do not wish to consider when estimating a synthetic image.
"""

# see arg_synthregressionmask_anat_bet_mask
synthregressionmask_anat_bet_mask = """
The file name of a binary brain only mask aligned to an anatomical (typically T1w or T2w) image. Voxels within this mask
are given the greatest (2x) significance in the final weighting image.
"""

# see arg_synthregressionmask_affine
synthregressionmask_affine = """
Path to a file representing an affine transformation that aligns the anatomical image to the EPI data set. This text
file must represent the affine transformation in AFNI format (i.e., suitable for use with 3dAllineate).
"""

# see arg_synthregressionmask_warp
synthregressionmask_warp = """
A non-linear transformation that will warp an affine-aligned anatomical image into proper registration with the input
EPI data set. The inverse of this warp is applied to the weighting image (when it is aligned to the EPI data set)
before it is transformed back into the anatomical image space and saved out. Including this optional warp is useful
in situations where one is iteratively correcting distortion and updating the synthetic image during each step (as in
``omni_synthunwarp`` and ``omni_synthpreproc``). In that case, regions that were initially determined to be *noise* and
were down weighted, may have shifted by some amount as a result of earlier corrections. Including the previous
corrective warp as input ensures that weight mask stays in register with current distortion correction iteration.
"""
