/******************************************************************************
 **	Filename:    adaptive.c
 **	Purpose:     Adaptive matcher.
 **	Author:      Dan Johnson
 **	History:     Fri Mar  8 10:00:21 1991, DSJ, Created.
 **
 **	(c) Copyright Hewlett-Packard Company, 1988.
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** You may obtain a copy of the License at
 ** http://www.apache.org/licenses/LICENSE-2.0
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 ******************************************************************************/

/**----------------------------------------------------------------------------
          Include Files and Type Defines
----------------------------------------------------------------------------**/
#include "adaptive.h"
#include "emalloc.h"
#include "freelist.h"
#include "globals.h"
#include "classify.h"

#ifdef __UNIX__
#include <assert.h>
#endif
#include <stdio.h>

/**----------------------------------------------------------------------------
              Public Code
----------------------------------------------------------------------------**/
/*---------------------------------------------------------------------------*/
void AddAdaptedClass(ADAPT_TEMPLATES Templates,
                     ADAPT_CLASS Class,
                     CLASS_ID ClassId) {
/*
 **	Parameters:
 **		Templates	set of templates to add new class to
 **		Class		new class to add to templates
 **		ClassId		class id to associate with new class
 **	Globals: none
 **	Operation: This routine adds a new adapted class to an existing
 **		set of adapted templates.
 **	Return: none
 **	Exceptions: none
 **	History: Thu Mar 14 13:06:09 1991, DSJ, Created.
 */
  INT_CLASS IntClass;

  assert (Templates != NULL);
  assert (Class != NULL);
  assert (LegalClassId (ClassId));
  assert (UnusedClassIdIn (Templates->Templates, ClassId));
  assert (Class->NumPermConfigs == 0);

  IntClass = NewIntClass (1, 1);
  AddIntClass (Templates->Templates, ClassId, IntClass);

  assert (Templates->Class[ClassId] == NULL);
  Templates->Class[ClassId] = Class;

}                                /* AddAdaptedClass */


/*---------------------------------------------------------------------------*/
void FreeTempConfig(TEMP_CONFIG Config) {
/*
 **	Parameters:
 **		Config	config to be freed
 **	Globals: none
 **	Operation: This routine frees all memory consumed by a temporary
 **		configuration.
 **	Return: none
 **	Exceptions: none
 **	History: Thu Mar 14 13:34:23 1991, DSJ, Created.
 */
  assert (Config != NULL);

  destroy_nodes (Config->ContextsSeen, memfree);
  FreeBitVector (Config->Protos);
  free_struct (Config, sizeof (TEMP_CONFIG_STRUCT), "TEMP_CONFIG_STRUCT");

}                                /* FreeTempConfig */


/*---------------------------------------------------------------------------*/
void FreeTempProto(void *arg) {
  PROTO proto = (PROTO) arg;

  free_struct (proto, sizeof (TEMP_PROTO_STRUCT), "TEMP_PROTO_STRUCT");
}


/*---------------------------------------------------------------------------*/
ADAPT_CLASS NewAdaptedClass() {
/*
 **	Parameters: none
 **	Globals: none
 **	Operation: This operation allocates and initializes a new adapted
 **		class data structure and returns a ptr to it.
 **	Return: Ptr to new class data structure.
 **	Exceptions: none
 **	History: Thu Mar 14 12:58:13 1991, DSJ, Created.
 */
  ADAPT_CLASS Class;
  int i;

  Class = (ADAPT_CLASS) Emalloc (sizeof (ADAPT_CLASS_STRUCT));
  Class->NumPermConfigs = 0;
  Class->TempProtos = NIL;

  Class->PermProtos = NewBitVector (MAX_NUM_PROTOS);
  Class->PermConfigs = NewBitVector (MAX_NUM_CONFIGS);
  zero_all_bits (Class->PermProtos, WordsInVectorOfSize (MAX_NUM_PROTOS));
  zero_all_bits (Class->PermConfigs, WordsInVectorOfSize (MAX_NUM_CONFIGS));

  for (i = 0; i < MAX_NUM_CONFIGS; i++)
    TempConfigFor (Class, i) = NULL;

  return (Class);

}                                /* NewAdaptedClass */


