/* ----------------------------------------------------------------------------
@COPYRIGHT  :
              Copyright 1993,1994,1995 David MacDonald,
              McConnell Brain Imaging Centre,
              Montreal Neurological Institute, McGill University.
              Permission to use, copy, modify, and distribute this
              software and its documentation for any purpose and without
              fee is hereby granted, provided that the above copyright
              notice appear in all copies.  The author and McGill University
              make no representations about the suitability of this
              software for any purpose.  It is provided "as is" without
              express or implied warranty.
---------------------------------------------------------------------------- */

#include  <internal_volume_io.h>

#ifndef lint
static char rcsid[] = "$Header: /software/source/minc/cvsroot/minc/volume_io/Volumes/output_volume.c,v 1.23 2004/10/04 20:23:52 bert Exp $";
#endif

/* ----------------------------- MNI Header -----------------------------------
@NAME       : get_file_dimension_names
@INPUT      : filename
              n_dims
@OUTPUT     : dim_names
@RETURNS    : OK or ERROR
@DESCRIPTION: Gets the names of the dimensions from the specified file.
              dim_names is an array of STRINGS, where the array has been
              allocated, but not each string.
@METHOD     : 
@GLOBALS    : 
@CALLS      : 
@CREATED    : 1993            David MacDonald
@MODIFIED   : 
---------------------------------------------------------------------------- */

VIOAPI  Status   get_file_dimension_names(
    STRING   filename,
    int      *n_dims,
    STRING   *dim_names[] )
{
    int                   i;
    Status                status;
    volume_input_struct   volume_input;
    Volume                tmp_volume;

    status = start_volume_input( filename, -1, File_order_dimension_names,
                                 MI_ORIGINAL_TYPE, FALSE, 0.0, 0.0,
                                 TRUE, &tmp_volume, (minc_input_options *) NULL,
                                 &volume_input );

    if( status == OK )
    {
        *n_dims = get_volume_n_dimensions( tmp_volume );

        ALLOC( *dim_names, *n_dims );

        for_less( i, 0, *n_dims )
        {
            (*dim_names)[i] = create_string(
                           volume_input.minc_file->dim_names[i]);
        }

        delete_volume_input( &volume_input );
        delete_volume( tmp_volume );
    }

    return( status );
}

/* ----------------------------- MNI Header -----------------------------------
@NAME       : create_output_dim_names
@INPUT      : volume
              original_filename
              options
@OUTPUT     : file_sizes
@RETURNS    : array of names
@DESCRIPTION: Creates an array of dimension names for file output.  If the
              options contains a set of names, they are used.  Otherwise,
              if the original_filename is specified (non-NULL), then the
              dimension names from it are used, if they contain all the
              dimension names in the volume.  Otherwise, those from the
              volume are used.  The file_sizes[] array is set to match
              the sizes in the volume cross-referenced with the dimension
              names.
@METHOD     : 
@GLOBALS    : 
@CALLS      : 
@CREATED    : Nov. 4, 1995    David MacDonald
@MODIFIED   : 
---------------------------------------------------------------------------- */

