/*
This product contains certain software code or other information
("AT&T Software") proprietary to AT&T Corp. ("AT&T").  The AT&T
Software is provided to you "AS IS".  YOU ASSUME TOTAL RESPONSIBILITY
AND RISK FOR USE OF THE AT&T SOFTWARE.  AT&T DOES NOT MAKE, AND
EXPRESSLY DISCLAIMS, ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND
WHATSOEVER, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, WARRANTIES OF
TITLE OR NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS, ANY
WARRANTIES ARISING BY USAGE OF TRADE, COURSE OF DEALING OR COURSE OF
PERFORMANCE, OR ANY WARRANTY THAT THE AT&T SOFTWARE IS "ERROR FREE" OR
WILL MEET YOUR REQUIREMENTS.

Unless you accept a license to use the AT&T Software, you shall not
reverse compile, disassemble or otherwise reverse engineer this
product to ascertain the source code for any AT&T Software.

(c) AT&T Corp. All rights reserved.  AT&T is a registered trademark of AT&T Corp.

***********************************************************************

History:

      24/11/99  - initial release by Hartmut Liefke, liefke@seas.upenn.edu
                                     Dan Suciu,      suciu@research.att.com
*/

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

// This module contains the container manager for the compressor XMill

#include "stdafx.h"

void Session::InitSpecialContainerSizeSum()
{
   structcontsizeorig=0;
   structcontsizecompressed=0;
   whitespacecontsizeorig=0;
   whitespacecontsizecompressed=0;
   specialcontsizeorig=0;
   specialcontsizecompressed=0;
   compressorcontsizeorig=0;
   compressorcontsizecompressed=0;
   datacontsizeorig=0;
   datacontsizecompressed=0;
}

void Session::PrintSpecialContainerSizeSum()
{
   printf("\nHeader:          Uncompressed: %8lu   Compressed: %8lu (%f%%)\n",
      fileheadersize_orig,fileheadersize_compressed,
      100.0f*(float)fileheadersize_compressed/(float)fileheadersize_orig);
   printf("Structure:       Uncompressed: %8lu   Compressed: %8lu (%f%%)\n",
      structcontsizeorig,structcontsizecompressed,
      100.0f*(float)structcontsizecompressed/(float)structcontsizeorig);
   if(whitespacecontsizeorig!=0)
      printf("Whitespaces:     Uncompressed: %8lu   Compressed: %8lu (%f%%)\n",
         whitespacecontsizeorig,whitespacecontsizecompressed,
         100.0f*(float)whitespacecontsizecompressed/(float)whitespacecontsizeorig);
   if(specialcontsizeorig!=0)
      printf("Special:         Uncompressed: %8lu   Compressed: %8lu (%f%%)\n",
         specialcontsizeorig,specialcontsizecompressed,
         100.0f*(float)specialcontsizecompressed/(float)specialcontsizeorig);
   if(compressorcontsizeorig!=0)
      printf("User Compressor: Uncompressed: %8lu   Compressed: %8lu (%f%%)\n",
         compressorcontsizeorig,compressorcontsizecompressed,
         100.0f*(float)compressorcontsizecompressed/(float)compressorcontsizeorig);
   if(datacontsizeorig!=0)
      printf("Data:            Uncompressed: %8lu   Compressed: %8lu (%f%%)\n",
         datacontsizeorig,datacontsizecompressed,
         100.0f*(float)datacontsizecompressed/(float)datacontsizeorig);

   printf("                                          --------------------\n");
   printf("Sum:                                      Compressed: %8lu\n",
         fileheadersize_compressed+structcontsizecompressed+
         whitespacecontsizecompressed+specialcontsizecompressed+
         compressorcontsizecompressed+datacontsizecompressed);
	printf("\n");
}
 
//*************************************************************************************
//*************************************************************************************
/* class CompressContainerBlock implementation */
inline unsigned long CompressContainerBlock::GetDataSize()
   // Computes the overall size of the container block
   // by size of the containers
{
   unsigned long size=0;

   for(int i=0;i<contnum;i++)
      size+=GetContainer(i)->GetSize();

   return size;
}

unsigned long CompressContainerMan::GetDataSize()
   // Computes the overall size of all containers
{
   CompressContainerBlock  *block=blocklist;
   unsigned long           size=0;

   // First, we compress all small containers using the
   // same compressor

   while(block!=NULL)
   {
      size+=block->GetDataSize();
      block=block->nextblock;
   }
   return size;
}

inline void CompressContainerBlock::CompressSmallContainers(Compressor *compress)
   // Compresses the small containers in the container block
{
   for(int i=0;i<contnum;i++)
   {
      if(GetContainer(i)->GetSize()<SMALLCONT_THRESHOLD)
         compress->CompressMemStream(GetContainer(i));
   }
}

