/*----------------------------------------------------------------------------
** Name: typetbl.cpp
**
** Title: Type Table
**
** Purpose:
**  Create and manage all simple and complex data types
**
**--------------------------------------------------------------------------*/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/

#ifndef _INDEXTBL_
#include "indextbl.h"
#endif
#ifndef __MEM_H
#include <mem.h>
#endif
#ifndef _MEMMANAG_
#include "memmanag.h"
#endif
#ifndef _MEMPOOL_
#include "mempool.h"
#endif
#ifndef _SYMBLSVR_
#include "symblsvr.h"
#endif
#ifndef _SYMMGR_
#include "symmgr.h"
#endif
#ifndef _SYMUTIL_
#include "symutil.h"
#endif
#ifndef _TYPES_
#include "types.h"
#endif
#ifndef _TYPETBL_
#include "typetbl.h"
#endif

                       /****************************
                        *                          *
                        *        DEFINITIONS       *
                        *                          *
                        ****************************/


#define TYPETABLE_EXPANSION_SIZE 0x2000L
#define TYPETABLE_INIT_SIZE      0x2000L
#define MAX_TYPE_SIZE 0x10000L

IndexTable typit;
extern MemPool st;
TypeTable tt;  // type table instantiation;

                       /****************************
                        *                          *
                        *     EXECUTABLE CODE      *
                        *                          *
                        ****************************/

//member functions for type table

// constructor ;
TypeTable::TypeTable():Table() {

   availMemOffset = 0L;
   bytesThrownAway = 0;  // initialize member vars;

   initialSize = TYPETABLE_INIT_SIZE;
   expandSize  = TYPETABLE_EXPANSION_SIZE;
   maxTypeIndex = MAX_BUILT_IN;
}


RETCODE TypeTable::AllocBytes(U16 size, TABLE_OFFSET& tableDataOffset) {
   RETCODE retCode;
   U32  memoryLeft;
   U32  copyLength = 0;
   TABLE_OFFSET beginOffset;
   HPU8 srcPtr, destPtr;

   tableDataOffset = 0;    // set to null in case of a memory failure
   if ((memoryLeft = (tableSize-availMemOffset)) < (U32)size) {

      // not enough space or empty table; must get more ;
      if ((retCode = InitOrExtendTable(0)) != GOOD)
         return retCode;
      // a non-zero retcode means no memory was found; otherwise fall thru

      else {   
         // found more memory ;

         // initialize the first valid offset >= 4.  this will allow ;
         // uninitialized type headers to be placed at offset 1-3 ;
         // (0 is a bad number because typit.GetOffset believes a type ;
         // with a value of 0 doesn't exist) ;
         if (!availMemOffset) {
            destPtr = GetHugeDataPtr(availMemOffset);
            *(U32 *)destPtr = 0L;
            availMemOffset = 4L;
         }

         // jump over any unused bytes to preserve 64K boundary ;
         // move pointer past boundary of old partition ;
         // then copy the header to availmemoffset down to new boundary ;

         if((retCode = typit.GetOffset(typeIndex,beginOffset)) !=GOOD)
            return(retCode);
         // if the beginning offset < 4 it hasn't been initialized to ;
         // a real value ;
         if (beginOffset < 4) beginOffset = availMemOffset;
         if( (availMemOffset - beginOffset + size) >= MAX_TYPE_SIZE)
            return(ER_TYPE_TOO_LARGE);
         if (( (availMemOffset + size) & 0xffffL) !=
               ((availMemOffset & 0xffffL) + size)) {
            // the new data being put in will cross a 64k boundary ;
            // copy the previously inserted data to the new 64k boundary ;
            copyLength = availMemOffset - beginOffset;
            srcPtr = GetHugeDataPtr(beginOffset);
            destPtr = GetHugeDataPtr(availMemOffset + memoryLeft);
            // the copy can't be >64k because we wouldn't have gotten to ;
            // this code ;
            memcpy(destPtr,srcPtr,(U16)copyLength);
         
            // update type index tables pointer to the type_header ;
            if ((retCode = typit.UpdateOffset(typeIndex,
               availMemOffset + memoryLeft)) != GOOD) 
               return(retCode);
            // only if new 64K region (not 8K region)
            availMemOffset += memoryLeft + copyLength;
            bytesThrownAway += (U16)memoryLeft;
         }
      }
   }  // end of if that checked for enough memory or retrieved more memory ;

   // set the return pointer to the head of the data ;
   tableDataOffset = availMemOffset;

   // bump pointer to available memory by size of data ;
   availMemOffset += size;

   return(GOOD);
}