VIOAPI  STRING  *create_output_dim_names(
    Volume                volume,
    STRING                original_filename,
    minc_output_options   *options,
    int                   file_sizes[] )
{
    int                  n_dims, n_file_dims, dim_index;
    int                  vol_sizes[MAX_DIMENSIONS];
    int                  i, j, n_found;
    STRING               *file_dim_names;
    STRING               *vol_dimension_names;
    STRING               *dim_names;

    get_volume_sizes( volume, vol_sizes );

    n_dims = get_volume_n_dimensions(volume);
    vol_dimension_names = get_volume_dimension_names( volume );

    ALLOC( dim_names, n_dims );

    /*--- either get the output dim name ordering from the original
          filename, the volume, or the options */

    if( options != NULL && string_length( options->dimension_names[0] ) > 0 )
    {
        for_less( i, 0, n_dims )
            dim_names[i] = create_string( options->dimension_names[i] );
    }
    else
    {
        if( original_filename != NULL && file_exists(original_filename) &&
            get_file_dimension_names( original_filename, &n_file_dims,
                                      &file_dim_names ) == OK )
        {
            /*--- extract the dimension names from the file which match
                  those of the volume, so a 3D volume of z, y, x with a 4D file
                  of x y z t, will generate a list of dim_names: x y z */

            dim_index = 0;

            for_less( i, 0, n_file_dims )
            {
                for_less( j, 0, n_dims )
                {
                    if( equal_strings( vol_dimension_names[j],
                                       file_dim_names[i] ) )
                    {
                        dim_names[dim_index] = create_string(
                                                  vol_dimension_names[j] );
                        ++dim_index;
                        break;
                    }
                }

                if( dim_index == n_dims )  /*--- save time */
                    break;
            }

            /*--- check that all volume dimensions exist in the file */

            if( dim_index != n_dims )
            {
                for_less( i, 0, dim_index )
                    delete_string( dim_names[i] );

                for_less( i, 0, n_dims )
                    dim_names[i] = create_string( vol_dimension_names[i] );
            }

            /*--- free up the file dimension names */

            for_less( i, 0, n_file_dims )
                delete_string( file_dim_names[i] );

            FREE( file_dim_names );
        }
        else   /*--- no original file specified, use the volumes own list */
        {
            for_less( i, 0, n_dims )
                dim_names[i] = create_string( vol_dimension_names[i] );
        }
    }

    /*--- check that the set of dimension names are simply a permutation
          of the ones in the volume */

    n_found = 0;

    for_less( i, 0, n_dims )
    {
        for_less( j, 0, n_dims )
        {
            if( equal_strings( dim_names[j], vol_dimension_names[i] ) )
            {
                file_sizes[j] = vol_sizes[i];
                ++n_found;
            }
        }
    }

    /*--- act on whether the set of names was a permutation or not */

    if( n_found != n_dims )
    {
        print_error(
               "create_output_dim_names: dimension name mismatch.\n" );

        delete_dimension_names( volume, dim_names );

        dim_names = NULL;
    }

    /*--- no longer need the volume dimension names */

    delete_dimension_names( volume, vol_dimension_names );

    return( dim_names );
}

/* ----------------------------- MNI Header -----------------------------------
@NAME       : copy_volume_auxiliary_and_history
@INPUT      : minc_file
              filename
              original_filename
              history
@OUTPUT     : 
@RETURNS    : OK or ERROR
@DESCRIPTION: If the original_filename is specified, Copies the auxiliary
              data from it.  If the history is specified, adds the history
              line.
@METHOD     : 
@GLOBALS    : 
@CALLS      : 
@CREATED    : Oct. 24, 1995    David MacDonald
@MODIFIED   : 
---------------------------------------------------------------------------- */

VIOAPI  Status   copy_volume_auxiliary_and_history(
    Minc_file   minc_file,
    STRING      filename,
    STRING      original_filename,
    STRING      history )
{
    Status    status;
    BOOLEAN   copy_original_file_data;
    STRING    full_filename, full_original_filename;

    copy_original_file_data = FALSE;

    if( original_filename != NULL )
    {
        full_filename = expand_filename( filename );
        full_original_filename = expand_filename( original_filename );

        if( !equal_strings( full_filename, full_original_filename ) &&
            file_exists( full_original_filename ) )
        {
            copy_original_file_data = TRUE;
        }

        delete_string( full_filename );
        delete_string( full_original_filename );
    }

    status = OK;

    if( copy_original_file_data )
    {
        status = copy_auxiliary_data_from_minc_file( minc_file,
                                                     original_filename,
                                                     history );
    }
    else if( history != NULL )
        status = add_minc_history( minc_file, history );

    return( status );
}

