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

import typing
import pathlib
from styxdefs import *

SURFACE_APPLY_AFFINE_METADATA = Metadata(
    id="248f32501c3003298999c7da69bba8ad26520e39.workbench",
    name="surface-apply-affine",
    package="workbench",
    container_image_tag="nx10x/workbench:2.1.0",
)


_SurfaceApplyAffineFlirtParamsDictNoTag = typing.TypedDict('_SurfaceApplyAffineFlirtParamsDictNoTag', {
    "source-volume": str,
    "target-volume": str,
})
SurfaceApplyAffineFlirtParamsDictTagged = typing.TypedDict('SurfaceApplyAffineFlirtParamsDictTagged', {
    "@type": typing.Literal["flirt"],
    "source-volume": str,
    "target-volume": str,
})
SurfaceApplyAffineFlirtParamsDict = _SurfaceApplyAffineFlirtParamsDictNoTag | SurfaceApplyAffineFlirtParamsDictTagged


_SurfaceApplyAffineParamsDictNoTag = typing.TypedDict('_SurfaceApplyAffineParamsDictNoTag', {
    "in-surf": InputPathType,
    "affine": str,
    "out-surf": str,
    "flirt": typing.NotRequired[SurfaceApplyAffineFlirtParamsDict | None],
})
SurfaceApplyAffineParamsDictTagged = typing.TypedDict('SurfaceApplyAffineParamsDictTagged', {
    "@type": typing.Literal["workbench/surface-apply-affine"],
    "in-surf": InputPathType,
    "affine": str,
    "out-surf": str,
    "flirt": typing.NotRequired[SurfaceApplyAffineFlirtParamsDict | None],
})
SurfaceApplyAffineParamsDict = _SurfaceApplyAffineParamsDictNoTag | SurfaceApplyAffineParamsDictTagged


def surface_apply_affine_flirt(
    source_volume: str,
    target_volume: str,
) -> SurfaceApplyAffineFlirtParamsDictTagged:
    """
    Build parameters.
    
    Args:
        source_volume: the source volume used when generating the affine.
        target_volume: the target volume used when generating the affine.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "flirt",
        "source-volume": source_volume,
        "target-volume": target_volume,
    }
    return params


def surface_apply_affine_flirt_validate(
    params: typing.Any,
) -> None:
    """
    Validate parameters. Throws an error if `params` is not a valid
    `SurfaceApplyAffineFlirtParamsDict` 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("source-volume", None) is None:
        raise StyxValidationError("`source-volume` must not be None")
    if not isinstance(params["source-volume"], str):
        raise StyxValidationError(f'`source-volume` has the wrong type: Received `{type(params.get("source-volume", None))}` expected `str`')
    if params.get("target-volume", None) is None:
        raise StyxValidationError("`target-volume` must not be None")
    if not isinstance(params["target-volume"], str):
        raise StyxValidationError(f'`target-volume` has the wrong type: Received `{type(params.get("target-volume", None))}` expected `str`')


def surface_apply_affine_flirt_cargs(
    params: SurfaceApplyAffineFlirtParamsDict,
    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([
        "-flirt",
        params.get("source-volume", None),
        params.get("target-volume", None)
    ])
    return cargs


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


def surface_apply_affine_params(
    in_surf: InputPathType,
    affine: str,
    out_surf: str,
    flirt: SurfaceApplyAffineFlirtParamsDict | None = None,
) -> SurfaceApplyAffineParamsDictTagged:
    """
    Build parameters.
    
    Args:
        in_surf: the surface to transform.
        affine: the affine file.
        out_surf: the output transformed surface.
        flirt: MUST be used if affine is a flirt affine.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "workbench/surface-apply-affine",
        "in-surf": in_surf,
        "affine": affine,
        "out-surf": out_surf,
    }
    if flirt is not None:
        params["flirt"] = flirt
    return params


def surface_apply_affine_validate(
    params: typing.Any,
) -> None:
    """
    Validate parameters. Throws an error if `params` is not a valid
    `SurfaceApplyAffineParamsDict` 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("affine", None) is None:
        raise StyxValidationError("`affine` must not be None")
    if not isinstance(params["affine"], str):
        raise StyxValidationError(f'`affine` has the wrong type: Received `{type(params.get("affine", 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("flirt", None) is not None:
        surface_apply_affine_flirt_validate(params["flirt"])


def surface_apply_affine_cargs(
    params: SurfaceApplyAffineParamsDict,
    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-affine"
    ])
    cargs.append(execution.input_file(params.get("in-surf", None)))
    cargs.append(params.get("affine", None))
    cargs.append(params.get("out-surf", None))
    if params.get("flirt", None) is not None:
        cargs.extend(surface_apply_affine_flirt_cargs(params.get("flirt", None), execution))
    return cargs


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


def surface_apply_affine_execute(
    params: SurfaceApplyAffineParamsDict,
    runner: Runner | None = None,
) -> SurfaceApplyAffineOutputs:
    """
    APPLY AFFINE TRANSFORM TO SURFACE FILE.
    
    For flirt matrices, you must use the -flirt option, because flirt matrices
    are not a complete description of the coordinate transform they represent.
    If the -flirt option is not present, the affine must be a nifti 'world'
    affine, which can be obtained with the -convert-affine command, or aff_conv
    from the 4dfp suite.
    
    Args:
        params: The parameters.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `SurfaceApplyAffineOutputs`).
    """
    surface_apply_affine_validate(params)
    runner = runner or get_global_runner()
    execution = runner.start_execution(SURFACE_APPLY_AFFINE_METADATA)
    params = execution.params(params)
    cargs = surface_apply_affine_cargs(params, execution)
    ret = surface_apply_affine_outputs(params, execution)
    execution.run(cargs)
    return ret


def surface_apply_affine(
    in_surf: InputPathType,
    affine: str,
    out_surf: str,
    flirt: SurfaceApplyAffineFlirtParamsDict | None = None,
    runner: Runner | None = None,
) -> SurfaceApplyAffineOutputs:
    """
    APPLY AFFINE TRANSFORM TO SURFACE FILE.
    
    For flirt matrices, you must use the -flirt option, because flirt matrices
    are not a complete description of the coordinate transform they represent.
    If the -flirt option is not present, the affine must be a nifti 'world'
    affine, which can be obtained with the -convert-affine command, or aff_conv
    from the 4dfp suite.
    
    Args:
        in_surf: the surface to transform.
        affine: the affine file.
        out_surf: the output transformed surface.
        flirt: MUST be used if affine is a flirt affine.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `SurfaceApplyAffineOutputs`).
    """
    params = surface_apply_affine_params(
        in_surf=in_surf,
        affine=affine,
        out_surf=out_surf,
        flirt=flirt,
    )
    return surface_apply_affine_execute(params, runner)


__all__ = [
    "SURFACE_APPLY_AFFINE_METADATA",
    "SurfaceApplyAffineFlirtParamsDict",
    "SurfaceApplyAffineFlirtParamsDictTagged",
    "SurfaceApplyAffineOutputs",
    "SurfaceApplyAffineParamsDict",
    "SurfaceApplyAffineParamsDictTagged",
    "surface_apply_affine",
    "surface_apply_affine_execute",
    "surface_apply_affine_flirt",
    "surface_apply_affine_params",
]
