/* XMLPPM: an XML compressor
Copyright (C) 2003 James Cheney

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

Contacting the author:
James Cheney
Computer Science Department
Cornell University
Ithaca, NY 14850

jcheney@cs.cornell.edu
*/
/****************************************************************************
 *  This file is part of PPMd project                                       *
 *  Written and distributed to public domain by Dmitry Shkarin 1997,        *
 *  1999-2001                                                               *
 *  Contents: PPMII model description and encoding/decoding routines        *
 ****************************************************************************/
/* Changes 1/2003 by James Cheney to interface to XMLPPM
 * Changes 3/2003 by Hedzer Westra to interface to XMill
 */

#ifndef __MODEL_H__
#define __MODEL_H__

#include "SubAlloc.hpp"
#include "PPMdType.h"
#include "Coder.h"

class PPMDI;

enum
{ UP_FREQ = 5, INT_BITS = 7, PERIOD_BITS = 7, TOT_BITS =
    INT_BITS + PERIOD_BITS,
  INTERVAL = 1 << INT_BITS, BIN_SCALE = 1 << TOT_BITS, MAX_FREQ =
    124, O_BOUND = 9
};

#pragma pack(1)
struct SEE2_CONTEXT
{				// SEE-contexts for PPM-contexts with masked symbols
  WORD Summ;
  BYTE Shift, Count;
  void init (UINT InitVal)
  {
    Summ = InitVal << (Shift = PERIOD_BITS - 4);
    Count = 7;
  }
  UINT getMean ()
  {
    UINT RetVal = (Summ >> Shift);
    Summ -= RetVal;
    return RetVal + (RetVal == 0);
  }
  void update ()
  {
    if (Shift < PERIOD_BITS && --Count == 0)
      {
	Summ += Summ;
	Count = 3 << Shift++;
      }
  }
} _PACK_ATTR;

struct PPM_CONTEXT;

struct STATE
{				
  BYTE Symbol, Freq;		
  PPM_CONTEXT *Successor;	
}  _PACK_ATTR;

#define STATS States.SummStats.Stats
#define SUMMFREQ States.SummStats.SummFreq
#define ONESTATE States.OneState




struct PPM_CONTEXT
{				
  BYTE NumStats, Flags;		
  union {
    struct {
      WORD SummFreq;		//  number of symbols minus 1
      struct STATE *Stats;		//  ABCD    context
    } SummStats;
    struct STATE OneState;
  } States;
  PPM_CONTEXT *Suffix;		//   BCD    suffix
}
_PACK_ATTR;


struct PPM_MODEL
{
  struct PPM_CONTEXT *MaxContext, *PrevContext;
  struct SEE2_CONTEXT SEE2Cont[24][32], DummySEE2Cont;
  BYTE NS2BSIndx[256], QTable[260];	// constants
  STATE * FoundState;	// found next state transition
  int InitEsc, OrderFall, RunLength, InitRL, MaxOrder;
  BYTE CharMask[256], NumMasked, PrevSuccess, EscCount, PrintCount;
  WORD BinSumm[25][64];		// binary SEE-contexts
  SubAlloc* sa;
  PPMDIData* data;
  int DecodedSize;
  int recoverstate;

  PPM_MODEL (int SASize, int MaxOrder, PPMDIData* data);
  ~PPM_MODEL() {}

  void StartModelRare();
  void RestoreModelRare (PPM_CONTEXT * pc1, PPM_CONTEXT * MinContext,
			 PPM_CONTEXT * FSuccessor);

  PPM_CONTEXT * CreateSuccessors (BOOL Skip,
				  STATE * p,
				  PPM_CONTEXT * pc);
  PPM_CONTEXT * ReduceOrder (STATE * p,
			     PPM_CONTEXT * pc);
  void UpdateModel (PPM_CONTEXT * MinContext);
  void ClearMask ();

  void EncodeChar (PPMDI* EncodedFile,
			    int c);
  void PreloadChar (int c);
  int DecodeChar (PPMDI* EncodedFile);

  inline int ariDecNormalize(PPMDI *stream);

  inline void encodeBinSymbol (PPM_CONTEXT * ctxt, int symbol);	//   BCDE   successor
  inline void encodeSymbol1 (PPM_CONTEXT * ctxt, int symbol);	// other orders:
  inline void encodeSymbol2 (PPM_CONTEXT * ctxt, int symbol);	//   BCD    context
  inline void decodeBinSymbol (PPM_CONTEXT * ctxt);	//    CD    suffix
  inline void decodeSymbol1 (PPM_CONTEXT * ctxt);	//   BCDE   successor
  inline void decodeSymbol2 (PPM_CONTEXT * ctxt);
  inline void update1 (PPM_CONTEXT * ctxt, STATE * p);
  inline void update2 (PPM_CONTEXT * ctxt, STATE * p);
  inline SEE2_CONTEXT *makeEscFreq2 (PPM_CONTEXT * ctxt);
  void rescale (PPM_CONTEXT * ctxt);
  void refresh (PPM_CONTEXT * ctxt, int OldNU, BOOL Scale);
  PPM_CONTEXT *cutOff (PPM_CONTEXT * ctxt, int Order);
  PPM_CONTEXT *removeBinConts (PPM_CONTEXT * ctxt, int Order);

}
_PACK_ATTR;

struct PPM_ENCODER : PPM_MODEL {
  PPMDI* outfile;
  PPM_ENCODER(int SASize, int MaxOrder, PPMDIData* data) 
    : PPM_MODEL(SASize, MaxOrder, data),
    outfile(data->getFp()) {}
  void EncodeChar (int c) {
    PPM_MODEL::EncodeChar(outfile,c);
  }
};

struct PPM_DECODER : public PPM_MODEL {
  PPMDI* infile;
  PPM_DECODER(int SASize, int MaxOrder, PPMDIData* data) 
    : PPM_MODEL(SASize,MaxOrder, data),
    infile(data->getFp()) {}
  int DecodeChar() {
    return PPM_MODEL::DecodeChar(infile);
  }
};

#endif



