# This file was auto generated by Styx.
# Do not edit this file directly.

import typing
import pathlib
from styxdefs import *

VOLUME_EXTREMA_METADATA = Metadata(
    id="bde4b9ab2a53737d37cd5c4267bc185877f0a3aa.workbench",
    name="volume-extrema",
    package="workbench",
    container_image_tag="nx10x/workbench:2.1.0",
)


_VolumeExtremaPresmoothParamsDictNoTag = typing.TypedDict('_VolumeExtremaPresmoothParamsDictNoTag', {
    "kernel": float,
    "fwhm": bool,
})
VolumeExtremaPresmoothParamsDictTagged = typing.TypedDict('VolumeExtremaPresmoothParamsDictTagged', {
    "@type": typing.Literal["presmooth"],
    "kernel": float,
    "fwhm": bool,
})
VolumeExtremaPresmoothParamsDict = _VolumeExtremaPresmoothParamsDictNoTag | VolumeExtremaPresmoothParamsDictTagged


_VolumeExtremaThresholdParamsDictNoTag = typing.TypedDict('_VolumeExtremaThresholdParamsDictNoTag', {
    "low": float,
    "high": float,
})
VolumeExtremaThresholdParamsDictTagged = typing.TypedDict('VolumeExtremaThresholdParamsDictTagged', {
    "@type": typing.Literal["threshold"],
    "low": float,
    "high": float,
})
VolumeExtremaThresholdParamsDict = _VolumeExtremaThresholdParamsDictNoTag | VolumeExtremaThresholdParamsDictTagged


_VolumeExtremaParamsDictNoTag = typing.TypedDict('_VolumeExtremaParamsDictNoTag', {
    "volume-in": InputPathType,
    "distance": float,
    "volume-out": str,
    "presmooth": typing.NotRequired[VolumeExtremaPresmoothParamsDict | None],
    "threshold": typing.NotRequired[VolumeExtremaThresholdParamsDict | None],
    "subvolume": typing.NotRequired[str | None],
    "roi-volume": typing.NotRequired[InputPathType | None],
    "only-minima": bool,
    "only-maxima": bool,
    "consolidate-mode": bool,
    "sum-subvols": bool,
})
VolumeExtremaParamsDictTagged = typing.TypedDict('VolumeExtremaParamsDictTagged', {
    "@type": typing.Literal["workbench/volume-extrema"],
    "volume-in": InputPathType,
    "distance": float,
    "volume-out": str,
    "presmooth": typing.NotRequired[VolumeExtremaPresmoothParamsDict | None],
    "threshold": typing.NotRequired[VolumeExtremaThresholdParamsDict | None],
    "subvolume": typing.NotRequired[str | None],
    "roi-volume": typing.NotRequired[InputPathType | None],
    "only-minima": bool,
    "only-maxima": bool,
    "consolidate-mode": bool,
    "sum-subvols": bool,
})
VolumeExtremaParamsDict = _VolumeExtremaParamsDictNoTag | VolumeExtremaParamsDictTagged


def volume_extrema_presmooth(
    kernel: float,
    fwhm: bool = False,
) -> VolumeExtremaPresmoothParamsDictTagged:
    """
    Build parameters.
    
    Args:
        kernel: the size of the gaussian smoothing kernel in mm, as sigma by\
            default.
        fwhm: kernel size is FWHM, not sigma.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "presmooth",
        "kernel": kernel,
        "fwhm": fwhm,
    }
    return params


def volume_extrema_presmooth_validate(
    params: typing.Any,
) -> None:
    """
    Validate parameters. Throws an error if `params` is not a valid
    `VolumeExtremaPresmoothParamsDict` object.
    
    Args:
        params: The parameters object to validate.
    """
    if params is None or not isinstance(params, dict):
        raise StyxValidationError(f'Params object has the wrong type \'{type(params)}\'')
    if params.get("kernel", None) is None:
        raise StyxValidationError("`kernel` must not be None")
    if not isinstance(params["kernel"], (float, int)):
        raise StyxValidationError(f'`kernel` has the wrong type: Received `{type(params.get("kernel", None))}` expected `float`')
    if params.get("fwhm", False) is None:
        raise StyxValidationError("`fwhm` must not be None")
    if not isinstance(params["fwhm"], bool):
        raise StyxValidationError(f'`fwhm` has the wrong type: Received `{type(params.get("fwhm", False))}` expected `bool`')


def volume_extrema_presmooth_cargs(
    params: VolumeExtremaPresmoothParamsDict,
    execution: Execution,
) -> list[str]:
    """
    Build command-line arguments from parameters.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Command-line arguments.
    """
    cargs = []
    cargs.extend([
        "-presmooth",
        str(params.get("kernel", None))
    ])
    if params.get("fwhm", False):
        cargs.append("-fwhm")
    return cargs


def volume_extrema_threshold(
    low: float,
    high: float,
) -> VolumeExtremaThresholdParamsDictTagged:
    """
    Build parameters.
    
    Args:
        low: the largest value to consider for being a minimum.
        high: the smallest value to consider for being a maximum.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "threshold",
        "low": low,
        "high": high,
    }
    return params


