/**
 * \file label.c
 * \brief MINC 2.0 Label functions
 * \author Bert Vincent
 *
 * This small set of three functions are intended to allow for the
 * definition of labeled, or enumerated, volumes.
 * 
 * Labeled volumes must have been created with the class MI_CLASS_LABEL,
 * and with any integer subtype.
 *
 ************************************************************************/

#include <stdlib.h>
#include <hdf5.h>
#include "minc2.h"
#include "minc2_private.h"

#define MI_LABEL_MAX 128

int miswap2(unsigned short tmp)
{
    unsigned char *x = (unsigned char *) &tmp;
    unsigned char t = x[0];
    x[0] = x[1];
    x[1] = t;
    return (tmp);
}

int miswap4(unsigned int tmp)
{
    unsigned char *x = (unsigned char *) &tmp;
    unsigned char t = x[0];
    x[0] = x[3];
    x[3] = t;
    t = x[1];
    x[1] = x[2];
    x[2] = t;
    return (tmp);
}

/**
This function associates a label name with an integer value for the given
volume. Functions which read and write voxel values will read/write 
in integer values, and must call miget_label_name() to discover the 
descriptive text string which corresponds to the integer value.
*/
int 
midefine_label(mihandle_t volume, int value, const char *name)
{
    int result;

    if (volume == NULL || name == NULL) {
        return (MI_ERROR);
    }

    if (strlen(name) > MI_LABEL_MAX) {
        return (MI_ERROR);
    }

    if (volume->volume_class != MI_CLASS_LABEL) {
	return (MI_ERROR);
    }

    if (volume->ftype_id <= 0 || volume->mtype_id <= 0) {
	return (MI_ERROR);
    }

    result = H5Tenum_insert(volume->mtype_id, name, &value);
    if (result < 0) {
	return (MI_ERROR);
    }

    /* We might have to swap these values before adding them to
     * the file type.
     */
    if (H5Tget_order(volume->ftype_id) != H5Tget_order(volume->mtype_id)) {
        switch (H5Tget_size(volume->ftype_id)) {
        case 2:
            value = miswap2((unsigned short) value);
            break;
        case 4:
            value = miswap4((unsigned int) value);
            break;
        }
    }
    result = H5Tenum_insert(volume->ftype_id, name, &value);
    if (result < 0) {
	return (MI_ERROR);
    }

    return (MI_NOERROR);
}

/**
For a labelled volume, this function retrieves the text name
associated with a given integer value.

The name pointer returned must be freed by calling mifree_name().
*/
int
miget_label_name(mihandle_t volume, int value, char **name)
{
    int result;

    if (volume == NULL || name == NULL) {
        return (MI_ERROR);
    }

    if (volume->volume_class != MI_CLASS_LABEL) {
        return (MI_ERROR);
    }
    if (volume->mtype_id <= 0) {
        return (MI_ERROR);
    }
    *name = malloc(MI_LABEL_MAX);
    if (*name == NULL) {
        return (MI_ERROR);
    }

    H5E_BEGIN_TRY {
        result = H5Tenum_nameof(volume->mtype_id, &value, *name, MI_LABEL_MAX);
    } H5E_END_TRY;

    if (result < 0) {
	return (MI_ERROR);
    }
    return (MI_NOERROR);
}

/**
This function is the inverse of miget_label_name(). It is called to determine
what integer value, if any, corresponds to the given text string.
*/
int
miget_label_value(mihandle_t volume, const char *name, int *value_ptr)
{
    int result;

    if (volume == NULL || name == NULL || value_ptr == NULL) {
        return (MI_ERROR);
    }

    if (volume->volume_class != MI_CLASS_LABEL) {
        return (MI_ERROR);
    }

    if (volume->mtype_id <= 0) {
        return (MI_ERROR);
    }

    H5E_BEGIN_TRY {
        result = H5Tenum_valueof(volume->mtype_id, name, value_ptr);
    } H5E_END_TRY;

    if (result < 0) {
	return (MI_ERROR);
    }
    return (MI_NOERROR);
}

/**
This function returns the number of defined labels, if any, or zero.
*/
int
miget_number_of_defined_labels(mihandle_t volume, int *number_of_labels)
{
  int result;
 
  if (volume == NULL) {
    return (MI_ERROR);
  }
  if (volume->volume_class != MI_CLASS_LABEL) {
    return (MI_ERROR);
  }

  if (volume->mtype_id <= 0) {
    return (MI_ERROR);
  }

  H5E_BEGIN_TRY {
    result = H5Tget_nmembers(volume->mtype_id);
  } H5E_END_TRY;

  if (result < 0) {
    return (MI_ERROR);
  }
  else {
    *number_of_labels = result;
  }
    
  return (MI_NOERROR);
}


syntax highlighted by Code2HTML, v. 0.9.1