/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * Copyright by the Board of Trustees of the University of Illinois.         *
  * All rights reserved.                                                      *
  *                                                                           *
  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
  * terms governing use, modification, and redistribution, is contained in    *
  * the files COPYING and Copyright.html.  COPYING can be found at the root   *
  * of the source code distribution tree; Copyright.html can be found at the  *
  * root level of an installed copy of the electronic HDF5 document set and   *
  * is linked from the top-level documents page.  It can also be found at     *
  * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html.  If you do not have     *
  * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <string>

#include "H5Include.h"
#include "H5RefCounter.h"
#include "H5Exception.h"
#include "H5IdComponent.h"
#include "H5PropList.h"
#include "H5Object.h"
#include "H5Alltypes.h"
#include "H5AbstractDs.h"
#include "H5DxferProp.h"
#include "H5DataSpace.h"
#include "H5DataSet.h"
#include "H5private.h"

#ifndef H5_NO_NAMESPACE
namespace H5 {
#endif

// Creates a new compound datatype
CompType::CompType( size_t size ) : DataType( H5T_COMPOUND, size ) {}

// Creates a compound datatype using an existing id
CompType::CompType( const hid_t existing_id ) : DataType( existing_id ) {}

// Default constructor
CompType::CompType() : DataType() {}

// Copy constructor: makes copy of the original CompType object
CompType::CompType( const CompType& original ) : DataType( original ) {}

// Gets the compound datatype of the specified dataset - reimplement this
CompType::CompType( const DataSet& dataset ) : DataType()
{
   // Calls C function H5Dget_type to get the id of the datatype
   id = H5Dget_type( dataset.getId() );

   // If the datatype id is invalid, throw exception
   if( id <= 0 )
   {
      throw DataSetIException("CompType constructor", "H5Dget_type failed");
   }
}

// Retrieves the number of members in this compound datatype. 
int CompType::getNmembers() const
{
   int num_members = H5Tget_nmembers( id );
   if( num_members < 0 )
   {
      throw DataTypeIException("CompType::getNmembers", 
		"H5Tget_nmembers returns negative number of members");
   }
   return( num_members );
}

// Retrieves the name of a member of this compound datatype. 
string CompType::getMemberName( int member_num ) const
{
    char* member_name_C = H5Tget_member_name( id, member_num );
    if( member_name_C == NULL )  // NULL means failure
    {
	throw DataTypeIException("CompType::getMemberName", 
		"H5Tget_member_name returns NULL for member name");
    }
    string member_name = string(member_name_C); // convert C string to string 
    HDfree(member_name_C); // free the C string 
    return( member_name ); // return the member name string
}

/*-------------------------------------------------------------------------
 * Function:    getMemberIndex
 *
 * Purpose:     Returns the index of a member in a compound data type.  
 *              Members are stored in no particular order with numbers 0 
 *              through N-1, where N is the value returned by the member 
 *              function getNmembers.
 *
 * Return:      Success:	index of the member if exists.
 *              Failure:	DataTypeIException
 *
 * BMR - May 16, 2002
 *-------------------------------------------------------------------------
 */
int CompType::getMemberIndex(const char* name) const
{
   int member_index = H5Tget_member_index(id, name);
   if( member_index < 0 )
   {
      throw DataTypeIException("CompType::getMemberIndex", 
		"H5Tget_member_index returns negative value");
   }
   return( member_index );
}
int CompType::getMemberIndex(const string& name) const
{
   return(getMemberIndex(name.c_str()));
}

/*-------------------------------------------------------------------------
 * Function:    getMemberOffset
 *
 * Purpose:     Returns the byte offset of the beginning of a member with
 *              respect to the beginning of the compound data type datum.
 *              Members are stored in no particular order with numbers 0 
 *              through N-1, where N is the value returned by the member 
 *              function getNmembers.
 *
 * Return:      Success:        Byte offset.
 *              Failure:        Quincey: for now, 0 is not a failure
 *
 * BMR - 2000
 *-------------------------------------------------------------------------
 */
size_t CompType::getMemberOffset( int member_num ) const
{
   size_t offset = H5Tget_member_offset( id, member_num );
   //if( offset == 0 )
   //{
      //throw DataTypeIException("CompType::getMemberOffset",
		//"H5Tget_member_offset failed");
   //}
   return( offset );
}

// Returns the dimensionality of the member. 
int CompType::getMemberDims( int member_num, size_t* dims, int* perm ) const
{
   throw DataTypeIException( "Error: getMemberDims is no longer supported." );
   return (-1); // unreachable statement; but without it, the compiler 
		// will complain
}

// Gets the type class of the specified member.
H5T_class_t CompType::getMemberClass( int member_num ) const
{
   // get the member datatype first
   hid_t member_type_id = H5Tget_member_type( id, member_num );
   if( member_type_id <= 0 )
   {
      throw DataTypeIException("CompType::getMemberClass", 
		"H5Tget_member_type failed");
   }

   // then get its class
   H5T_class_t member_class = H5Tget_class( member_type_id );
   if( member_class == H5T_NO_CLASS )
   {
      throw DataTypeIException("CompType::getMemberClass", 
		"H5Tget_class returns H5T_NO_CLASS");
   }
   return( member_class );
}

// This private member function calls the C API to get the identifier 
// of the specified member.  It provides the id to construct appropriate
// sub-types in the functions getMemberXxxType below, where Xxx indicates
// the sub-types.
hid_t CompType::p_getMemberType( int member_num ) const
{
   // get the id of the specified member first
   hid_t member_type_id = H5Tget_member_type( id, member_num );
   if( member_type_id > 0 )
      return( member_type_id );
   else
   {
	// p_getMemberType is private, use caller's function name for api
      throw DataTypeIException("CompType::getMemberDataType", 
		"H5Tget_member_type failed");
   }
}

// Returns the datatype of the specified member in this compound datatype. 
DataType CompType::getMemberDataType( int member_num ) const
{
   DataType datatype( p_getMemberType( member_num )); 
   return( datatype );
}

EnumType CompType::getMemberEnumType( int member_num ) const
{
   EnumType enumtype( p_getMemberType( member_num )); 
   return( enumtype );
}

CompType CompType::getMemberCompType( int member_num ) const
{
   CompType comptype( p_getMemberType( member_num )); 
   return( comptype );
}

IntType CompType::getMemberIntType( int member_num ) const
{
   IntType inttype( p_getMemberType( member_num )); 
   return( inttype );
}

FloatType CompType::getMemberFloatType( int member_num ) const
{
   FloatType floatype( p_getMemberType( member_num )); 
   return( floatype );
}

StrType CompType::getMemberStrType( int member_num ) const
{
   StrType strtype( p_getMemberType( member_num )); 
   return( strtype );
}

/* old style of getMemberType - using overloads; new style above 
   returns the appropriate datatypes but has different named functions.
   In the old style, a datatype must be passed into the function.
// Returns the datatype of the specified member in this compound datatype. 
// Several overloading of getMemberType are for different datatypes
void CompType::getMemberType( int member_num, EnumType& enumtype ) const
{
   p_getMemberType( member_num, enumtype ); 
}

void CompType::getMemberType( int member_num, CompType& comptype ) const
{
   p_getMemberType( member_num, comptype ); 
}

void CompType::getMemberType( int member_num, IntType& inttype ) const
{
   p_getMemberType( member_num, inttype ); 
}

void CompType::getMemberType( int member_num, FloatType& floatype ) const
{
   p_getMemberType( member_num, floatype ); 
}

void CompType::getMemberType( int member_num, StrType& strtype ) const
{
   p_getMemberType( member_num, strtype ); 
}
// end of overloading of getMemberType
*/

// Adds a new member to a compound datatype
void CompType::insertMember( const string& name, size_t offset, const DataType& new_member ) const
{
   // Convert string to C-string
   const char* name_C;
   name_C = name.c_str();  // name_C refers to the contents of name as a C-str

   hid_t new_member_id = new_member.getId();  // get new_member id for C API

   // Call C routine H5Tinsert to add the new member
   herr_t ret_value = H5Tinsert( id, name_C, offset, new_member_id );
   if( ret_value < 0 )
   {
      throw DataTypeIException("CompType::insertMember", "H5Tinsert failed");
   }
}

// Recursively removes padding from within a compound datatype. 
void CompType::pack() const
{
   // Calls C routine H5Tpack to remove padding
   herr_t ret_value = H5Tpack( id );
   if( ret_value < 0 )
   {
      throw DataTypeIException("CompType::pack", "H5Tpack failed");
   }
}

// This destructor just invokes the base-class' destructor
CompType::~CompType() {}

#ifndef H5_NO_NAMESPACE
} // end namespace
#endif
