

#include <string.h>
#include <stdio.h>
#include "Boolean.h"
#include "ImpactStore.h"



ImpactFile::ImpactFile()
{
  // Initilise everything to null
  file = NULL;
  fb = NULL;
}


ImpactFile::~ImpactFile()
{
  // Delete array
  if (fb!=NULL)
    delete fb;

  // Close file
  if (file!=NULL)
    fclose(file);
}


int ImpactFile::initialise(const int maximumid)
{
  int i;

  // Open the file
  file = tmpfile();
  if (file==NULL)
    return 0;

  // Alloc first block array
  fb = new long[maximumid];
  if (fb==NULL)
    {
      fclose(file);
      file=NULL;

      return 0;
    }

  // Initialise first bloxk array
  for(i=0;i<maximumid;i++)
    fb[i]=-1L;

  // Everything went ok ...
  return 1;
}




ImpactStore::ImpactStore(const int maximumid)
{
  int   i;

  // Save the maximum identifier
  maxid = maximumid+1;

  // Find the space needed for one impact.
  sizeofimpact = Impact::getNumBytes();

  // Number of impact per block
  impactperblock = (bsz - sizeof(long)) / sizeofimpact;

  // No impact file
  cf = -1; 
  cb = maxfilesz; // To force allocation of a new file
  
  // Alloc memory for array of last block positions
  lb = new long[maxid];

  // Alloc memory for array of last file numbers
  lf = new int[maxid];

  // Alloc array for buffer
  buffer = new Impact[buffersz];

  // Alloc memory for array of counter
  numonid = new long[maxid];

  // Alloc memory for array of DynamicVector
  ids = new DynamicVector* [maxid];
  
  // Alloc DynamicVector individually
  for (i=0;i<maxid;i++)
    {
      ids[i] = new DynamicVector();
      numonid[i] = 0;
      lf[i]=-1;
      lb[i]=-1;
    }
  
  // No impacts in memory
  numinmemory = 0;
}



ImpactStore::~ImpactStore()
{
  int                  i;
  
  // Free array of DynamicVectors
  if (ids != NULL)
    {
      for (i=0;i<maxid;i++)
	if (ids[i] != NULL)
	  delete ids[i];
      
      delete ids;
    }

  // Free array of last blocks
  if (lb != NULL)
    delete lb;

  // Free array of last file
  if (lf != NULL)
    delete lf;

  // Free count array
  if (numonid != NULL)
    delete numonid;

  // Free buffer
  if (buffer != NULL)
    delete buffer;
}



void ImpactStore::flush()
{
  int                  i;
  long                 inv;

  printf("Recording impacts on disk...\n");

  for (i=0;i<maxid;i++)
    {
      // Place the file pointer
      if ((lb[i]!=-1)&&(lf[i]!=-1))
	fseek(pf[lf[i]].file,lb[i] + (numonid[i] % impactperblock)*sizeofimpact, SEEK_SET);

      ids[i]->iterateStart();
      while (ids[i]->iterateIsNext())
	{
	  // Check if we have to alloc a new block
	  if (numonid[i] % impactperblock == 0)
	    {
	      // New block allocation
	      if (cb == maxfilesz)
		{
		  // New file
		  cf++;
		  pf[cf].initialise(maxid);
		  cb=0;
		}

	      // cf and cb now contains the current file and the current position in this file.	      
	      
	      // Write link in previous block.
	      if (lf[i] !=-1)
		{
		  // Write next block pointer
		  
		  // Seek to correct position
		  fseek(pf[lf[i]].file, lb[i] + (impactperblock*sizeofimpact), SEEK_SET);
		  
		  if (cf!=lf[i])
		    {
		      // We change file write file number
		      inv = -cf;
		      fwrite((void*)&inv,sizeof(long),1,pf[lf[i]].file);
		    }
		  else
		    fwrite((void*)&cb,sizeof(long),1,pf[lf[i]].file);
		}

	      // Update first block for file field if we changed file
	      if (cf != lf[i])
		pf[cf].fb[i] = cb;

	      lb[i] = cb;
	      lf[i] = cf;		
		
	      // Update current block
	      cb += bsz;
	     
	      // Put the file pointer at the start of the block
	      fseek(pf[lf[i]].file, lb[i], SEEK_SET);
	    }

	  // Save the impact
	  ((Impact*)ids[i]->iterate())->write(pf[lf[i]].file);
	  numonid[i]++;
          numinmemory--;
	}

      ids[i]->freeAllElements();
    }

  numinmemory = 0;
}


int ImpactStore::recordImpact(const int id,const Impact& impact)
{
  // Copy the impact
  buffer[numinmemory] = impact;

  // Add link to the impact
  if (!ids[id]->addElement(&buffer[numinmemory]))
    return FALSE;
  
  // If too much impacts on memory, flush on disk
  numinmemory++;
  if (numinmemory == buffersz)
    flush();
  
  return TRUE;
}


int ImpactStore::getNumberOfImpacts(const int id)
{ return numonid[id]; }


ImpactStoreWindow* ImpactStore::newImpactStoreWindow(const int id)
{
  ImpactStoreWindow *isw;

  isw = new ImpactStoreWindow();

  isw->is = this;
  isw->id = id;
  isw->curfile  = 0;
  isw->curblock = pf[0].fb[id];
  isw->curnum = 0;
  isw->maxnum = numonid[id];

  return isw;
}

int ImpactStoreWindow::readNext(Impact &p)
{
  if (curnum>=maxnum)
    return 0;

  while (curblock<0)
    {
      curfile++;
      curblock = is->pf[curfile].fb[id];
    }

  fseek(is->pf[curfile].file,curblock + (curnum % is->impactperblock)*is->sizeofimpact,SEEK_SET);
  p.read(is->pf[curfile].file);

  curnum++;
  if ((curnum % is->impactperblock) == 0)
    {
      fread((void*)&curblock,sizeof(long),1,is->pf[curfile].file);
    }
    
  return 1;
}