/* ----------------------------- MNI Header -----------------------------------
@NAME       : output_modified_volume
@INPUT      : filename
              file_nc_data_type
              file_signed_flag
              file_voxel_min
              file_voxel_max
              volume
              original_filename
              history
              options
@OUTPUT     : 
@RETURNS    : OK or ERROR
@DESCRIPTION: Creates a Minc file and outputs the volume to it.  The data
              type of the file is either specified by the second through fifth
              parameters, or by the volume, if file_nc_data_type is
              MI_ORIGINAL_TYPE.  The volume is assumed to be derived, in some
              fashion, from an existing MINC file, and the auxiliary data
              from the existing MINC file, 'original_filename', is
              copied to the output file, along with the 'history' string.
@METHOD     : 
@GLOBALS    : 
@CALLS      : 
@CREATED    : 1993            David MacDonald
@MODIFIED   : May  22, 1997   D. MacDonald - now sets
                                            use_volume_starts_and_steps flag
---------------------------------------------------------------------------- */

VIOAPI  Status  output_modified_volume(
    STRING                filename,
    nc_type               file_nc_data_type,
    BOOLEAN               file_signed_flag,
    Real                  file_voxel_min,
    Real                  file_voxel_max,
    Volume                volume,
    STRING                original_filename,
    STRING                history,
    minc_output_options   *options )
{
    Status               status;
    Minc_file            minc_file;
    int                  n_dims, sizes[MAX_DIMENSIONS];
    Real                 real_min, real_max;
    STRING               *dim_names;
    minc_output_options  used_options;

    dim_names = create_output_dim_names( volume, original_filename,
                                         options, sizes );

    if( dim_names == NULL )
        return( ERROR );

    n_dims = get_volume_n_dimensions(volume);

    if( options == NULL )
        set_default_minc_output_options( &used_options );
    else
        used_options = *options;

    if( used_options.global_image_range[0] >=
        used_options.global_image_range[1] )
    {
        get_volume_real_range( volume, &real_min, &real_max );
        set_minc_output_real_range( &used_options, real_min, real_max );
    }

    /*--- if the user has not explicitly set the use_volume_starts_and_steps
          flag, let's set it if the transform is linear, to output the
          same starts as was input, and avoid round-off error */

    if( !used_options.use_starts_set &&
        !used_options.use_volume_starts_and_steps &&
        get_transform_type(get_voxel_to_world_transform(volume)) == LINEAR )
    {
        set_minc_output_use_volume_starts_and_steps_flag( &used_options, TRUE );
    }

    minc_file = initialize_minc_output( filename,
                                        n_dims, dim_names, sizes,
                                        file_nc_data_type, file_signed_flag,
                                        file_voxel_min, file_voxel_max,
                                        get_voxel_to_world_transform(volume),
                                        volume, &used_options );

    if( minc_file == NULL )
        return( ERROR );

    status = copy_volume_auxiliary_and_history( minc_file, filename,
                                                original_filename, history );

    if( status == OK )
        status = output_minc_volume( minc_file );

    if( status == OK )
        status = close_minc_output( minc_file );

    delete_dimension_names( volume, dim_names );

    return( status );
}

/* ----------------------------- MNI Header -----------------------------------
@NAME       : output_volume
@INPUT      : filename
              file_nc_data_type
              file_signed_flag
              file_voxel_min
              file_voxel_max
              volume
              history
              options
@OUTPUT     : 
@RETURNS    : 
@DESCRIPTION: Sames as output_modified_volume, above, but the volume is not
              a modification of an existing MINC file.
@METHOD     : 
@GLOBALS    : 
@CALLS      : 
@CREATED    : 1993            David MacDonald
@MODIFIED   : 
---------------------------------------------------------------------------- */

VIOAPI  Status  output_volume(
    STRING                filename,
    nc_type               file_nc_data_type,
    BOOLEAN               file_signed_flag,
    Real                  file_voxel_min,
    Real                  file_voxel_max,
    Volume                volume,
    STRING                history,
    minc_output_options   *options )
{
    return( output_modified_volume( filename, file_nc_data_type,
                                    file_signed_flag,
                                    file_voxel_min, file_voxel_max,
                                    volume, NULL, history, options ) );
}


syntax highlighted by Code2HTML, v. 0.9.1