/*
 *  Copyright 2009 OpenSourceResearchInstitute.org
 *  Licensed under GNU General Public License version 2
 *
 *  Based on code posted to a discussion group on the web.  (Forgot to mark
 *   down where got it from)
 *
 * Author: seanhalle@yahoo.com
 *
 * Created on November 14, 2009, 9:00 PM
 */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "Param.h"

void         freeParamStruc( ParamStruc * param );
void         freeParamBagHashEntry( ParamBagHashEntry *entry );
ParamBagHashEntry *  lookupKeyInHash( char *key, ParamBag * bag );
unsigned int hashThisKey( char *s, int hashSz );
void         nullOutParamBagHashEntries( ParamBag *bag );

//TODO: Bug -- need internal, App/WL, and external versions
 ParamBag *
makeParamBag()
 { ParamBag * retBag;
   retBag = malloc( sizeof( ParamBag ) );
   retBag->entries = malloc( PARAM_BAG_HASHSIZE * sizeof( ParamBagHashEntry *) );
   retBag->bagSz = PARAM_BAG_HASHSIZE;
   nullOutParamBagHashEntries( retBag );
   
   return retBag;
 }

 void
nullOutParamBagHashEntries( ParamBag *bag )
 { int i, bagSz;
   bagSz = bag->bagSz;
   ParamBagHashEntry ** entries = bag->entries;
   for( i = 0; i < bagSz; i++ )
      entries[ i ] = NULL;
 }

 unsigned int
hashKey( char *s, int hashSz )
 { unsigned int h = 0;
   
   for( ; *s != 0; s++ )
      h = *s + h*31;
   return h % hashSz;
 }

/*Need this to be separated out, for use in both getParam and putParam
 */
 ParamBagHashEntry *
lookupKeyInHash( char *key, ParamBag * bag )
 {  unsigned int
   hashIndex = hashKey( key, bag->bagSz );
    ParamBagHashEntry*
   hashEntry = bag->entries[ hashIndex ];
   for( ; hashEntry != NULL; hashEntry = hashEntry->next )
    { if( strcmp( hashEntry->key, key ) == 0 )  return hashEntry;
    }
   return NULL;
 }

 ParamStruc *
getParamFromBag( char *key, ParamBag * bag )
 { ParamBagHashEntry *entry;
   entry = lookupKeyInHash( key, bag );
   if( entry == NULL ) return NULL;
   
   return entry->param;
 }

 int
addParamToBag( char* key, ParamStruc *param, ParamBag *bag )
 { unsigned int hashIdx;
   ParamBagHashEntry* hashEntry;
   hashEntry = lookupKeyInHash( key, bag );
   if( hashEntry == NULL )
    { hashIdx = hashKey( key, bag->bagSz );
      hashEntry = (ParamBagHashEntry*) malloc( sizeof( ParamBagHashEntry ) );
            if( hashEntry == NULL )  return 0;
      hashEntry->key = strdup( key );
            if( hashEntry->key == NULL ) return 0;
      hashEntry->next = (bag->entries)[hashIdx];
      (bag->entries)[hashIdx] = hashEntry;
    }
   else
    { freeParamStruc( hashEntry->param );
    }
   hashEntry->param = param;
   return 1;
 }

 
 void
freeParamBag( ParamBag *bag )
 { int i;
   ParamBagHashEntry *hashEntry, *temp, **entries;

   entries = bag->entries;
   for( i=0; i < bag->bagSz; i++ )
    { if( entries[i] != NULL )
       { hashEntry = entries[i];
         while( hashEntry != NULL )
          {
            temp = hashEntry->next;
            freeParamBagHashEntry( hashEntry );
            hashEntry = temp;
          }
       }
    }
 }

 void
freeParamBagHashEntry( ParamBagHashEntry *entry )
 {
   freeParamStruc( entry->param );
   free( entry->key ); //was malloc'd above, so free it
   free( entry );
 }

 void
freeParamStruc( ParamStruc * param )
 { if( param->type == STRING_PARAM_TYPE ) free( param->strValue );
   free( param );
 }

 ParamStruc *
makeParamStruc()
 { ParamStruc *retStruc;
   retStruc = malloc( sizeof( ParamStruc ) );
   retStruc->floatValue = 0.0;
   retStruc->intValue   = 0;
   retStruc->strValue   = NULL;

   return retStruc;
 }

void
removeEndWhtSpaceFromStr( char *str )
 { int n;

   n = strlen ( str );
   while( --n >= 0 )
    {
      if(str[n] != ' ' && str[n] != '\t' && str[n] != '\n' && str[n] != '\r')
         break;
    }
   str[n + 1] = '\0';
 }


ParamStruc *
makeParamFromStrs( char * type, char *value )
 { ParamStruc *retParam;
   retParam = makeParamStruc();
   switch(*type)
    { case 'i':
       { retParam->type = INT_PARAM_TYPE;
         retParam->intValue = atoi( value );
       } break;
      case 's':
       { retParam->type = STRING_PARAM_TYPE;
         retParam->strValue = malloc( strlen(value) + 1);
         strcpy( retParam->strValue, value );
         removeEndWhtSpaceFromStr( retParam->strValue );
       } break;
      case 'f':
       { retParam->type = FLOAT_PARAM_TYPE;
         retParam->floatValue = atof( value );
       } break;
    }
   return retParam;
 }


/* A pretty useless but good debugging function,
   which simply displays the hashtable in (key.value) pairs
*/
/*void paramBagToString( ParamBag * bag )
 { int i;
   ParamBagHashEntry *t;
   for( i = 0; i < bag->bagSz; i++ )
    { t = entries[i];
      if( t == NULL )
         strcat_m( retStr, &"()" );
      else
       { strcat_m( retStr, &"(" );
         for( ; t != NULL; t = t->next )
          { strcat_m( retStr, &" " );
            strcat_m( retStr, t->key );
            strcat_m( retStr, &"." );
            strcat_m( retStr, paramToString( t->param ) );
            strcat_m( retStr, &" " );
          }
         strcat_m( retStr, &")" );
       }
    }
 }
*/
