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

import typing
import pathlib
from styxdefs import *

CONVERT_AFFINE_METADATA = Metadata(
    id="f8f331e0186c1d179bf357df5d5eadf7019f39e3.workbench",
    name="convert-affine",
    package="workbench",
    container_image_tag="nx10x/workbench:2.1.0",
)


_ConvertAffineFromWorldParamsDictNoTag = typing.TypedDict('_ConvertAffineFromWorldParamsDictNoTag', {
    "input": str,
    "inverse": bool,
})
ConvertAffineFromWorldParamsDictTagged = typing.TypedDict('ConvertAffineFromWorldParamsDictTagged', {
    "@type": typing.Literal["from-world"],
    "input": str,
    "inverse": bool,
})
ConvertAffineFromWorldParamsDict = _ConvertAffineFromWorldParamsDictNoTag | ConvertAffineFromWorldParamsDictTagged


_ConvertAffineFromFlirtParamsDictNoTag = typing.TypedDict('_ConvertAffineFromFlirtParamsDictNoTag', {
    "input": str,
    "source-volume": str,
    "target-volume": str,
})
ConvertAffineFromFlirtParamsDictTagged = typing.TypedDict('ConvertAffineFromFlirtParamsDictTagged', {
    "@type": typing.Literal["from-flirt"],
    "input": str,
    "source-volume": str,
    "target-volume": str,
})
ConvertAffineFromFlirtParamsDict = _ConvertAffineFromFlirtParamsDictNoTag | ConvertAffineFromFlirtParamsDictTagged


_ConvertAffineToWorldParamsDictNoTag = typing.TypedDict('_ConvertAffineToWorldParamsDictNoTag', {
    "output": str,
    "inverse": bool,
})
ConvertAffineToWorldParamsDictTagged = typing.TypedDict('ConvertAffineToWorldParamsDictTagged', {
    "@type": typing.Literal["to-world"],
    "output": str,
    "inverse": bool,
})
ConvertAffineToWorldParamsDict = _ConvertAffineToWorldParamsDictNoTag | ConvertAffineToWorldParamsDictTagged


_ConvertAffineToFlirtParamsDictNoTag = typing.TypedDict('_ConvertAffineToFlirtParamsDictNoTag', {
    "output": str,
    "source-volume": str,
    "target-volume": str,
})
ConvertAffineToFlirtParamsDictTagged = typing.TypedDict('ConvertAffineToFlirtParamsDictTagged', {
    "@type": typing.Literal["to-flirt"],
    "output": str,
    "source-volume": str,
    "target-volume": str,
})
ConvertAffineToFlirtParamsDict = _ConvertAffineToFlirtParamsDictNoTag | ConvertAffineToFlirtParamsDictTagged


_ConvertAffineParamsDictNoTag = typing.TypedDict('_ConvertAffineParamsDictNoTag', {
    "from-world": typing.NotRequired[ConvertAffineFromWorldParamsDict | None],
    "from-flirt": typing.NotRequired[ConvertAffineFromFlirtParamsDict | None],
    "to-world": typing.NotRequired[ConvertAffineToWorldParamsDict | None],
    "to-flirt": typing.NotRequired[list[ConvertAffineToFlirtParamsDict] | None],
    "output": typing.NotRequired[str | None],
    "input": typing.NotRequired[str | None],
})
ConvertAffineParamsDictTagged = typing.TypedDict('ConvertAffineParamsDictTagged', {
    "@type": typing.Literal["workbench/convert-affine"],
    "from-world": typing.NotRequired[ConvertAffineFromWorldParamsDict | None],
    "from-flirt": typing.NotRequired[ConvertAffineFromFlirtParamsDict | None],
    "to-world": typing.NotRequired[ConvertAffineToWorldParamsDict | None],
    "to-flirt": typing.NotRequired[list[ConvertAffineToFlirtParamsDict] | None],
    "output": typing.NotRequired[str | None],
    "input": typing.NotRequired[str | None],
})
ConvertAffineParamsDict = _ConvertAffineParamsDictNoTag | ConvertAffineParamsDictTagged