void CompressContainerMan::CompressSmallContainers(Compressor *compress)
   // Compresses the small containers of all container blocks
{
   CompressContainerBlock *block=blocklist;

   // First, we compress all small containers using the
   // same compressor

   while(block!=NULL)
   {
      block->CompressSmallContainers(compress);
      block=block->nextblock;
   }
}

inline void CompressContainerBlock::CompressLargeContainers(Output *output)
   // Compresses the large containers of the block
{
   Compressor        compress(settings,output);

   // In 'settings->verbose' mode, we output information about the
   // path dictionary
   if(  (settings->verbose >= XMILL_VERBOSE_ALL)
	  && (pathdictnode!=NULL)) {
      pathdictnode->PrintInfo();
      printf("\n");
   }

   // Each (large) container is compressed separately
   
   unsigned long  sumuncompressed=0,sumcompressed=0,
                  uncompressedsize,compressedsize;

   // First, we print the status information of the user compressors.
   // For example, for dictionary compressors, the dictonary
   // must be compressed - hence, we output the size of the
   // dictionary before and after compression

   if(  settings->verbose  >= XMILL_VERBOSE_STATS
		&& (cpathexpr!=NULL)) {
      cpathexpr->GetUserCompressor()->PrintCompressInfo(
         GetUserDataPtr(),&sumuncompressed,&sumcompressed);
	}

   session->compressorcontsizeorig+=sumuncompressed;
   session->compressorcontsizecompressed+=sumcompressed;

   char printsum=0;

   if(sumuncompressed>0)
      printsum=1;

   for(int i=0;i<contnum;i++)
   {
      if(settings->verbose >= XMILL_VERBOSE_STATS)
      {
			if (  pathdictnode != NULL) {  // Do we have a normal block?
				if (settings->verbose >= XMILL_VERBOSE_ALL) {
					printf("       %4lu: ",i);
				}
			} else {
            switch(i)
            {
            case 0: printf("   Structure:");break;
            case 1: printf(" Whitespaces:");break;
            case 2: printf("     Special:");break;
            }
         }
      }

      if(GetContainer(i)->GetSize()>=SMALLCONT_THRESHOLD)
      {
         sumuncompressed+=GetContainer(i)->GetSize();

         compress.CompressMemStream(GetContainer(i));
         compress.FinishCompress(&uncompressedsize,&compressedsize);

         if (  settings->verbose >= XMILL_VERBOSE_ALL
			   || (  pathdictnode == NULL
					&& settings->verbose >= XMILL_VERBOSE_STATS)) {
            printf("%8lu ==> %8lu (%f%%)\n",uncompressedsize,compressedsize,100.0f*(float)compressedsize/(float)uncompressedsize);
			}

         sumcompressed+=compressedsize;

         if(pathdictnode==NULL)  // The first block?
         {
            // For the three special containers, we keep track of the sum
            // of the (un)compressed data size
            switch(i)
            {
            case 0:  session->structcontsizeorig+=uncompressedsize;
                     session->structcontsizecompressed+=compressedsize;
                     break;
            case 1:  session->whitespacecontsizeorig+=uncompressedsize;
                     session->whitespacecontsizecompressed+=compressedsize;
                     break;
            case 2:  session->specialcontsizeorig+=uncompressedsize;
                     session->specialcontsizecompressed+=compressedsize;
            }
         }
         else
         {
            session->datacontsizeorig+=uncompressedsize;
            session->datacontsizecompressed+=compressedsize;
         }
      } else {
         if (  settings->verbose >= XMILL_VERBOSE_ALL
			   || (  pathdictnode == NULL
					&& settings->verbose >= XMILL_VERBOSE_STATS)) {
            printf("%8lu ==> Small...\n",GetContainer(i)->GetSize());
			}
      }
   }
   if(settings->verbose >= XMILL_VERBOSE_ALL) {
      if((contnum>1)||printsum)
         printf("        Sum: %8lu ==> %8lu (%f%%)\n\n",sumuncompressed,sumcompressed,100.0f*(float)sumcompressed/(float)sumuncompressed);
      else
         printf("\n");
   }
}

void CompressContainerMan::CompressLargeContainers(Output *output)
{
   CompressContainerBlock *block=blocklist;

   while(block!=NULL)
   {
      block->CompressLargeContainers(output);
      block=block->nextblock;
   }
}

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

inline void CompressContainerBlock::FinishCompress()
{
   if(cpathexpr!=NULL)
      cpathexpr->FinishCompress(GetContainer(0),GetUserDataPtr());
}

void CompressContainerMan::FinishCompress()
{
   CompressContainerBlock *block=blocklist;
   while(block!=NULL)
   {
      block->FinishCompress();
      block=block->nextblock;
   }
}

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