/*-------------------------------------------------------------------------*/
void free_adapted_class(ADAPT_CLASS adapt_class) {
  int i;

  for (i = 0; i < MAX_NUM_CONFIGS; i++) {
    if (ConfigIsPermanent (adapt_class, i)
      && PermConfigFor (adapt_class, i) != NULL)
      Efree (PermConfigFor (adapt_class, i));
    else if (!ConfigIsPermanent (adapt_class, i)
      && TempConfigFor (adapt_class, i) != NULL)
      FreeTempConfig (TempConfigFor (adapt_class, i));
  }
  FreeBitVector (adapt_class->PermProtos);
  FreeBitVector (adapt_class->PermConfigs);
  destroy_nodes (adapt_class->TempProtos, FreeTempProto);
  Efree(adapt_class);
}


/*---------------------------------------------------------------------------*/
namespace tesseract {
ADAPT_TEMPLATES Classify::NewAdaptedTemplates(bool InitFromUnicharset) {
/*
 **	Parameters:
 **		PopulateFromUnicharset      if true, add an empty class for
 **                                         each char in unicharset to the
 **                                         newly created templates
 **	Globals: none
 **	Operation: Allocates memory for adapted tempates.
 **	Return: Ptr to new adapted templates.
 **	Exceptions: none
 **	History: Fri Mar  8 10:15:28 1991, DSJ, Created.
 */
  ADAPT_TEMPLATES Templates;
  int i;

  Templates = (ADAPT_TEMPLATES) Emalloc (sizeof (ADAPT_TEMPLATES_STRUCT));

  Templates->Templates = NewIntTemplates ();
  Templates->NumPermClasses = 0;
  Templates->NumNonEmptyClasses = 0;

  /* Insert an empty class for each unichar id in unicharset */
  for (i = 0; i < MAX_NUM_CLASSES; i++) {
    Templates->Class[i] = NULL;
    if (InitFromUnicharset && i < unicharset.size()) {
      AddAdaptedClass(Templates, NewAdaptedClass(), i);
    }
  }

  return (Templates);

}                                /* NewAdaptedTemplates */
}  // namespace tesseract

/*----------------------------------------------------------------------------*/
void free_adapted_templates(ADAPT_TEMPLATES templates) {

  if (templates != NULL) {
    int i;
    for (i = 0; i < (templates->Templates)->NumClasses; i++)
      free_adapted_class (templates->Class[i]);
    free_int_templates (templates->Templates);
    Efree(templates);
  }
}


/*---------------------------------------------------------------------------*/
TEMP_CONFIG NewTempConfig(int MaxProtoId) {
/*
 **	Parameters:
 **		MaxProtoId	max id of any proto in new config
 **	Globals: none
 **	Operation: This routine allocates and returns a new temporary
 **		config.
 **	Return: Ptr to new temp config.
 **	Exceptions: none
 **	History: Thu Mar 14 13:28:21 1991, DSJ, Created.
 */
  TEMP_CONFIG Config;
  int NumProtos = MaxProtoId + 1;

  Config =
    (TEMP_CONFIG) alloc_struct (sizeof (TEMP_CONFIG_STRUCT),
    "TEMP_CONFIG_STRUCT");
  Config->Protos = NewBitVector (NumProtos);

  Config->NumTimesSeen = 1;
  Config->MaxProtoId = MaxProtoId;
  Config->ProtoVectorSize = WordsInVectorOfSize (NumProtos);
  Config->ContextsSeen = NIL;
  zero_all_bits (Config->Protos, Config->ProtoVectorSize);

  return (Config);

}                                /* NewTempConfig */


/*---------------------------------------------------------------------------*/
TEMP_PROTO NewTempProto() {
/*
 **	Parameters: none
 **	Globals: none
 **	Operation: This routine allocates and returns a new temporary proto.
 **	Return: Ptr to new temporary proto.
 **	Exceptions: none
 **	History: Thu Mar 14 13:31:31 1991, DSJ, Created.
 */
  return ((TEMP_PROTO)
    alloc_struct (sizeof (TEMP_PROTO_STRUCT), "TEMP_PROTO_STRUCT"));
}                                /* NewTempProto */