RETCODE TypeTable::IncrementMemberCount(VOID) {
   RETCODE err;
   TYPE_HEADER_TYPE2 *typeHeader;
   TABLE_OFFSET typeOffset;
   
   if((err = typit.GetOffset(typeIndex, typeOffset)) != GOOD) return(err);
   
   typeHeader = (TYPE_HEADER_TYPE2 *)tt.GetHugeDataPtr(typeOffset);
   typeHeader->memberCount++;
   
   return(GOOD);
}

RETCODE TypeTable::InitBasicTypes(VOID) {
   RETCODE err;
   LOOP_VAR i;
   TYPE_HEADER_TYPE2 typeHeader;

   // initialize all of the basic types ;
   typeHeader.typeChoice = SIMPLE_TYPE_CLASS;
   // basic types have no members added, therefore set member count to 1
   typeHeader.memberCount = 1;
   // All built-in types have precalculated size of MAU
   typeHeader.sizeCalculated = TRUE;
                    
   for(i = 0; i<BASIC_TYPE_COUNT; i++) {
      // if the name of the basic type is NULL then this is not a valid entry;
      if( lstrlen((LPSTR)basicTypeName[i]) ) {

         // put the type name into the symbol table ;
         if((err = st.PutString((LPSTR)basicTypeName[i],typeHeader.typeName))
            != GOOD) return(err);
         typeHeader.t.simpleType = i;
         typeHeader.sizeInMAUs = basicTypeSize[i];
         typeHeader.recordSize = sizeof(TYPE_HEADER_TYPE2);

         // put the type information into the type table ;
         if((err = tt.PutHeader((U8 *)&typeHeader,sizeof(TYPE_HEADER_TYPE2),
            i )) != GOOD) return(err);
      }
   }
   return GOOD;
}

VOID TypeTable::ObliterateTable(VOID) {
   Table::ObliterateTable();
   availMemOffset = 0L;
   bytesThrownAway = 0;  // initialize member vars

   initialSize = TYPETABLE_INIT_SIZE;
   expandSize  = TYPETABLE_EXPANSION_SIZE;
   maxTypeIndex = MAX_BUILT_IN;
}

RETCODE TypeTable::PutBytes(U8 *inputDataPtr, U16 size, 
                            TABLE_OFFSET &offset) {
   RETCODE retCode;
   HPU8 tempHugePtr;
   TABLE_OFFSET tableDataOffset;

   retCode = AllocBytes(size, tableDataOffset);
   if (retCode != GOOD) return(retCode);  // return if some error ;

   // tableDataOffset points to head of allocated memory;
   // calculate pointer to this data;
   tempHugePtr = hpTableObject + tableDataOffset;

   // store the data
   for (; size; size--) {
      *tempHugePtr++ = *inputDataPtr++;
   }
   offset = tableDataOffset;
   return(GOOD);
}

RETCODE TypeTable::PutHeader(U8 *inputDataPtr, U16 size, TYPE_INDEX index) {
   RETCODE err;
   TABLE_OFFSET typeOffset = 1L;
   
   typeIndex = index;
   maxTypeIndex = max(typeIndex,maxTypeIndex);
   // put the offset to the type into the type index table ;
   if((err = typit.AddIndex(index,typeOffset)) != GOOD) 
      return(err);
   if ((err = PutBytes(inputDataPtr, size, typeOffset)) != GOOD) return(err);
   if ((err = typit.UpdateOffset(index,typeOffset)) != GOOD) return(err);
   return(GOOD);
}

RETCODE TypeTable::UpdateMAUSize(TYPE_INDEX prevIndex) {
   RETCODE err;
   TYPE_HEADER_TYPE2 *prevPtr, *currPtr;
   TABLE_OFFSET prevOffset, currOffset;

   // whatever type was just added will point back to some previously ;
   // defined type.  use the previously defined types MAU size and ;
   // add it to the MAU size of the type just added to the type table. ;
   if ((err = typit.GetOffset(prevIndex,prevOffset)) != GOOD) return(err);
   prevPtr = (TYPE_HEADER_TYPE2 *)tt.GetHugeDataPtr(prevOffset);

   // add the previous type MAU size to the current types MAU size ;
   if ((err = typit.GetOffset(typeIndex,currOffset)) != GOOD) return(err);
   currPtr = (TYPE_HEADER_TYPE2 *)tt.GetHugeDataPtr(prevOffset);
   currPtr->sizeInMAUs += prevPtr->sizeInMAUs;
   return(GOOD);
}

RETCODE TypeTable::UpdateRecordSize(U16 setValue) {
   RETCODE err;
   TYPE_HEADER_TYPE2 *typePtr;
   TABLE_OFFSET typeOffset;

   if ((err = typit.GetOffset(typeIndex,typeOffset)) != GOOD) return(err);
   typePtr = (TYPE_HEADER_TYPE2 *)tt.GetHugeDataPtr(typeOffset);
   typePtr->recordSize += setValue;
   return(GOOD);
}

/******************************** E O F *************************************/