inline void CompressContainerBlock::StoreMainInfo(MemStreamer *output)
{
   output->StoreUInt32((cpathexpr!=NULL) ? cpathexpr->GetIdx() : 0);
   output->StoreUInt32(contnum);

   for(int i=0;i<contnum;i++)
      // First, we store the number of data containers
      output->StoreUInt32(GetContainer(i)->GetSize());
}

void CompressContainerMan::StoreMainInfo(MemStreamer *memstream)
{
   // First, we store the number of container block
   memstream->StoreUInt32(blocknum);

   CompressContainerBlock *block=blocklist;

   while(block!=NULL)
   {
      block->StoreMainInfo(memstream);
      block=block->nextblock;
   }

//   compressor->CompressMemStream(memstream);
}

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

inline void CompressContainerBlock::ReleaseMemory()
   // Releases the memory of the containers
{
   for(int i=0;i<contnum;i++)
      // Let's release the memory of all containers
      GetContainer(i)->ReleaseMemory(0);
}

void CompressContainerMan::ReleaseMemory()
{
   CompressContainerBlock *block=blocklist;

   while(block!=NULL)
   {
      block->ReleaseMemory();
      block=block->nextblock;
   }

   containernum=0;
   blocknum=0;
   blocklist=lastblock=NULL;
}


CompressContainerBlock *CompressContainerMan::CreateNewContainerBlock(unsigned contnum,unsigned userdatasize,PathDictNode *mypathdictnode,CompVPathExpr *pathexpr)
   // Creates a new container block with 'contnum' containers , with user data size
   // given by 'userdatasize', with the path dictionary node given by 'mypathdictnode'
   // and the path expression given by 'pathexpr'
   // If there is not enough memory, the function returns NULL.
{
	CompressContainerBlock *block=
#ifdef NOTHREAD
		new(contnum,userdatasize) 
			CompressContainerBlock(
				session, session->settings, blocknum);
#else
	(CompressContainerBlock*)
		session->blockmem->GetByteBlock(
		 sizeof(CompressContainerBlock)+
		 sizeof(CompressContainer)*contnum+
		 userdatasize); 
	block->Init(session, session->settings, blocknum);
#endif

   if(block==NULL)
      return NULL;

   block->contnum=(unsigned short)contnum;
   block->userdatasize=(unsigned short)userdatasize;

   block->pathdictnode=mypathdictnode;
   block->cpathexpr=pathexpr;

   // Let's add the container block at the end of the list
   block->nextblock=NULL;

   if(blocklist==NULL)
      blocklist=lastblock=block;
   else
   {
      lastblock->nextblock=block;
      lastblock=block;
   }

   // We initialize the memory for all the containers
   for(unsigned i=0;i<contnum;i++)
      block->GetContainer(i)->Initialize(session);

   blocknum++;
   containernum+=contnum;

   return block;
}

#ifdef NOTHREAD
void *CompressContainer::operator new(size_t size)  
{  
	return ::session->blockmem->GetByteBlock(size); 
}
void CompressContainer::operator delete(void *ptr)  {}

void *CompressContainerBlock::operator new(size_t size,unsigned contnum,unsigned userdatasize)  
{  
	return ::session->blockmem->GetByteBlock(size+sizeof(CompressContainer)*contnum+userdatasize); 
}
void CompressContainerBlock::operator delete(void *ptr)  {}
#ifdef SPECIAL_DELETE
void CompressContainerBlock::operator delete(void *ptr,unsigned contnum,unsigned userdatasize)  
{
}
#endif
#endif

CompressContainerBlock::CompressContainerBlock(Session *s,Settings *se,unsigned long id)
{
	Init(s, se, id);
}

void CompressContainerBlock::Init(Session *s,Settings *se,unsigned long id)
{
	session = s;
	settings = se;
   blockid = id;
}

unsigned long CompressContainerBlock::GetID() 
   // Returns block ID
{  
	return blockid;   
}

CompressContainer *CompressContainerBlock::GetContainer(int idx)
   // Returns the container with index 'idx' (0<=idx<=contnum)
{
   return (CompressContainer *)(this+1)+idx;
}

CompVPathExpr *CompressContainerBlock::GetPathExpr()   
   // return the path expression of the container block
{  
	return cpathexpr;  
}

unsigned short CompressContainerBlock::GetContNum()         
   // Returns container number
{  
	return contnum;   
}

char *CompressContainerBlock::GetUserDataPtr()
   // Returns a pointer to the actual user data after the container objects
{  
	return (char *)(this+1)+sizeof(CompressContainer)*contnum;  
}

unsigned long CompressContainerBlock::GetUserDataSize() 
   // Returns the size of the container data
{  
	return userdatasize;  
}

CompressContainerMan::CompressContainerMan(Session *s)
{
	session = s;
   containernum=0;
   blocknum=0;
   blocklist=lastblock=NULL;
}
