#include <string.h>
#include <stdlib.h>
#include <stdio.h>

/*typedef enum __ProgramType_ {
  __ProgramType_Int = 1,
  __ProgramType_Float = 2,
  __ProgramType_String = 3,
  __ProgramType_Boolean = 4,
  } __ProgramType_; */

typedef struct __TableReturn_ {
  __ProgramType_ returnType;
  char * _str;
  int _int;
  double _float;
  void * _ptr;
  int _boolean;
} __TableReturn_;

typedef __TableReturn_ (*__TableColumnFunc_)();
typedef void * (*__TableColumnGetItemFunc_)();

typedef struct __TableColumn_ {
  char * name;
  __ProgramType_ returnType;
  __TableColumnFunc_ func;
} __TableColumn_ ;

typedef struct __Table_ {
  char * name;
  int columnCount;
  __TableColumn_ * columns;
  __TableColumnGetItemFunc_ getItem;
  int objectType;
  int objectArrayCount;
  void * objectArray;
} __Table_;

#define TABLE_START( name ) __TableColumn_ _TableColumnList_##name##_[] = {
#define TABLE_COLUMN( name, type, func ) { name, type, func },
#define TABLE_END(name) };

#define TABLE_COLUMNS(name) _TableColumnList_##name##_
#define TABLE_GETITEM(name) _##name##_getItem_

static char * newString( char * name )
{
  char * new;
  int k, n;

  if( name == NULL )
    return NULL;

  k = strlen( name );
  n = k + 1;
  new = (char *) malloc(n);
  strncpy( new, name, n );
  new[n] = '\0';
  
  return new;
}

static void * ObjectNew( __ProgramType_ type )
{
  __ProgramTypeInfo_ * info;
  int listSize;
  void * mem;

  listSize = sizeof(__programTypeList_)/sizeof(__ProgramTypeInfo_);
  if( type < 1 || type >= listSize )
    {
    printf("Error: Invalid type for Object Creation\n");
    return NULL;
    }

  info = &__programTypeList_[type];
  if( info == NULL )
    {    
    printf("Error: Invalid type for Object Creation\n");
    return NULL;
    }

  mem = malloc( info->size );
  memset( mem, 0, info->size );

  return mem;
}

static void * ArrayNew( __ProgramType_ type, int size )
{
  __ProgramTypeInfo_ * info;
  int listSize, n;
  void * mem;

  listSize = sizeof(__programTypeList_)/sizeof(__ProgramTypeInfo_);
  if( type < 1 || type >= listSize )
    {
    printf("Error: Invalid type for Object Creation\n");
    return NULL;
    }

  info = &__programTypeList_[type];
  if( info == NULL )
    {    
    printf("Error: Invalid type for Object Creation\n");
    return NULL;
    }

  n = info->size * size; /* Total Bytes needed for the array */
  mem = malloc( n );
  memset( mem, 0, n );

  return mem;
}

static void freeString( char * name )
{
  if( name == NULL )
    return;

  free( name );
}

static __Table_ * __TableNew( char * name,
  __TableColumnGetItemFunc_ getItemFunc,
  __TableColumn_ * columnList, int columnCount, 
  int objectType, int objectArrayCount, 
  void * objectArray )
{
  __Table_ * table;

  table = (__Table_ *) malloc( sizeof(__Table_) );
  memset( table, 0, sizeof(__Table_) );

  table->name = newString(name);
  table->getItem = getItemFunc;
  table->columns = columnList;
  table->columnCount = columnCount;
  table->objectType = objectType;
  table->objectArrayCount = objectArrayCount;
  table->objectArray = objectArray;
  return table;
}

static __TableFree( __Table_ * table )
{
  free( table );
}

static void __TablePrint( __Table_ * table )
{
  int i, j, m, n;

  /* Init */
  m = table->columnCount;
  n = table->objectArrayCount;

  /* Print Header */
  for( i=0; i < m; i++ )
    {
    __TableColumn_ * col;

    col = &table->columns[i];
    printf( "%15s", col->name );
    }
  printf("\n");

  for( i=0; i < n; i++ )
    { 
    for( j=0; j < m; j++ )
      {
      __TableColumn_ * col;
      __TableReturn_ ret;

      col = &table->columns[j];
      ret = col->func( table->getItem(table->objectArray,i) );
      //      switch( ret.returnType )
      switch( col->returnType )
         {
        case __ProgramType_Int:
          printf( "%14d", ret._int );
          break;
        case __ProgramType_Float:
          printf( "%14f", ret._float );
          break;
        case __ProgramType_String:
          printf( "%14s", ret._str );
          break;
        case __ProgramType_Boolean:
          printf( "%14d", ret._boolean );
          break;
        }
      
      printf(",");
      }
    printf("\n");
    }
} 





