/***************************************************************

This is a data accumulator for the CES system. I'd have used a 
 regular array, but I thought this would be more expandable
 should I make ANOTHER structure change later. 
Its still unknown if this will be the level that has the 
 concurency locks, cause I havn't even thought about
 how this will be threaded.
 
 One of the ideas here is to make this thing so that its internal 
   functionality can be completely overhauled without changing 
   the way that its called by other objects.

 This thing is supposed to store data, and provide for easy 
   manipulation of said data. This SHOULD be able to handle 
   binary data just fine.
   

Methods are sumarized as follows:
  long   GetSize( void );                how big is it?
  long   ReadN(  long position, char * buffer, long size ); read bytes
  long   SetN( long destStart, long destSize, char * src, long srcSize); insert/delete content. automatically resizes accumulator. 
 
  -- internal methods --
  int    ReSize( long newSize);              raw resize op.
  long   Insert( long position, long size);   position specific resize
  long   Remove( long position, long size);   position specific unresize

 Dont use tab characters in this code.
  Dont use tab characters in this code.
   Dont use tab characters in this code.
    Dont use tab characters in this code.
     Dont use tab characters in this code.
      Dont use tab characters in this code.
       Dont use tab characters in this code.
        Dont use tab characters in this code.
         Dont use tab characters in this code.
          thanks.
 
 Creation Dan, <Dec 28/2001>
 added resize. Dan <jan ??/2002>
 added insert and remove. Dan <feb 18/2002>
 added adjustsize. Dan <feb 19/2002>
 removed local class def. Dan <mar 5/2002>
 minor overhaul on size tracking. Dan, <mar 8/2002>
 major overhaul. removed several sizing classes in preference of 
    united content/resize method. remaining methods are private Dan. 
    attempted optimizations of insert / delete code <jul 5/2002>

***************************************************************/

#include <stdlib.h>
#include <string.h>
#include "cestypes.h" // MIN
#include "accumulator2.h" // class definition

#include <stdio.h>

//#include <always_exclude.h>

/*****************************************
*
* Initilize contents
*  By default the buffer has one byte
*
*****************************************/
Accumulator::Accumulator ( void ) {
  
  Contents    = (char *)malloc(1);
  ContentSize = 1;
  
}


/**********************************************
*
*  Return the Current size of the accumulator,
*   result in bytes.
*
**********************************************/

long Accumulator::GetSize( void ){
 
 return ContentSize;

}

/********************************************************************
*
* Read N bytes of the accumulator. The read 
*  and write methods exist to enable 
*  this code to be concurrent.
*  
*  In:
*    position:  The First character to start reading from (included)
*    buffer  :  The location of a buffer to store the result.
*    size    :  The number of characters to read.
*
*  Out:
*    The Number of characters actually read. (This may 
*     come up short if the buffers end was reached.)
*
* notes:
*
*   - should this be able to handle negitive sizes?
*
*******************************************************************/
long Accumulator::ReadN(  long position, char * buffer, long size ) {

  long safeSize = MIN(position + size, GetSize()) - position; 
  
  //safety check.
  if (( position > GetSize() )|( position < 0 )) { 
    return 0;
  }   
  
  // I dont want to limit this to strings, hence memcpy
  memcpy(buffer, Contents+position, safeSize);

  return safeSize;

}


/*************************************************************************
*
* Insert/delete content. automatically resizes accumulator.
*  
* In:
*   destStart: First position of the accumulators contents to replace.
*   destSize:  Number of accumulator "bytes" to be affected by "paste".
*   src:       Data to use for the contents of the "paste".
*   srcSize:   Size of src.
*
* Out:
*   The number of characters written, should match srcSize if there
*      were no problems
*
**************************************************************************/
long   Accumulator::SetN( long destStart, long destSize, char * src, long srcSize ) {

 long memDelta;

 //sanity check, its 1:30 am, I must not be sane...
 if ( !WITHIN(0, GetSize(), destStart) ) {
   return 0;
 }  

 if ((destSize < 0) | (srcSize < 0)) {
   return 0;
 }

 //sanity check, you can only replace content up to the end
 //  of the buffer, but not past it

 destSize = MIN(GetSize()-destStart, destSize); 

 // sanity check, only YOU can prevent buffer overuns.

 memDelta = srcSize - destSize ;

 printf("accumulator: delta size is %ld\n", memDelta);

 // resize accumulator as neccisary
 if (memDelta > 0) {   // insert bytes
   printf("accumulator: inserting %ld bytes\n", memDelta);
   Insert(destStart, memDelta);  //!!!???!!! we need a check here...
 } else if (memDelta < 0) {                     // remove bytes
   printf("accumulator: removing %ld bytes\n", memDelta);
   Remove(destStart, abs(memDelta));
 } 
 printf("accumulator: resize done, copying contents\n");
 
 memcpy( Contents+destStart, src, srcSize);    // write content

 return srcSize;
}

/****************************************
*
* Resize the Accumulator. If making larger,
*  space is added to end of array, if making
*  smaller, space is removed from end. The
*  new size is absolute, not relative.
*  Contents of new memory are undefined.
* 
* NOTES:
*   This is where bookmarks need to be updated.
*
* In:
*  0 -> ~2G
*
* Out:
*  1 = successfull.
*  0 = unsuccessfull.
*
****************************************/
int Accumulator::ReSize( long newSize ) {

  char * tempPtr;

  printf("accumulator:Resize reallocing memory to %ld\n", newSize);  
  if ((tempPtr = (char *)realloc(Contents, newSize)) == NULL) { 
    printf("accululator:Resize realloc failed.\n");
    return 0;
  }
  
  printf("accumulator:Resize updating poitners\n");
  Contents    = tempPtr;
  ContentSize = newSize;
  
  return 1; 
}


/****************************************
*
*  Insert "blank" space of size at position
*
*  In:
*    - The position to insert "blank" space
*    - The amount of space to add
*
*  Out:
*    - The amount of space added
*
*
****************************************/
long Accumulator::Insert( long position, long size) {

  char * src;
  char * dest; 

 // add the space onto the end
  printf("accumulaor:Insert resizing array\n");
 ReSize(GetSize() + size);  // there should be a fail check here
 
 printf("accumulator:Insert  moving data\n");
 // move the data forward.
 
 dest = Contents + GetSize();
 src  = dest - size;
 for (; src >= (Contents + position); src--) {
   *dest = *src;
   *dest--;     
 } 
 
  return size; // note that if resize fails, this shouldn't return size. 

}


/****************************************
*
*  Remove a block of size at position
*    position is the start of the block.
*  In:
*    - The start position to remove from
*    - The amount of space to remove
*
*  Out:
*    - The amount of space removed
*
****************************************/
long Accumulator::Remove( long position, long size) {

  char * src;
  char * dest;

  src  = Contents + position + size;
  dest = Contents + position;

  // fold back the post data
  for (; src <= (Contents + GetSize()); src++) {
    *dest = *src;
    dest++;
  }
 
 // trim the space off the end.

  ReSize(GetSize() - size);

  return size; // change this !!!???!!!

}



Accumulator::~Accumulator ( void ) {
  
  // delete[] Contents;
  
  free(Contents);

}