def volume_extrema_threshold_validate(
    params: typing.Any,
) -> None:
    """
    Validate parameters. Throws an error if `params` is not a valid
    `VolumeExtremaThresholdParamsDict` object.
    
    Args:
        params: The parameters object to validate.
    """
    if params is None or not isinstance(params, dict):
        raise StyxValidationError(f'Params object has the wrong type \'{type(params)}\'')
    if params.get("low", None) is None:
        raise StyxValidationError("`low` must not be None")
    if not isinstance(params["low"], (float, int)):
        raise StyxValidationError(f'`low` has the wrong type: Received `{type(params.get("low", None))}` expected `float`')
    if params.get("high", None) is None:
        raise StyxValidationError("`high` must not be None")
    if not isinstance(params["high"], (float, int)):
        raise StyxValidationError(f'`high` has the wrong type: Received `{type(params.get("high", None))}` expected `float`')


def volume_extrema_threshold_cargs(
    params: VolumeExtremaThresholdParamsDict,
    execution: Execution,
) -> list[str]:
    """
    Build command-line arguments from parameters.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Command-line arguments.
    """
    cargs = []
    cargs.extend([
        "-threshold",
        str(params.get("low", None)),
        str(params.get("high", None))
    ])
    return cargs


class VolumeExtremaOutputs(typing.NamedTuple):
    """
    Output object returned when calling `VolumeExtremaParamsDict(...)`.
    """
    root: OutputPathType
    """Output root folder. This is the root folder for all outputs."""
    volume_out: OutputPathType
    """the output extrema volume"""


