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

import typing
import pathlib
from styxdefs import *

SURFACE_APPLY_WARPFIELD_METADATA = Metadata(
    id="81f972736bb6af1bd37bc10b9a2daf65cf08fc89.workbench",
    name="surface-apply-warpfield",
    package="workbench",
    container_image_tag="nx10x/workbench:2.1.0",
)


_SurfaceApplyWarpfieldParamsDictNoTag = typing.TypedDict('_SurfaceApplyWarpfieldParamsDictNoTag', {
    "in-surf": InputPathType,
    "warpfield": str,
    "out-surf": str,
    "forward-warp": typing.NotRequired[str | None],
})
SurfaceApplyWarpfieldParamsDictTagged = typing.TypedDict('SurfaceApplyWarpfieldParamsDictTagged', {
    "@type": typing.Literal["workbench/surface-apply-warpfield"],
    "in-surf": InputPathType,
    "warpfield": str,
    "out-surf": str,
    "forward-warp": typing.NotRequired[str | None],
})
SurfaceApplyWarpfieldParamsDict = _SurfaceApplyWarpfieldParamsDictNoTag | SurfaceApplyWarpfieldParamsDictTagged


class SurfaceApplyWarpfieldOutputs(typing.NamedTuple):
    """
    Output object returned when calling `SurfaceApplyWarpfieldParamsDict(...)`.
    """
    root: OutputPathType
    """Output root folder. This is the root folder for all outputs."""
    out_surf: OutputPathType
    """the output transformed surface"""


def surface_apply_warpfield_params(
    in_surf: InputPathType,
    warpfield: str,
    out_surf: str,
    forward_warp: str | None = None,
) -> SurfaceApplyWarpfieldParamsDictTagged:
    """
    Build parameters.
    
    Args:
        in_surf: the surface to transform.
        warpfield: the INVERSE warpfield.
        out_surf: the output transformed surface.
        forward_warp: MUST be used if using a fnirt warpfield\
            \
            the forward warpfield.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "workbench/surface-apply-warpfield",
        "in-surf": in_surf,
        "warpfield": warpfield,
        "out-surf": out_surf,
    }
    if forward_warp is not None:
        params["forward-warp"] = forward_warp
    return params


def surface_apply_warpfield_validate(
    params: typing.Any,
) -> None:
    """
    Validate parameters. Throws an error if `params` is not a valid
    `SurfaceApplyWarpfieldParamsDict` 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("in-surf", None) is None:
        raise StyxValidationError("`in-surf` must not be None")
    if not isinstance(params["in-surf"], (pathlib.Path, str)):
        raise StyxValidationError(f'`in-surf` has the wrong type: Received `{type(params.get("in-surf", None))}` expected `InputPathType`')
    if params.get("warpfield", None) is None:
        raise StyxValidationError("`warpfield` must not be None")
    if not isinstance(params["warpfield"], str):
        raise StyxValidationError(f'`warpfield` has the wrong type: Received `{type(params.get("warpfield", None))}` expected `str`')
    if params.get("out-surf", None) is None:
        raise StyxValidationError("`out-surf` must not be None")
    if not isinstance(params["out-surf"], str):
        raise StyxValidationError(f'`out-surf` has the wrong type: Received `{type(params.get("out-surf", None))}` expected `str`')
    if params.get("forward-warp", None) is not None:
        if not isinstance(params["forward-warp"], str):
            raise StyxValidationError(f'`forward-warp` has the wrong type: Received `{type(params.get("forward-warp", None))}` expected `str | None`')


def surface_apply_warpfield_cargs(
    params: SurfaceApplyWarpfieldParamsDict,
    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",
        "-surface-apply-warpfield"
    ])
    cargs.append(execution.input_file(params.get("in-surf", None)))
    cargs.append(params.get("warpfield", None))
    cargs.append(params.get("out-surf", None))
    if params.get("forward-warp", None) is not None:
        cargs.extend([
            "-fnirt",
            params.get("forward-warp", None)
        ])
    return cargs


def surface_apply_warpfield_outputs(
    params: SurfaceApplyWarpfieldParamsDict,
    execution: Execution,
) -> SurfaceApplyWarpfieldOutputs:
    """
    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 = SurfaceApplyWarpfieldOutputs(
        root=execution.output_file("."),
        out_surf=execution.output_file(params.get("out-surf", None)),
    )
    return ret


def surface_apply_warpfield_execute(
    params: SurfaceApplyWarpfieldParamsDict,
    runner: Runner | None = None,
) -> SurfaceApplyWarpfieldOutputs:
    """
    APPLY WARPFIELD TO SURFACE FILE.
    
    NOTE: warping a surface requires the INVERSE of the warpfield used to warp
    the volume it lines up with. The header of the forward warp is needed by the
    -fnirt option in order to correctly interpret the displacements in the fnirt
    warpfield.
    
    If the -fnirt option is not present, the warpfield must be a nifti 'world'
    warpfield, which can be obtained with the -convert-warpfield command.
    
    Args:
        params: The parameters.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `SurfaceApplyWarpfieldOutputs`).
    """
    surface_apply_warpfield_validate(params)
    runner = runner or get_global_runner()
    execution = runner.start_execution(SURFACE_APPLY_WARPFIELD_METADATA)
    params = execution.params(params)
    cargs = surface_apply_warpfield_cargs(params, execution)
    ret = surface_apply_warpfield_outputs(params, execution)
    execution.run(cargs)
    return ret


def surface_apply_warpfield(
    in_surf: InputPathType,
    warpfield: str,
    out_surf: str,
    forward_warp: str | None = None,
    runner: Runner | None = None,
) -> SurfaceApplyWarpfieldOutputs:
    """
    APPLY WARPFIELD TO SURFACE FILE.
    
    NOTE: warping a surface requires the INVERSE of the warpfield used to warp
    the volume it lines up with. The header of the forward warp is needed by the
    -fnirt option in order to correctly interpret the displacements in the fnirt
    warpfield.
    
    If the -fnirt option is not present, the warpfield must be a nifti 'world'
    warpfield, which can be obtained with the -convert-warpfield command.
    
    Args:
        in_surf: the surface to transform.
        warpfield: the INVERSE warpfield.
        out_surf: the output transformed surface.
        forward_warp: MUST be used if using a fnirt warpfield\
            \
            the forward warpfield.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `SurfaceApplyWarpfieldOutputs`).
    """
    params = surface_apply_warpfield_params(
        in_surf=in_surf,
        warpfield=warpfield,
        out_surf=out_surf,
        forward_warp=forward_warp,
    )
    return surface_apply_warpfield_execute(params, runner)


__all__ = [
    "SURFACE_APPLY_WARPFIELD_METADATA",
    "SurfaceApplyWarpfieldOutputs",
    "SurfaceApplyWarpfieldParamsDict",
    "SurfaceApplyWarpfieldParamsDictTagged",
    "surface_apply_warpfield",
    "surface_apply_warpfield_execute",
    "surface_apply_warpfield_params",
]
