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

import typing
import pathlib
from styxdefs import *

METRIC_DILATE_METADATA = Metadata(
    id="5f7bbed13558b8a40bfedd7f35e6b45da7a74ffa.workbench",
    name="metric-dilate",
    package="workbench",
    container_image_tag="nx10x/workbench:2.1.0",
)


_MetricDilateParamsDictNoTag = typing.TypedDict('_MetricDilateParamsDictNoTag', {
    "metric": InputPathType,
    "surface": InputPathType,
    "distance": float,
    "metric-out": str,
    "area-metric": typing.NotRequired[InputPathType | None],
    "exponent": typing.NotRequired[float | None],
    "column": typing.NotRequired[str | None],
    "roi-metric": typing.NotRequired[InputPathType | None],
    "roi-metric": typing.NotRequired[InputPathType | None],
    "legacy-cutoff": bool,
    "linear": bool,
    "nearest": bool,
})
MetricDilateParamsDictTagged = typing.TypedDict('MetricDilateParamsDictTagged', {
    "@type": typing.Literal["workbench/metric-dilate"],
    "metric": InputPathType,
    "surface": InputPathType,
    "distance": float,
    "metric-out": str,
    "area-metric": typing.NotRequired[InputPathType | None],
    "exponent": typing.NotRequired[float | None],
    "column": typing.NotRequired[str | None],
    "roi-metric": typing.NotRequired[InputPathType | None],
    "roi-metric": typing.NotRequired[InputPathType | None],
    "legacy-cutoff": bool,
    "linear": bool,
    "nearest": bool,
})
MetricDilateParamsDict = _MetricDilateParamsDictNoTag | MetricDilateParamsDictTagged


class MetricDilateOutputs(typing.NamedTuple):
    """
    Output object returned when calling `MetricDilateParamsDict(...)`.
    """
    root: OutputPathType
    """Output root folder. This is the root folder for all outputs."""
    metric_out: OutputPathType
    """the output metric"""