/*---------------------------------------------------------------------------*/
namespace tesseract {
void Classify::PrintAdaptedTemplates(FILE *File, ADAPT_TEMPLATES Templates) {
/*
 **	Parameters:
 **		File		open text file to print Templates to
 **		Templates	adapted templates to print to File
 **	Globals: none
 **	Operation: This routine prints a summary of the adapted templates
 **		in Templates to File.
 **	Return: none
 **	Exceptions: none
 **	History: Wed Mar 20 13:35:29 1991, DSJ, Created.
 */
  int i;
  INT_CLASS IClass;
  ADAPT_CLASS AClass;

  #ifndef SECURE_NAMES
  fprintf (File, "\n\nSUMMARY OF ADAPTED TEMPLATES:\n\n");
  fprintf (File, "Num classes = %d;  Num permanent classes = %d\n\n",
           Templates->NumNonEmptyClasses, Templates->NumPermClasses);
  fprintf (File, "   Id  NC NPC  NP NPP\n");
  fprintf (File, "------------------------\n");

  for (i = 0; i < (Templates->Templates)->NumClasses; i++) {
    IClass = Templates->Templates->Class[i];
    AClass = Templates->Class[i];
    if (!IsEmptyAdaptedClass (AClass)) {
      fprintf (File, "%5d  %s %3d %3d %3d %3d\n",
        i, unicharset.id_to_unichar(i),
      IClass->NumConfigs, AClass->NumPermConfigs,
      IClass->NumProtos,
      IClass->NumProtos - count (AClass->TempProtos));
    }
  }
  #endif
  fprintf (File, "\n");

}                                /* PrintAdaptedTemplates */
}  // namespace tesseract


/*---------------------------------------------------------------------------*/
ADAPT_CLASS ReadAdaptedClass(FILE *File) {
/*
 **	Parameters:
 **		File	open file to read adapted class from
 **	Globals: none
 **	Operation: Read an adapted class description from File and return
 **		a ptr to the adapted class.
 **	Return: Ptr to new adapted class.
 **	Exceptions: none
 **	History: Tue Mar 19 14:11:01 1991, DSJ, Created.
 */
  int NumTempProtos;
  int NumConfigs;
  int i;
  ADAPT_CLASS Class;
  TEMP_PROTO TempProto;

  /* first read high level adapted class structure */
  Class = (ADAPT_CLASS) Emalloc (sizeof (ADAPT_CLASS_STRUCT));
  fread ((char *) Class, sizeof (ADAPT_CLASS_STRUCT), 1, File);

  /* then read in the definitions of the permanent protos and configs */
  Class->PermProtos = NewBitVector (MAX_NUM_PROTOS);
  Class->PermConfigs = NewBitVector (MAX_NUM_CONFIGS);
  fread ((char *) Class->PermProtos, sizeof (uinT32),
    WordsInVectorOfSize (MAX_NUM_PROTOS), File);
  fread ((char *) Class->PermConfigs, sizeof (uinT32),
    WordsInVectorOfSize (MAX_NUM_CONFIGS), File);

  /* then read in the list of temporary protos */
  fread ((char *) &NumTempProtos, sizeof (int), 1, File);
  Class->TempProtos = NIL;
  for (i = 0; i < NumTempProtos; i++) {
    TempProto =
      (TEMP_PROTO) alloc_struct (sizeof (TEMP_PROTO_STRUCT),
      "TEMP_PROTO_STRUCT");
    fread ((char *) TempProto, sizeof (TEMP_PROTO_STRUCT), 1, File);
    Class->TempProtos = push_last (Class->TempProtos, TempProto);
  }

  /* then read in the adapted configs */
  fread ((char *) &NumConfigs, sizeof (int), 1, File);
  for (i = 0; i < NumConfigs; i++)
    if (test_bit (Class->PermConfigs, i))
      Class->Config[i].Perm = ReadPermConfig (File);
    else
      Class->Config[i].Temp = ReadTempConfig (File);

  return (Class);

}                                /* ReadAdaptedClass */