def convert_affine_from_world(
    input_: str,
    inverse: bool = False,
) -> ConvertAffineFromWorldParamsDictTagged:
    """
    Build parameters.
    
    Args:
        input_: the input affine.
        inverse: for files that use 'target to source' convention.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "from-world",
        "input": input_,
        "inverse": inverse,
    }
    return params


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


def convert_affine_from_world_cargs(
    params: ConvertAffineFromWorldParamsDict,
    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([
        "-from-world",
        params.get("input", None)
    ])
    if params.get("inverse", False):
        cargs.append("-inverse")
    return cargs


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


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


def convert_affine_to_world(
    output: str,
    inverse: bool = False,
) -> ConvertAffineToWorldParamsDictTagged:
    """
    Build parameters.
    
    Args:
        output: output - the output affine.
        inverse: write file using 'target to source' convention.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "to-world",
        "output": output,
        "inverse": inverse,
    }
    return params


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


def convert_affine_to_world_cargs(
    params: ConvertAffineToWorldParamsDict,
    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([
        "-to-world",
        params.get("output", None)
    ])
    if params.get("inverse", False):
        cargs.append("-inverse")
    return cargs


def convert_affine_to_flirt(
    output: str,
    source_volume: str,
    target_volume: str,
) -> ConvertAffineToFlirtParamsDictTagged:
    """
    Build parameters.
    
    Args:
        output: output - the output affine.
        source_volume: the volume you want to apply the transform to.
        target_volume: the target space you want the transformed volume to\
            match.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "to-flirt",
        "output": output,
        "source-volume": source_volume,
        "target-volume": target_volume,
    }
    return params


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


class ConvertAffineOutputs(typing.NamedTuple):
    """
    Output object returned when calling `ConvertAffineParamsDict(...)`.
    """
    root: OutputPathType
    """Output root folder. This is the root folder for all outputs."""


def convert_affine_params(
    from_world: ConvertAffineFromWorldParamsDict | None = None,
    from_flirt: ConvertAffineFromFlirtParamsDict | None = None,
    to_world: ConvertAffineToWorldParamsDict | None = None,
    to_flirt: list[ConvertAffineToFlirtParamsDict] | None = None,
    output: str | None = None,
    input_: str | None = None,
) -> ConvertAffineParamsDictTagged:
    """
    Build parameters.
    
    Args:
        from_world: input is a NIFTI 'world' affine.
        from_flirt: input is a flirt matrix.
        to_world: write output as a NIFTI 'world' affine.
        to_flirt: write output as a flirt matrix.
        output: write output as an ITK affine\
            \
            output - the output affine.
        input_: input is an ITK matrix\
            \
            the input affine.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "workbench/convert-affine",
    }
    if from_world is not None:
        params["from-world"] = from_world
    if from_flirt is not None:
        params["from-flirt"] = from_flirt
    if to_world is not None:
        params["to-world"] = to_world
    if to_flirt is not None:
        params["to-flirt"] = to_flirt
    if output is not None:
        params["output"] = output
    if input_ is not None:
        params["input"] = input_
    return params


def convert_affine_validate(
    params: typing.Any,
) -> None:
    """
    Validate parameters. Throws an error if `params` is not a valid
    `ConvertAffineParamsDict` 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("from-world", None) is not None:
        convert_affine_from_world_validate(params["from-world"])
    if params.get("from-flirt", None) is not None:
        convert_affine_from_flirt_validate(params["from-flirt"])
    if params.get("to-world", None) is not None:
        convert_affine_to_world_validate(params["to-world"])
    if params.get("to-flirt", None) is not None:
        if not isinstance(params["to-flirt"], list):
            raise StyxValidationError(f'`to-flirt` has the wrong type: Received `{type(params.get("to-flirt", None))}` expected `list[ConvertAffineToFlirtParamsDict] | None`')
        for e in params["to-flirt"]:
            convert_affine_to_flirt_validate(e)
    if params.get("output", None) is not None:
        if not isinstance(params["output"], str):
            raise StyxValidationError(f'`output` has the wrong type: Received `{type(params.get("output", None))}` expected `str | None`')
    if params.get("input", None) is not None:
        if not isinstance(params["input"], str):
            raise StyxValidationError(f'`input` has the wrong type: Received `{type(params.get("input", None))}` expected `str | None`')


def convert_affine_cargs(
    params: ConvertAffineParamsDict,
    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",
        "-convert-affine"
    ])
    if params.get("from-world", None) is not None or params.get("from-flirt", None) is not None or params.get("to-world", None) is not None or params.get("to-flirt", None) is not None:
        cargs.extend([
            *(convert_affine_from_world_cargs(params.get("from-world", None), execution) if (params.get("from-world", None) is not None) else []),
            *(convert_affine_from_flirt_cargs(params.get("from-flirt", None), execution) if (params.get("from-flirt", None) is not None) else []),
            *(convert_affine_to_world_cargs(params.get("to-world", None), execution) if (params.get("to-world", None) is not None) else []),
            *([a for c in [convert_affine_to_flirt_cargs(s, execution) for s in params.get("to-flirt", None)] for a in c] if (params.get("to-flirt", None) is not None) else [])
        ])
    if params.get("output", None) is not None:
        cargs.extend([
            "-to-itk",
            params.get("output", None)
        ])
    if params.get("input", None) is not None:
        cargs.extend([
            "-from-itk",
            params.get("input", None)
        ])
    return cargs


def convert_affine_outputs(
    params: ConvertAffineParamsDict,
    execution: Execution,
) -> ConvertAffineOutputs:
    """
    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 = ConvertAffineOutputs(
        root=execution.output_file("."),
    )
    return ret


