/*
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 Division-Combine-Compressor 'seqcomb'

#include "stdafx.h"

// The DivCombine compressor is similar to the DivSep compressor.
// The only difference is that the containers of the subcompressors 'overlap' -
// i.e. the overall number of containers of the 'seqcomb' compressor is
// the *maximum* number of containers of the subcompressors.
void DivCombineCompressor::ComputeProperties()
{
   isrejecting=1;canoverlap=1;
   isfixedlen=1;
   datasize=0;
   contnum=0;
   
   DivCompressorItem *item=info.subcompressors;
   while(item!=NULL)
   {
      datasize+=item->usercompressor->GetUserDataSize();

      // We find the maximum container number
      if(contnum<item->usercompressor->GetUserContNum())
         contnum=item->usercompressor->GetUserContNum();

      if(item->usercompressor->CanOverlap()==0)
         canoverlap=0;

      if(item->usercompressor->IsFixedLen()==0)
         isfixedlen=0;

      item=item->next;
   }
}

void DivCombineCompressor::CreateSubCompressors(char *paramstr,int len)
{
   info.CreateSubCompressors(paramstr,len);
}

void DivCombineCompressor::InitCompress(CompressContainer *cont,char *dataptr)
{
   DivCompressorItem *item=info.subcompressors;

   while(item!=NULL)
   {
      // Note that 'cont' is the same for all subcompressors.
      item->usercompressor->InitCompress(cont,dataptr);
      dataptr+=item->usercompressor->GetUserDataSize();
      item=item->next;
   }
}

void DivCombineCompressor::CompressString(char *str,unsigned len,CompressContainer *cont,char *dataptr)
   // Compresses the given input string
   // 'dataptr' denotes the state
   // Since the compressor is 'rejecting', the function can expect
   // that 'DivSepCompressor::ParseString' has been called before and
   // 'item->curitemlen' has been set for each subcompressor
{
   DivCompressorItem *item=info.subcompressors;
   char              *startitemptr;

   startitemptr=str+info.startseparatorlen;

   while(item!=NULL)
   {
      item->usercompressor->CompressString(startitemptr,item->curitemlen,cont,dataptr);
      dataptr+=item->usercompressor->GetUserDataSize();

      startitemptr+=item->curitemlen+item->afterseparatorlen;
      item=item->next;
   }
}

void DivCombineCompressor::FinishCompress(CompressContainer *cont,char *dataptr)
   // Finishes the compression - the compressor should write any
   // remaining data to the containers
{
   DivCompressorItem *item=info.subcompressors;

   while(item!=NULL)
   {
      item->usercompressor->FinishCompress(cont,dataptr);
      dataptr+=item->usercompressor->GetUserDataSize();
      item=item->next;
   }
}

void DivCombineCompressor::PrintCompressInfo(char *dataptr,unsigned long *overalluncomprsize,unsigned long *overallcomprsize)
   // Prints statistical information about how well the compressor compressed
   // the data
{
   DivCompressorItem *item=info.subcompressors;

   while(item!=NULL)
   {
      item->usercompressor->PrintCompressInfo(dataptr,overalluncomprsize,overallcomprsize);

      dataptr+=item->usercompressor->GetUserDataSize();

      item=item->next;
   }
}

// The combined sequence decompressor
void DivCombineUncompressor::ComputeProperties()
   // Computes the properties of the decompressor
   // Note that this is different from 'ComputeProperties' in the original
   // DivSepUncompressor
{
   DivCompressorItem *item=info.subcompressors;

   datasize=0;
   contnum=0;

   while(item!=NULL)
   {
      datasize+=item->useruncompressor->GetUserDataSize();

      // We find the maximum container count:
      if(contnum<item->useruncompressor->GetUserContNum())
         contnum=item->useruncompressor->GetUserContNum();
      item=item->next;
   }
}

void DivCombineUncompressor::CreateSubCompressors(char *paramstr,int len)
{
   info.CreateSubCompressors(paramstr,len);
}

void DivCombineUncompressor::InitUncompress(UncompressContainer *cont,char *dataptr)
   // Initializes the decompressor
{
   DivCompressorItem *item=info.subcompressors;

   while(item!=NULL)
   {
      item->useruncompressor->InitUncompress(cont,dataptr);

      dataptr+=item->useruncompressor->GetUserDataSize();
      item=item->next;
   }
}

void DivCombineUncompressor::UncompressItem(UncompressContainer *cont,char *dataptr,XMLOutput *output)
   // Does the actual decompression of a single text item
   // and prints the text to 'output'
{
   DivCompressorItem *item=info.subcompressors;

   if(info.startseparator!=NULL)
      output->characters(info.startseparator,info.startseparatorlen);

   while(item!=NULL)
   {
      item->useruncompressor->UncompressItem(cont,dataptr,output);
      if(item->afterseparator!=NULL)
         output->characters(item->afterseparator,item->afterseparatorlen);
      dataptr+=item->useruncompressor->GetUserDataSize();

      item=item->next;
   }
}

void DivCombineUncompressor::FinishUncompress(UncompressContainer *cont,char *dataptr)
   // Finished the decompression
{
   DivCompressorItem *item=info.subcompressors;

   while(item!=NULL)
   {
      item->useruncompressor->FinishUncompress(cont,dataptr);
      dataptr+=item->useruncompressor->GetUserDataSize();
      item=item->next;
   }
}

DivCombineCompressorFactory::DivCombineCompressorFactory(Session *s): DivSepCompressorFactory(s)
{}

char *DivCombineCompressorFactory::GetName()         
{  
	return "seqcomb"; 
}
char *DivCombineCompressorFactory::GetDescription()  
{  
	return "Combined sequence compressor for strings with separators"; 
}

UserCompressor *DivCombineCompressorFactory::InstantiateCompressor(char *paramstr,int len)
{
   if(paramstr==NULL)
   {
      throw new XMillException(XMILL_ERR_ARGUMENTS, "Combined sequence compressor 'seqcomb' must have a sequence of strings and compressors as parameters");
   }

   DivCombineCompressor  *divcombcompressor=new DivCombineCompressor(session);

   // Initializes the decompressor with the subcompressors
   divcombcompressor->CreateSubCompressors(paramstr,len);
   divcombcompressor->ComputeProperties();
   return divcombcompressor;
}

UserUncompressor *DivCombineCompressorFactory::InstantiateUncompressor(char *paramstr,int len)
{
   DivCombineUncompressor  *divcombuncompressor=new DivCombineUncompressor(session);

   // Initializes the decompressor with the subcompressors
   divcombuncompressor->CreateSubCompressors(paramstr,len);
   divcombuncompressor->ComputeProperties();
   return divcombuncompressor;
}