/*---------------------------------------------------------------------------*/
namespace tesseract {
ADAPT_TEMPLATES Classify::ReadAdaptedTemplates(FILE *File) {
/*
 **	Parameters:
 **		File	open text file to read adapted templates from
 **	Globals: none
 **	Operation: Read a set of adapted templates from File and return
 **		a ptr to the templates.
 **	Return: Ptr to adapted templates read from File.
 **	Exceptions: none
 **	History: Mon Mar 18 15:18:10 1991, DSJ, Created.
 */
  int i;
  ADAPT_TEMPLATES Templates;

  /* first read the high level adaptive template struct */
  Templates = (ADAPT_TEMPLATES) Emalloc (sizeof (ADAPT_TEMPLATES_STRUCT));
  fread ((char *) Templates, sizeof (ADAPT_TEMPLATES_STRUCT), 1, File);

  /* then read in the basic integer templates */
  Templates->Templates = ReadIntTemplates (File);

  /* then read in the adaptive info for each class */
  for (i = 0; i < (Templates->Templates)->NumClasses; i++) {
    Templates->Class[i] = ReadAdaptedClass (File);
  }
  return (Templates);

}                                /* ReadAdaptedTemplates */
}  // namespace tesseract


/*---------------------------------------------------------------------------*/
PERM_CONFIG ReadPermConfig(FILE *File) {
/*
 **	Parameters:
 **		File	open file to read permanent config from
 **	Globals: none
 **	Operation: Read a permanent configuration description from File
 **		and return a ptr to it.
 **	Return: Ptr to new permanent configuration description.
 **	Exceptions: none
 **	History: Tue Mar 19 14:25:26 1991, DSJ, Created.
 */
  PERM_CONFIG Config;
  uinT8 NumAmbigs;

  fread ((char *) &NumAmbigs, sizeof (uinT8), 1, File);
  Config = (PERM_CONFIG) Emalloc (sizeof (UNICHAR_ID) * (NumAmbigs + 1));
  fread (Config, sizeof (UNICHAR_ID), NumAmbigs, File);
  Config[NumAmbigs] = -1;

  return (Config);

}                                /* ReadPermConfig */


/*---------------------------------------------------------------------------*/
TEMP_CONFIG ReadTempConfig(FILE *File) {
/*
 **	Parameters:
 **		File	open file to read temporary config from
 **	Globals: none
 **	Operation:  Read a temporary configuration description from File
 **		and return a ptr to it.
 **	Return: Ptr to new temporary configuration description.
 **	Exceptions: none
 **	History: Tue Mar 19 14:29:59 1991, DSJ, Created.
 */
  TEMP_CONFIG Config;

  Config =
    (TEMP_CONFIG) alloc_struct (sizeof (TEMP_CONFIG_STRUCT),
    "TEMP_CONFIG_STRUCT");
  fread ((char *) Config, sizeof (TEMP_CONFIG_STRUCT), 1, File);

  Config->Protos = NewBitVector (Config->ProtoVectorSize * BITSINLONG);
  fread ((char *) Config->Protos, sizeof (uinT32),
    Config->ProtoVectorSize, File);

  return (Config);

}                                /* ReadTempConfig */