def convert_affine_execute(
    params: ConvertAffineParamsDict,
    runner: Runner | None = None,
) -> ConvertAffineOutputs:
    """
    CONVERT AN AFFINE FILE BETWEEN CONVENTIONS.
    
    NIFTI world matrices can be used directly on mm coordinates via matrix
    multiplication, they use the NIFTI coordinate system, that is, positive X is
    right, positive Y is anterior, and positive Z is superior. Note that
    wb_command assumes that world matrices transform source coordinates to
    target coordinates, while other tools may use affines that transform target
    coordinates to source coordinates.
    
    The ITK format is used by ANTS.
    
    You must specify exactly one -from option, but you may specify multiple -to
    options, and -to-flirt may be specified more than once.
    
    Args:
        params: The parameters.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `ConvertAffineOutputs`).
    """
    convert_affine_validate(params)
    runner = runner or get_global_runner()
    execution = runner.start_execution(CONVERT_AFFINE_METADATA)
    params = execution.params(params)
    cargs = convert_affine_cargs(params, execution)
    ret = convert_affine_outputs(params, execution)
    execution.run(cargs)
    return ret


def convert_affine(
    from_world: ConvertAffineFromWorldParamsDict | None = None,
    from_flirt: ConvertAffineFromFlirtParamsDict | None = None,
    to_world: ConvertAffineToWorldParamsDict | None = None,
    to_flirt: list[ConvertAffineToFlirtParamsDict] | None = None,
    output: str | None = None,
    input_: str | None = None,
    runner: Runner | None = None,
) -> ConvertAffineOutputs:
    """
    CONVERT AN AFFINE FILE BETWEEN CONVENTIONS.
    
    NIFTI world matrices can be used directly on mm coordinates via matrix
    multiplication, they use the NIFTI coordinate system, that is, positive X is
    right, positive Y is anterior, and positive Z is superior. Note that
    wb_command assumes that world matrices transform source coordinates to
    target coordinates, while other tools may use affines that transform target
    coordinates to source coordinates.
    
    The ITK format is used by ANTS.
    
    You must specify exactly one -from option, but you may specify multiple -to
    options, and -to-flirt may be specified more than once.
    
    Args:
        from_world: input is a NIFTI 'world' affine.
        from_flirt: input is a flirt matrix.
        to_world: write output as a NIFTI 'world' affine.
        to_flirt: write output as a flirt matrix.
        output: write output as an ITK affine\
            \
            output - the output affine.
        input_: input is an ITK matrix\
            \
            the input affine.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `ConvertAffineOutputs`).
    """
    params = convert_affine_params(
        from_world=from_world,
        from_flirt=from_flirt,
        to_world=to_world,
        to_flirt=to_flirt,
        output=output,
        input_=input_,
    )
    return convert_affine_execute(params, runner)


__all__ = [
    "CONVERT_AFFINE_METADATA",
    "ConvertAffineFromFlirtParamsDict",
    "ConvertAffineFromFlirtParamsDictTagged",
    "ConvertAffineFromWorldParamsDict",
    "ConvertAffineFromWorldParamsDictTagged",
    "ConvertAffineOutputs",
    "ConvertAffineParamsDict",
    "ConvertAffineParamsDictTagged",
    "ConvertAffineToFlirtParamsDict",
    "ConvertAffineToFlirtParamsDictTagged",
    "ConvertAffineToWorldParamsDict",
    "ConvertAffineToWorldParamsDictTagged",
    "convert_affine",
    "convert_affine_execute",
    "convert_affine_from_flirt",
    "convert_affine_from_world",
    "convert_affine_params",
    "convert_affine_to_flirt",
    "convert_affine_to_world",
]
