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

import typing
import pathlib
from styxdefs import *

SURFACE_AFFINE_REGRESSION_METADATA = Metadata(
    id="81e681b772379bf62c291d6e75c808098051eb2f.workbench",
    name="surface-affine-regression",
    package="workbench",
    container_image_tag="nx10x/workbench:2.1.0",
)


_SurfaceAffineRegressionParamsDictNoTag = typing.TypedDict('_SurfaceAffineRegressionParamsDictNoTag', {
    "source": InputPathType,
    "target": InputPathType,
    "affine-out": str,
})
SurfaceAffineRegressionParamsDictTagged = typing.TypedDict('SurfaceAffineRegressionParamsDictTagged', {
    "@type": typing.Literal["workbench/surface-affine-regression"],
    "source": InputPathType,
    "target": InputPathType,
    "affine-out": str,
})
SurfaceAffineRegressionParamsDict = _SurfaceAffineRegressionParamsDictNoTag | SurfaceAffineRegressionParamsDictTagged


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


def surface_affine_regression_params(
    source: InputPathType,
    target: InputPathType,
    affine_out: str,
) -> SurfaceAffineRegressionParamsDictTagged:
    """
    Build parameters.
    
    Args:
        source: the surface to warp.
        target: the surface to match the coordinates of.
        affine_out: output - the output affine file.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "workbench/surface-affine-regression",
        "source": source,
        "target": target,
        "affine-out": affine_out,
    }
    return params


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


def surface_affine_regression_cargs(
    params: SurfaceAffineRegressionParamsDict,
    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-affine-regression"
    ])
    cargs.append(execution.input_file(params.get("source", None)))
    cargs.append(execution.input_file(params.get("target", None)))
    cargs.append(params.get("affine-out", None))
    return cargs


def surface_affine_regression_outputs(
    params: SurfaceAffineRegressionParamsDict,
    execution: Execution,
) -> SurfaceAffineRegressionOutputs:
    """
    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 = SurfaceAffineRegressionOutputs(
        root=execution.output_file("."),
    )
    return ret


def surface_affine_regression_execute(
    params: SurfaceAffineRegressionParamsDict,
    runner: Runner | None = None,
) -> SurfaceAffineRegressionOutputs:
    """
    REGRESS THE AFFINE TRANSFORM BETWEEN SURFACES ON THE SAME MESH.
    
    Use linear regression to compute an affine that minimizes the sum of squares
    of the coordinate differences between the target surface and the warped
    source surface. Note that this has a bias to shrink the surface that is
    being warped. The output is written as a NIFTI 'world' matrix, see
    -convert-affine to convert it for use in other software.
    
    Args:
        params: The parameters.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `SurfaceAffineRegressionOutputs`).
    """
    surface_affine_regression_validate(params)
    runner = runner or get_global_runner()
    execution = runner.start_execution(SURFACE_AFFINE_REGRESSION_METADATA)
    params = execution.params(params)
    cargs = surface_affine_regression_cargs(params, execution)
    ret = surface_affine_regression_outputs(params, execution)
    execution.run(cargs)
    return ret


def surface_affine_regression(
    source: InputPathType,
    target: InputPathType,
    affine_out: str,
    runner: Runner | None = None,
) -> SurfaceAffineRegressionOutputs:
    """
    REGRESS THE AFFINE TRANSFORM BETWEEN SURFACES ON THE SAME MESH.
    
    Use linear regression to compute an affine that minimizes the sum of squares
    of the coordinate differences between the target surface and the warped
    source surface. Note that this has a bias to shrink the surface that is
    being warped. The output is written as a NIFTI 'world' matrix, see
    -convert-affine to convert it for use in other software.
    
    Args:
        source: the surface to warp.
        target: the surface to match the coordinates of.
        affine_out: output - the output affine file.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `SurfaceAffineRegressionOutputs`).
    """
    params = surface_affine_regression_params(
        source=source,
        target=target,
        affine_out=affine_out,
    )
    return surface_affine_regression_execute(params, runner)


__all__ = [
    "SURFACE_AFFINE_REGRESSION_METADATA",
    "SurfaceAffineRegressionOutputs",
    "SurfaceAffineRegressionParamsDict",
    "SurfaceAffineRegressionParamsDictTagged",
    "surface_affine_regression",
    "surface_affine_regression_execute",
    "surface_affine_regression_params",
]