/*---------------------------------------------------------------------------*/
void WriteAdaptedClass(FILE *File, ADAPT_CLASS Class, int NumConfigs) {
/*
 **	Parameters:
 **		File		open file to write Class to
 **		Class		adapted class to write to File
 **		NumConfigs	number of configs in Class
 **	Globals: none
 **	Operation: This routine writes a binary representation of Class
 **		to File.
 **	Return: none
 **	Exceptions: none
 **	History: Tue Mar 19 13:33:51 1991, DSJ, Created.
 */
  int NumTempProtos;
  LIST TempProtos;
  int i;

  /* first write high level adapted class structure */
  fwrite ((char *) Class, sizeof (ADAPT_CLASS_STRUCT), 1, File);

  /* then write out the definitions of the permanent protos and configs */
  fwrite ((char *) Class->PermProtos, sizeof (uinT32),
    WordsInVectorOfSize (MAX_NUM_PROTOS), File);
  fwrite ((char *) Class->PermConfigs, sizeof (uinT32),
    WordsInVectorOfSize (MAX_NUM_CONFIGS), File);

  /* then write out the list of temporary protos */
  NumTempProtos = count (Class->TempProtos);
  fwrite ((char *) &NumTempProtos, sizeof (int), 1, File);
  TempProtos = Class->TempProtos;
  iterate (TempProtos) {
    void* proto = first_node(TempProtos);
    fwrite ((char *) proto, sizeof (TEMP_PROTO_STRUCT), 1, File);
  }

  /* then write out the adapted configs */
  fwrite ((char *) &NumConfigs, sizeof (int), 1, File);
  for (i = 0; i < NumConfigs; i++)
    if (test_bit (Class->PermConfigs, i))
      WritePermConfig (File, Class->Config[i].Perm);
    else
      WriteTempConfig (File, Class->Config[i].Temp);

}                                /* WriteAdaptedClass */


/*---------------------------------------------------------------------------*/
namespace tesseract {
void Classify::WriteAdaptedTemplates(FILE *File, ADAPT_TEMPLATES Templates) {
/*
 **	Parameters:
 **		File		open text file to write Templates to
 **		Templates	set of adapted templates to write to File
 **	Globals: none
 **	Operation: This routine saves Templates to File in a binary format.
 **	Return: none
 **	Exceptions: none
 **	History: Mon Mar 18 15:07:32 1991, DSJ, Created.
 */
  int i;

  /* first write the high level adaptive template struct */
  fwrite ((char *) Templates, sizeof (ADAPT_TEMPLATES_STRUCT), 1, File);

  /* then write out the basic integer templates */
  WriteIntTemplates (File, Templates->Templates, unicharset);

  /* then write out the adaptive info for each class */
  for (i = 0; i < (Templates->Templates)->NumClasses; i++) {
    WriteAdaptedClass (File, Templates->Class[i],
      Templates->Templates->Class[i]->NumConfigs);
  }
}                                /* WriteAdaptedTemplates */
}  // namespace tesseract


/*---------------------------------------------------------------------------*/
void WritePermConfig(FILE *File, PERM_CONFIG Config) {
/*
 **	Parameters:
 **		File	open file to write Config to
 **		Config	permanent config to write to File
 **	Globals: none
 **	Operation: This routine writes a binary representation of a
 **		permanent configuration to File.
 **	Return: none
 **	Exceptions: none
 **	History: Tue Mar 19 13:55:44 1991, DSJ, Created.
 */
  uinT8 NumAmbigs = 0;

  assert (Config != NULL);
  while (Config[NumAmbigs] > 0)
    ++NumAmbigs;

  fwrite ((char *) &NumAmbigs, sizeof (uinT8), 1, File);
  fwrite (Config, sizeof (UNICHAR_ID), NumAmbigs, File);

}                                /* WritePermConfig */


/*---------------------------------------------------------------------------*/
void WriteTempConfig(FILE *File, TEMP_CONFIG Config) {
/*
 **	Parameters:
 **		File	open file to write Config to
 **		Config	temporary config to write to File
 **	Globals: none
 **	Operation: This routine writes a binary representation of a
 **		temporary configuration to File.
 **	Return: none
 **	Exceptions: none
 **	History: Tue Mar 19 14:00:28 1991, DSJ, Created.
 */
  assert (Config != NULL);
                                 /* contexts not yet implemented */
  assert (Config->ContextsSeen == NULL);

  fwrite ((char *) Config, sizeof (TEMP_CONFIG_STRUCT), 1, File);
  fwrite ((char *) Config->Protos, sizeof (uinT32),
    Config->ProtoVectorSize, File);

}                                /* WriteTempConfig */