//**************************************************************************
#include "dataserver.h"
//**************************************************************************
int packStruct(KeyTable *T, unsigned char **dataptr, int *totsize)
{
static KeyInfo d;
*totsize = sizeof(T->n) + T->n*(sizeof(d.id) + sizeof(d.key) + sizeof(d.description) + sizeof(d.type) + sizeof(d.elem_size) + sizeof(d.num_elems) + sizeof(d.vartype) + sizeof(d.is_locked) + sizeof(d.value) + sizeof(d.perm));
unsigned char *data;
ALLOC1D(&data, *totsize);
*dataptr = data;
int ptr = 0;

PACK_VARIABLE(T->n, data, &ptr);

for (int i = 0; i < T->n; i++)
        {
         PACK_VARIABLE(T->key[i].id, data, &ptr);
         PACK_VARIABLE(T->key[i].elem_size, data, &ptr);
         PACK_VARIABLE(T->key[i].num_elems, data, &ptr);
         PACK_VARIABLE(T->key[i].vartype, data, &ptr);
         PACK_VARIABLE(T->key[i].is_locked, data, &ptr);
         PACK_VARIABLE(T->key[i].perm, data, &ptr);
         PACK_VARIABLE(T->key[i].description, data, &ptr);
         PACK_1D_ARRAY(T->key[i].key, data, &ptr);
         PACK_1D_ARRAY(T->key[i].type, data, &ptr);
         PACK_1D_ARRAY(T->key[i].value, data, &ptr);
        }

return ptr;
}
//**************************************************************************
int unpackStruct(KeyTable *T, unsigned char *data, int size)
{
int ptr = 0;

UNPACK_VARIABLE(&(T->n), data, &ptr);

if (T->key.size())
        {
         T->key.clear();
        }

for (int i = 0; i < T->n; i++)
        {
         T->Add();
         UNPACK_VARIABLE(&(T->key[i].id), data, &ptr);
         UNPACK_VARIABLE(&(T->key[i].elem_size), data, &ptr);
         UNPACK_VARIABLE(&(T->key[i].num_elems), data, &ptr);
         UNPACK_VARIABLE(&(T->key[i].vartype), data, &ptr);
         UNPACK_VARIABLE(&(T->key[i].is_locked), data, &ptr);
         UNPACK_VARIABLE(&(T->key[i].perm), data, &ptr);
         UNPACK_VARIABLE(&(T->key[i].description), data, &ptr);
         UNPACK_1D_ARRAY(T->key[i].key, data, &ptr);
         UNPACK_1D_ARRAY(T->key[i].type, data, &ptr);
         UNPACK_1D_ARRAY(T->key[i].value, data, &ptr);
        }

return ptr;
}
//**************************************************************************
KeyTable::KeyTable()
{
n = 0;
}
//**************************************************************************
KeyTable::~KeyTable()
{
for (int i = 0; i < key.size(); i++)
        delete key[i].sem;

key.clear();
}
//**************************************************************************
int KeyTable::Add()
{
static KeyInfo dummy;
dummy.ptr = NULL;
dummy.callback = NULL;
key.push_back(dummy);

return key.size();
}
//**************************************************************************
int KeyTable::getKeyHandle(char *keyword)
{
int i;
for (i = 0; i < key.size(); i++)
        {
         if (strcmp(key[i].key, keyword) == 0)
                break;
        }
return i;
}
//**************************************************************************
bool KeyTable::isVar(int i)
{
return (key[i].description == VARIABLE);
}
//**************************************************************************
bool KeyTable::isVar(char *keyword)
{
int i = getKeyHandle(keyword);
if (i < n)
        return isVar(i);
return false;
}
//**************************************************************************
bool KeyTable::isCharArray(int i)
{
return (key[i].description == STATIC_1D_ARRAY && key[i].vartype == CHAR);
}
//**************************************************************************
bool KeyTable::isCharArray(char *keyword)
{
int i = getKeyHandle(keyword);
if (i < n)
        return isCharArray(i);

return false;
}
//**************************************************************************
bool KeyTable::isValidKeyword(char *keyword)
{
return (getKeyHandle(keyword) < n);
}
//**************************************************************************
bool KeyTable::isViewableVar(int i)
{
return (isVar(i) || isCharArray(i));
}
//**************************************************************************
bool KeyTable::isViewableVar(char *keyword)
{
int i = getKeyHandle(keyword);
if (i < n)
        return isViewableVar(i);

return false;
}
//**************************************************************************
void KeyTable::List()
{
cout << "==============================================================================" << endl << "\r";
cout << "Keyword\t\tDescription\t\tType\tElem Size (bytes)  # elements" << endl << "\r";
cout << "==============================================================================" << endl << "\r";
for (int i = 0; i < key.size(); i++)
        {
         char desc[24];
         int keylen = strlen(key[i].key);
         cout << key[i].key;
         if (key[i].is_locked)
                {
                 cout << "*";
                 ++keylen;
                }
         cout << "\t";
         if (keylen <= 7) cout << "\t";

         if (strlen(Description(i)) > 23)
                {
                 strncpy(desc, Description(i), 23);
                 desc[23] = '\0';
                 cout << desc << " ";
                }
         else
                cout << Description(i) << "\t";
         if (strlen(Description(i)) <= 15) cout << "\t";

         cout << key[i].type << "\t";
         if (strlen(key[i].type) < 9) cout << "\t";

         cout << key[i].elem_size << "\t\t"
                << key[i].num_elems << endl << "\r";
        }
cout << "==============================================================================" << endl << "\r";
cout.flush();
}
//**************************************************************************
void KeyTable::ListValues()
{
int i;

cout << "==============================================================================" << endl << "\r";
int max = 0;
for (i = 0; i < n; i++)
        {
         if (!isViewableVar(i))
                continue;
         if (max < strlen(key[i].key))
                max = strlen(key[i].key);
        }

for (i = 0; i < n; i++)
        {
         if (!isViewableVar(i))
                continue;
         cout << key[i].key;
         for (int j = 0; j < max-strlen(key[i].key); j++)
                cout << " ";
         cout << " = " << key[i].value << endl << "\r" << flush;
        }
cout << "==============================================================================" << endl << "\r";
}
//**************************************************************************
bool KeyTable::isWritable(int i)
{
return (key[i].perm == KEY_READ_WRITE);
}
//**************************************************************************
bool KeyTable::isWritable(char *keyword)
{
int i = getKeyHandle(keyword);
if (i < n)
        return isWritable(i);

return false;
}
//**************************************************************************
bool KeyTable::isArray(int i)
{
return (strstr(Description(i), "Array") != NULL);
}
//**************************************************************************
bool KeyTable::isArray(char *keyword)
{
int i = getKeyHandle(keyword);
if (i < n)
        return isArray(i);

return false;
}
//**************************************************************************
bool KeyTable::isStaticArray(int i)
{
return (strstr(Description(i), "Static") != NULL);
}
//**************************************************************************
bool KeyTable::isStaticArray(char *keyword)
{
int i = getKeyHandle(keyword);
if (i < n)
        return isStaticArray(i);

return false;
}
//**************************************************************************
void KeyTable::RegisterCallback(char *keyword, void (*cb)(void*), void *data)
{
int i = getKeyHandle(keyword);
if (i == n)
        {
         cerr << "KeyTable::RegisterCallback: Error! Invalid keyword \"" << keyword << "\"!!" << endl << flush;
         return;
        }
if (!isWritable(i))
        {
         cerr << "KeyTable::RegisterCallback: Error! Keyword \"" << keyword << "\" points to read-only data!!" << endl << flush;
         return;
        }

key[i].callback = cb;
key[i].callbackdata = data;
}
//**************************************************************************
bool KeyTable::hasCallback(int i)
{
return (key[i].callback != NULL);
}
//**************************************************************************
bool KeyTable::hasCallback(char *keyword)
{
int i = getKeyHandle(keyword);
if (i < n)
        return hasCallback(i);

return false;
}
//**************************************************************************
void KeyTable::Callback(int i)
{
key[i].callback(key[i].callbackdata);
}
//**************************************************************************
void KeyTable::Callback(char *keyword)
{
int i = getKeyHandle(keyword);
if (i < n)
        Callback(i);
}
//**************************************************************************