def volume_extrema_params(
    volume_in: InputPathType,
    distance: float,
    volume_out: str,
    presmooth: VolumeExtremaPresmoothParamsDict | None = None,
    threshold: VolumeExtremaThresholdParamsDict | None = None,
    subvolume: str | None = None,
    roi_volume: InputPathType | None = None,
    only_minima: bool = False,
    only_maxima: bool = False,
    consolidate_mode: bool = False,
    sum_subvols: bool = False,
) -> VolumeExtremaParamsDictTagged:
    """
    Build parameters.
    
    Args:
        volume_in: volume file to find the extrema of.
        distance: the minimum distance between identified extrema of the same\
            type.
        volume_out: the output extrema volume.
        presmooth: smooth the volume before finding extrema.
        threshold: ignore small extrema.
        subvolume: select a single subvolume to find extrema in\
            \
            the subvolume number or name.
        roi_volume: ignore values outside the selected area\
            \
            the area to find extrema in.
        only_minima: only find the minima.
        only_maxima: only find the maxima.
        consolidate_mode: use consolidation of local minima instead of a large\
            neighborhood.
        sum_subvols: output the sum of the extrema subvolumes instead of each\
            subvolume separately.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "workbench/volume-extrema",
        "volume-in": volume_in,
        "distance": distance,
        "volume-out": volume_out,
        "only-minima": only_minima,
        "only-maxima": only_maxima,
        "consolidate-mode": consolidate_mode,
        "sum-subvols": sum_subvols,
    }
    if presmooth is not None:
        params["presmooth"] = presmooth
    if threshold is not None:
        params["threshold"] = threshold
    if subvolume is not None:
        params["subvolume"] = subvolume
    if roi_volume is not None:
        params["roi-volume"] = roi_volume
    return params


def volume_extrema_validate(
    params: typing.Any,
) -> None:
    """
    Validate parameters. Throws an error if `params` is not a valid
    `VolumeExtremaParamsDict` object.
    
    Args:
        params: The parameters object to validate.
    """
    if params is None or not isinstance(params, dict):
        raise StyxValidationError(f'Params object has the wrong type \'{type(params)}\'')
    if params.get("volume-in", None) is None:
        raise StyxValidationError("`volume-in` must not be None")
    if not isinstance(params["volume-in"], (pathlib.Path, str)):
        raise StyxValidationError(f'`volume-in` has the wrong type: Received `{type(params.get("volume-in", None))}` expected `InputPathType`')
    if params.get("distance", None) is None:
        raise StyxValidationError("`distance` must not be None")
    if not isinstance(params["distance"], (float, int)):
        raise StyxValidationError(f'`distance` has the wrong type: Received `{type(params.get("distance", None))}` expected `float`')
    if params.get("volume-out", None) is None:
        raise StyxValidationError("`volume-out` must not be None")
    if not isinstance(params["volume-out"], str):
        raise StyxValidationError(f'`volume-out` has the wrong type: Received `{type(params.get("volume-out", None))}` expected `str`')
    if params.get("presmooth", None) is not None:
        volume_extrema_presmooth_validate(params["presmooth"])
    if params.get("threshold", None) is not None:
        volume_extrema_threshold_validate(params["threshold"])
    if params.get("subvolume", None) is not None:
        if not isinstance(params["subvolume"], str):
            raise StyxValidationError(f'`subvolume` has the wrong type: Received `{type(params.get("subvolume", None))}` expected `str | None`')
    if params.get("roi-volume", None) is not None:
        if not isinstance(params["roi-volume"], (pathlib.Path, str)):
            raise StyxValidationError(f'`roi-volume` has the wrong type: Received `{type(params.get("roi-volume", None))}` expected `InputPathType | None`')
    if params.get("only-minima", False) is None:
        raise StyxValidationError("`only-minima` must not be None")
    if not isinstance(params["only-minima"], bool):
        raise StyxValidationError(f'`only-minima` has the wrong type: Received `{type(params.get("only-minima", False))}` expected `bool`')
    if params.get("only-maxima", False) is None:
        raise StyxValidationError("`only-maxima` must not be None")
    if not isinstance(params["only-maxima"], bool):
        raise StyxValidationError(f'`only-maxima` has the wrong type: Received `{type(params.get("only-maxima", False))}` expected `bool`')
    if params.get("consolidate-mode", False) is None:
        raise StyxValidationError("`consolidate-mode` must not be None")
    if not isinstance(params["consolidate-mode"], bool):
        raise StyxValidationError(f'`consolidate-mode` has the wrong type: Received `{type(params.get("consolidate-mode", False))}` expected `bool`')
    if params.get("sum-subvols", False) is None:
        raise StyxValidationError("`sum-subvols` must not be None")
    if not isinstance(params["sum-subvols"], bool):
        raise StyxValidationError(f'`sum-subvols` has the wrong type: Received `{type(params.get("sum-subvols", False))}` expected `bool`')


def volume_extrema_cargs(
    params: VolumeExtremaParamsDict,
    execution: Execution,
) -> list[str]:
    """
    Build command-line arguments from parameters.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Command-line arguments.
    """
    cargs = []
    cargs.extend([
        "wb_command",
        "-volume-extrema"
    ])
    cargs.append(execution.input_file(params.get("volume-in", None)))
    cargs.append(str(params.get("distance", None)))
    cargs.append(params.get("volume-out", None))
    if params.get("presmooth", None) is not None or params.get("threshold", None) is not None:
        cargs.extend([
            *(volume_extrema_presmooth_cargs(params.get("presmooth", None), execution) if (params.get("presmooth", None) is not None) else []),
            *(volume_extrema_threshold_cargs(params.get("threshold", None), execution) if (params.get("threshold", None) is not None) else [])
        ])
    if params.get("subvolume", None) is not None:
        cargs.extend([
            "-subvolume",
            params.get("subvolume", None)
        ])
    if params.get("roi-volume", None) is not None:
        cargs.extend([
            "-roi",
            execution.input_file(params.get("roi-volume", None))
        ])
    if params.get("only-minima", False):
        cargs.append("-only-minima")
    if params.get("only-maxima", False):
        cargs.append("-only-maxima")
    if params.get("consolidate-mode", False):
        cargs.append("-consolidate-mode")
    if params.get("sum-subvols", False):
        cargs.append("-sum-subvols")
    return cargs


def volume_extrema_outputs(
    params: VolumeExtremaParamsDict,
    execution: Execution,
) -> VolumeExtremaOutputs:
    """
    Build outputs object containing output file paths and possibly stdout/stderr.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Outputs object.
    """
    ret = VolumeExtremaOutputs(
        root=execution.output_file("."),
        volume_out=execution.output_file(params.get("volume-out", None)),
    )
    return ret


def volume_extrema_execute(
    params: VolumeExtremaParamsDict,
    runner: Runner | None = None,
) -> VolumeExtremaOutputs:
    """
    FIND EXTREMA IN A VOLUME FILE.
    
    Finds extrema in a volume file, such that no two extrema of the same type
    are within <distance> of each other. The extrema are labeled as -1 for
    minima, 1 for maxima, 0 otherwise. If -only-maxima or -only-minima is
    specified, then it will ignore extrema not of the specified type. These
    options are mutually exclusive.
    
    If -sum-subvols is specified, these extrema subvolumes are summed, and the
    output has a single subvolume with this result.
    
    By default, a datapoint is an extrema only if it is more extreme than every
    other datapoint that is within <distance> from it. If -consolidate-mode is
    used, it instead starts by finding all datapoints that are more extreme than
    their immediate neighbors, then while there are any extrema within
    <distance> of each other, take the two extrema closest to each other and
    merge them into one by a weighted average based on how many original extrema
    have been merged into each.
    
    By default, all input subvolumes are used with no smoothing, use -subvolume
    to specify a single subvolume to use, and -presmooth to smooth the input
    before finding the extrema.
    
    Args:
        params: The parameters.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `VolumeExtremaOutputs`).
    """
    volume_extrema_validate(params)
    runner = runner or get_global_runner()
    execution = runner.start_execution(VOLUME_EXTREMA_METADATA)
    params = execution.params(params)
    cargs = volume_extrema_cargs(params, execution)
    ret = volume_extrema_outputs(params, execution)
    execution.run(cargs)
    return ret


def volume_extrema(
    volume_in: InputPathType,
    distance: float,
    volume_out: str,
    presmooth: VolumeExtremaPresmoothParamsDict | None = None,
    threshold: VolumeExtremaThresholdParamsDict | None = None,
    subvolume: str | None = None,
    roi_volume: InputPathType | None = None,
    only_minima: bool = False,
    only_maxima: bool = False,
    consolidate_mode: bool = False,
    sum_subvols: bool = False,
    runner: Runner | None = None,
) -> VolumeExtremaOutputs:
    """
    FIND EXTREMA IN A VOLUME FILE.
    
    Finds extrema in a volume file, such that no two extrema of the same type
    are within <distance> of each other. The extrema are labeled as -1 for
    minima, 1 for maxima, 0 otherwise. If -only-maxima or -only-minima is
    specified, then it will ignore extrema not of the specified type. These
    options are mutually exclusive.
    
    If -sum-subvols is specified, these extrema subvolumes are summed, and the
    output has a single subvolume with this result.
    
    By default, a datapoint is an extrema only if it is more extreme than every
    other datapoint that is within <distance> from it. If -consolidate-mode is
    used, it instead starts by finding all datapoints that are more extreme than
    their immediate neighbors, then while there are any extrema within
    <distance> of each other, take the two extrema closest to each other and
    merge them into one by a weighted average based on how many original extrema
    have been merged into each.
    
    By default, all input subvolumes are used with no smoothing, use -subvolume
    to specify a single subvolume to use, and -presmooth to smooth the input
    before finding the extrema.
    
    Args:
        volume_in: volume file to find the extrema of.
        distance: the minimum distance between identified extrema of the same\
            type.
        volume_out: the output extrema volume.
        presmooth: smooth the volume before finding extrema.
        threshold: ignore small extrema.
        subvolume: select a single subvolume to find extrema in\
            \
            the subvolume number or name.
        roi_volume: ignore values outside the selected area\
            \
            the area to find extrema in.
        only_minima: only find the minima.
        only_maxima: only find the maxima.
        consolidate_mode: use consolidation of local minima instead of a large\
            neighborhood.
        sum_subvols: output the sum of the extrema subvolumes instead of each\
            subvolume separately.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `VolumeExtremaOutputs`).
    """
    params = volume_extrema_params(
        volume_in=volume_in,
        distance=distance,
        volume_out=volume_out,
        presmooth=presmooth,
        threshold=threshold,
        subvolume=subvolume,
        roi_volume=roi_volume,
        only_minima=only_minima,
        only_maxima=only_maxima,
        consolidate_mode=consolidate_mode,
        sum_subvols=sum_subvols,
    )
    return volume_extrema_execute(params, runner)


__all__ = [
    "VOLUME_EXTREMA_METADATA",
    "VolumeExtremaOutputs",
    "VolumeExtremaParamsDict",
    "VolumeExtremaParamsDictTagged",
    "VolumeExtremaPresmoothParamsDict",
    "VolumeExtremaPresmoothParamsDictTagged",
    "VolumeExtremaThresholdParamsDict",
    "VolumeExtremaThresholdParamsDictTagged",
    "volume_extrema",
    "volume_extrema_execute",
    "volume_extrema_params",
    "volume_extrema_presmooth",
    "volume_extrema_threshold",
]
