/*
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-Compressor 'seq'
// The Div-compressor compresses a string by applying a sequence of subcompressors
// to the string. The substrings for the compressors are separated by some delimiter strings

#pragma once

#include "CompressMan.hpp"
#include "UnCompCont.hpp"

struct DivCompressorItem
   // Each subcompressor and the following delimiter string
   // are stored in a 'DivCompressorItem'
{
   DivCompressorItem *next;               // The next subcompressor item
   UserCompressor    *usercompressor;     // The sub compressor
   UserUncompressor  *useruncompressor;   // The sub decompressor

   // The separator between subcompressors
   // This can be empty (afterseparator=NULL), if this is the last subcompressor
   // and there is no separator string at the end
   char              *afterseparator;
   unsigned short    afterseparatorlen;

   unsigned short    curitemlen;          // After parsing a string, we keep the
                                          // length of the string that matches the compressor
                                          // 'usercompressor'

#ifdef NOTHREAD
   void *operator new(size_t size);
   void operator delete(void *ptr);
#endif
};

struct DivSepComprInfo
   // Stores all the information about the subcompressors and delimiters
{
   // If there is a separator at the beginning, we store it here
   char              *startseparator;
   unsigned long     startseparatorlen;
	Session *session;

   DivCompressorItem *subcompressors;  // The list of subcompressors

	DivSepComprInfo(Session *s) {session = s;}
	DivSepComprInfo() {session = NULL;}
	void SetSession(Session *s) {session = s;}

   void CreateSubCompressors(char *paramstr,int len);
      // Generates the subcompressors from the parameter string
};

//*************************************************************************
// The 'seq' compressor
class DivSepCompressorFactory;

class DivSepCompressor : public UserCompressor
{
   friend DivSepCompressorFactory;
protected:

   DivSepComprInfo info;   // The information about the subcompressors

public:
	DivSepCompressor(Session *s): UserCompressor(s) 
	{
		info.SetSession(s);
	}
   void ComputeProperties();
   void CreateSubCompressors(char *paramstr,int len);
	void InitCompress(CompressContainer *cont,char *dataptr);
      // Initializes the the compressors
   char ParseString(char *str,unsigned len,char *dataptr);
   void 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 'ParseString' has been called before and
      // 'item->curitemlen' has been set for each subcompressor
   void FinishCompress(CompressContainer *cont,char *dataptr);
      // Finishes the compression - the compressor should write any
      // remaining data to the containers
      // For the seq-compressor, all subcompressors are 'finished'
   void PrintCompressInfo(char *dataptr,unsigned long *overalluncomprsize,unsigned long *overallcomprsize);
      // Prints statistical information about how well the compressor compressed
      // the data
};

//************************************************************************
//************************************************************************
//** The Decompressor ********

class DivSepUncompressor : public UserUncompressor
{
   friend DivSepCompressorFactory;
protected:
   DivSepComprInfo info;
public:
	DivSepUncompressor(Session *s): UserUncompressor(s) 
	{
		info.SetSession(s);
	}

   void ComputeProperties();
      // Computes the properties of the decompressor
   void CreateSubCompressors(char *paramstr,int len);
      // Creates the subcompressor structures based the
      // parameter string
   void InitUncompress(UncompressContainer *cont,char *dataptr);
      // Initializes the subcompressors
   void UncompressItem(UncompressContainer *cont,char *dataptr,XMLOutput *output);
      // Does the actual decompression of a single text item
      // and prints the text to 'output'
   void FinishUncompress(UncompressContainer *cont,char *dataptr);
      // Finishes the decompression
};

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

class DivSepCompressorFactory : public UserCompressorFactory
   // The compressor factory for 'seq'
{
public:
   char *GetName();
   char *GetDescription();

	DivSepCompressorFactory(Session *s);
   UserCompressor *InstantiateCompressor(char *paramstr,int len);
      // Instantiates the compressor
	UserUncompressor *InstantiateUncompressor(char *paramstr,int len);
      // Instantiates the decompressor
};

// 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.
class DivCombineCompressor : public DivSepCompressor
   // The compressor class is inherited from DivSepCompressor so that
   // we can use 'ParseString'
{
   friend DivSepCompressorFactory;

public:
	DivCombineCompressor(Session *s): DivSepCompressor(s) {};

   void ComputeProperties();
   void CreateSubCompressors(char *paramstr,int len);
   void InitCompress(CompressContainer *cont,char *dataptr);
   void 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
   void FinishCompress(CompressContainer *cont,char *dataptr);
      // Finishes the compression - the compressor should write any
      // remaining data to the containers
   void PrintCompressInfo(char *dataptr,unsigned long *overalluncomprsize,unsigned long *overallcomprsize);
      // Prints statistical information about how well the compressor compressed
      // the data
};

//**********************************************************************************
// The combined sequence decompressor

class DivCombineUncompressor : public DivSepUncompressor
   // Note that the class is denoted from 'DivSepUncompressor' so that
   // we can use the 'info' attribute
{
   friend DivSepCompressorFactory;

public:
	DivCombineUncompressor(Session *s): DivSepUncompressor(s) {};

   void ComputeProperties();
      // Computes the properties of the decompressor
      // Note that this is different from 'ComputeProperties' in the original
      // DivSepUncompressor
   void CreateSubCompressors(char *paramstr,int len);
   void InitUncompress(UncompressContainer *cont,char *dataptr);
      // Initializes the decompressor
   void UncompressItem(UncompressContainer *cont,char *dataptr,XMLOutput *output);
      // Does the actual decompression of a single text item
      // and prints the text to 'output'
   void FinishUncompress(UncompressContainer *cont,char *dataptr);
      // Finished the decompression
};

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

class DivCombineCompressorFactory : public DivSepCompressorFactory
   // The compressor factory for combined compressor/decompressor
{
public:
   char *GetName();
   char *GetDescription();

	DivCombineCompressorFactory(Session *s);
   UserCompressor *InstantiateCompressor(char *paramstr,int len);
   UserUncompressor *InstantiateUncompressor(char *paramstr,int len);
};