def metric_dilate_params(
    metric: InputPathType,
    surface: InputPathType,
    distance: float,
    metric_out: str,
    area_metric: InputPathType | None = None,
    exponent: float | None = None,
    column: str | None = None,
    roi_metric: InputPathType | None = None,
    roi_metric_: InputPathType | None = None,
    legacy_cutoff: bool = False,
    linear: bool = False,
    nearest: bool = False,
) -> MetricDilateParamsDictTagged:
    """
    Build parameters.
    
    Args:
        metric: the metric to dilate.
        surface: the surface to compute on.
        distance: distance in mm to dilate.
        metric_out: the output metric.
        area_metric: vertex areas to use instead of computing them from the\
            surface\
            \
            the corrected vertex areas, as a metric.
        exponent: use a different exponent in the weighting function\
            \
            exponent 'n' to use in (area / (distance ^ n)) as the weighting\
            function (default 6).
        column: select a single column to dilate\
            \
            the column number or name.
        roi_metric: specify an roi of where there is data\
            \
            metric file, positive values denote vertices that have data.
        roi_metric_: specify an roi of vertices to overwrite, rather than\
            vertices with value zero\
            \
            metric file, positive values denote vertices to have their values\
            replaced.
        legacy_cutoff: use the v1.3.2 method of choosing how many vertices to\
            use when calulating the dilated value with weighted method.
        linear: fill in values with linear interpolation along strongest\
            gradient.
        nearest: use the nearest good value instead of a weighted average.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "workbench/metric-dilate",
        "metric": metric,
        "surface": surface,
        "distance": distance,
        "metric-out": metric_out,
        "legacy-cutoff": legacy_cutoff,
        "linear": linear,
        "nearest": nearest,
    }
    if area_metric is not None:
        params["area-metric"] = area_metric
    if exponent is not None:
        params["exponent"] = exponent
    if column is not None:
        params["column"] = column
    if roi_metric is not None:
        params["roi-metric"] = roi_metric
    if roi_metric_ is not None:
        params["roi-metric"] = roi_metric_
    return params


def metric_dilate_validate(
    params: typing.Any,
) -> None:
    """
    Validate parameters. Throws an error if `params` is not a valid
    `MetricDilateParamsDict` 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("metric", None) is None:
        raise StyxValidationError("`metric` must not be None")
    if not isinstance(params["metric"], (pathlib.Path, str)):
        raise StyxValidationError(f'`metric` has the wrong type: Received `{type(params.get("metric", None))}` expected `InputPathType`')
    if params.get("surface", None) is None:
        raise StyxValidationError("`surface` must not be None")
    if not isinstance(params["surface"], (pathlib.Path, str)):
        raise StyxValidationError(f'`surface` has the wrong type: Received `{type(params.get("surface", 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("metric-out", None) is None:
        raise StyxValidationError("`metric-out` must not be None")
    if not isinstance(params["metric-out"], str):
        raise StyxValidationError(f'`metric-out` has the wrong type: Received `{type(params.get("metric-out", None))}` expected `str`')
    if params.get("area-metric", None) is not None:
        if not isinstance(params["area-metric"], (pathlib.Path, str)):
            raise StyxValidationError(f'`area-metric` has the wrong type: Received `{type(params.get("area-metric", None))}` expected `InputPathType | None`')
    if params.get("exponent", None) is not None:
        if not isinstance(params["exponent"], (float, int)):
            raise StyxValidationError(f'`exponent` has the wrong type: Received `{type(params.get("exponent", None))}` expected `float | None`')
    if params.get("column", None) is not None:
        if not isinstance(params["column"], str):
            raise StyxValidationError(f'`column` has the wrong type: Received `{type(params.get("column", None))}` expected `str | None`')
    if params.get("roi-metric", None) is not None:
        if not isinstance(params["roi-metric"], (pathlib.Path, str)):
            raise StyxValidationError(f'`roi-metric` has the wrong type: Received `{type(params.get("roi-metric", None))}` expected `InputPathType | None`')
    if params.get("roi-metric", None) is not None:
        if not isinstance(params["roi-metric"], (pathlib.Path, str)):
            raise StyxValidationError(f'`roi-metric` has the wrong type: Received `{type(params.get("roi-metric", None))}` expected `InputPathType | None`')
    if params.get("legacy-cutoff", False) is None:
        raise StyxValidationError("`legacy-cutoff` must not be None")
    if not isinstance(params["legacy-cutoff"], bool):
        raise StyxValidationError(f'`legacy-cutoff` has the wrong type: Received `{type(params.get("legacy-cutoff", False))}` expected `bool`')
    if params.get("linear", False) is None:
        raise StyxValidationError("`linear` must not be None")
    if not isinstance(params["linear"], bool):
        raise StyxValidationError(f'`linear` has the wrong type: Received `{type(params.get("linear", False))}` expected `bool`')
    if params.get("nearest", False) is None:
        raise StyxValidationError("`nearest` must not be None")
    if not isinstance(params["nearest"], bool):
        raise StyxValidationError(f'`nearest` has the wrong type: Received `{type(params.get("nearest", False))}` expected `bool`')


def metric_dilate_cargs(
    params: MetricDilateParamsDict,
    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",
        "-metric-dilate"
    ])
    cargs.append(execution.input_file(params.get("metric", None)))
    cargs.append(execution.input_file(params.get("surface", None)))
    cargs.append(str(params.get("distance", None)))
    cargs.append(params.get("metric-out", None))
    if params.get("area-metric", None) is not None:
        cargs.extend([
            "-corrected-areas",
            execution.input_file(params.get("area-metric", None))
        ])
    if params.get("exponent", None) is not None:
        cargs.extend([
            "-exponent",
            str(params.get("exponent", None))
        ])
    if params.get("column", None) is not None:
        cargs.extend([
            "-column",
            params.get("column", None)
        ])
    if params.get("roi-metric", None) is not None:
        cargs.extend([
            "-data-roi",
            execution.input_file(params.get("roi-metric", None))
        ])
    if params.get("roi-metric", None) is not None:
        cargs.extend([
            "-bad-vertex-roi",
            execution.input_file(params.get("roi-metric", None))
        ])
    if params.get("legacy-cutoff", False):
        cargs.append("-legacy-cutoff")
    if params.get("linear", False):
        cargs.append("-linear")
    if params.get("nearest", False):
        cargs.append("-nearest")
    return cargs


def metric_dilate_outputs(
    params: MetricDilateParamsDict,
    execution: Execution,
) -> MetricDilateOutputs:
    """
    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 = MetricDilateOutputs(
        root=execution.output_file("."),
        metric_out=execution.output_file(params.get("metric-out", None)),
    )
    return ret


def metric_dilate_execute(
    params: MetricDilateParamsDict,
    runner: Runner | None = None,
) -> MetricDilateOutputs:
    """
    DILATE A METRIC FILE.
    
    For all metric vertices that are designated as bad, if they neighbor a
    non-bad vertex with data or are within the specified distance of such a
    vertex, replace the value with a distance-based weighted average of nearby
    non-bad vertices that have data, otherwise set the value to zero. No matter
    how small <distance> is, dilation will always use at least the immediate
    neighbor vertices. If -nearest is specified, it will use the value from the
    closest non-bad vertex with data within range instead of a weighted average.
    
    If -bad-vertex-roi is specified, all vertices with a positive ROI value are
    bad. If it is not specified, only vertices that have data, with a value of
    zero, are bad. If -data-roi is not specified, all vertices are assumed to
    have data.
    
    Note that the -corrected-areas option uses an approximate correction for the
    change in distances along a group average surface.
    
    To get the behavior of version 1.3.2 or earlier, use '-legacy-cutoff
    -exponent 2'.
    
    Args:
        params: The parameters.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `MetricDilateOutputs`).
    """
    metric_dilate_validate(params)
    runner = runner or get_global_runner()
    execution = runner.start_execution(METRIC_DILATE_METADATA)
    params = execution.params(params)
    cargs = metric_dilate_cargs(params, execution)
    ret = metric_dilate_outputs(params, execution)
    execution.run(cargs)
    return ret


def metric_dilate(
    metric: InputPathType,
    surface: InputPathType,
    distance: float,
    metric_out: str,
    area_metric: InputPathType | None = None,
    exponent: float | None = None,
    column: str | None = None,
    roi_metric: InputPathType | None = None,
    roi_metric_: InputPathType | None = None,
    legacy_cutoff: bool = False,
    linear: bool = False,
    nearest: bool = False,
    runner: Runner | None = None,
) -> MetricDilateOutputs:
    """
    DILATE A METRIC FILE.
    
    For all metric vertices that are designated as bad, if they neighbor a
    non-bad vertex with data or are within the specified distance of such a
    vertex, replace the value with a distance-based weighted average of nearby
    non-bad vertices that have data, otherwise set the value to zero. No matter
    how small <distance> is, dilation will always use at least the immediate
    neighbor vertices. If -nearest is specified, it will use the value from the
    closest non-bad vertex with data within range instead of a weighted average.
    
    If -bad-vertex-roi is specified, all vertices with a positive ROI value are
    bad. If it is not specified, only vertices that have data, with a value of
    zero, are bad. If -data-roi is not specified, all vertices are assumed to
    have data.
    
    Note that the -corrected-areas option uses an approximate correction for the
    change in distances along a group average surface.
    
    To get the behavior of version 1.3.2 or earlier, use '-legacy-cutoff
    -exponent 2'.
    
    Args:
        metric: the metric to dilate.
        surface: the surface to compute on.
        distance: distance in mm to dilate.
        metric_out: the output metric.
        area_metric: vertex areas to use instead of computing them from the\
            surface\
            \
            the corrected vertex areas, as a metric.
        exponent: use a different exponent in the weighting function\
            \
            exponent 'n' to use in (area / (distance ^ n)) as the weighting\
            function (default 6).
        column: select a single column to dilate\
            \
            the column number or name.
        roi_metric: specify an roi of where there is data\
            \
            metric file, positive values denote vertices that have data.
        roi_metric_: specify an roi of vertices to overwrite, rather than\
            vertices with value zero\
            \
            metric file, positive values denote vertices to have their values\
            replaced.
        legacy_cutoff: use the v1.3.2 method of choosing how many vertices to\
            use when calulating the dilated value with weighted method.
        linear: fill in values with linear interpolation along strongest\
            gradient.
        nearest: use the nearest good value instead of a weighted average.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `MetricDilateOutputs`).
    """
    params = metric_dilate_params(
        metric=metric,
        surface=surface,
        distance=distance,
        metric_out=metric_out,
        area_metric=area_metric,
        exponent=exponent,
        column=column,
        roi_metric=roi_metric,
        roi_metric_=roi_metric_,
        legacy_cutoff=legacy_cutoff,
        linear=linear,
        nearest=nearest,
    )
    return metric_dilate_execute(params, runner)


__all__ = [
    "METRIC_DILATE_METADATA",
    "MetricDilateOutputs",
    "MetricDilateParamsDict",
    "MetricDilateParamsDictTagged",
    "metric_dilate",
    "metric_dilate_execute",
    "metric_dilate_params",
]
