/* -*-C-*-
 ********************************************************************************
 *
 * File:        states.c  (Formerly states.c)
 * Description:  Representations of search states
 * Author:       Mark Seaman, OCR Technology
 * Created:      Wed May 16 15:49:34 1990
 * Modified:     Mon Jun 17 17:54:41 1991 (Mark Seaman) marks@hpgrlt
 * Language:     C
 * Package:      N/A
 * Status:       Experimental (Do Not Distribute)
 *
 * (c) Copyright 1990, Hewlett-Packard Company.
 ** 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.
 *
 *********************************************************************************/
/*----------------------------------------------------------------------
              I n c l u d e s
----------------------------------------------------------------------*/
#include "states.h"
#include "structures.h"
#include "tordvars.h"
#include "callcpp.h"

/*-------------------------------------------------------------------------
            Variables
--------------------------------------------------------------------------*/
#define STATEBLOCK 100           /* Cells per block */
makestructure (newstate, free_state, printstate, STATE,
freestate, STATEBLOCK, "STATE", statecount);

/*----------------------------------------------------------------------
              F u n c t i o n s
----------------------------------------------------------------------*/
/**********************************************************************
 * bin_to_chunks
 *
 * Convert a representation of the search state in "STATE" form to one
 * in "SEARCH_STATE" form.  Create the memory required to hold the
 * resultant state value.
 **********************************************************************/
SEARCH_STATE bin_to_chunks(STATE *state, int num_joints) {
  int x;
  unsigned int mask;
  int depth;
  int pieces = 0;
  SEARCH_STATE s;

  s = memalloc (sizeof (int) * (ones_in_state (state, num_joints) + 1));

  depth = 1;
  mask = 1 << (num_joints - 1 - 32);
  for (x = num_joints; x > 32; x--) {
    if (state->part1 & mask) {
      s[depth++] = pieces;
      pieces = 0;
    }
    else {
      pieces++;
    }
    mask >>= 1;
  }

  if (num_joints > 32)
    mask = 1 << 31;
  else
    mask = 1 << (num_joints - 1);

  while (x--) {
    if (state->part2 & mask) {
      s[depth++] = pieces;
      pieces = 0;
    }
    else {
      pieces++;
    }
    mask >>= 1;
  }
  s[0] = depth - 1;

  return (s);
}


/**********************************************************************
 * bin_to_pieces
 *
 * Convert the binary (bit vector) format of a search state to an array
 * of piece counts. This array has a zero element after the last valid
 * character.
 **********************************************************************/
void bin_to_pieces(STATE *state, int num_joints, PIECES_STATE pieces) {
  int x;
  unsigned int mask;             /* Bit mask */
  inT16 num_pieces = 0;
  /* Preset mask */
  if (debug_8)
    print_state ("bin_to_pieces = ", state, num_joints);

  mask = ((num_joints > 32) ?
    (1 << (num_joints - 1 - 32)) : (1 << (num_joints - 1)));

  pieces[num_pieces] = 0;

  for (x = num_joints - 1; x >= 0; x--) {
                                 /* Iterate all bits */
    pieces[num_pieces]++;

    if ((x < 32) ?               /* Test for 1 bit */
      ((state->part2 & mask) ? TRUE : FALSE) :
    ((state->part1 & mask) ? TRUE : FALSE)) {
      pieces[++num_pieces] = 0;
      if (debug_8)
        cprintf ("[%d]=%d ", num_pieces - 1, pieces[num_pieces - 1]);
    }
    /* Next mask value */
    mask = ((mask == 1) ? (1 << 31) : (mask >> 1));
  }
  pieces[num_pieces]++;
  pieces[++num_pieces] = 0;
  ASSERT_HOST (num_pieces < MAX_NUM_CHUNKS + 2);
  if (debug_8)
    new_line();
}


/**********************************************************************
 * insert_new_chunk
 *
 * Add a new chunk division into this state vector at the location
 * requested.
 **********************************************************************/
void insert_new_chunk(register STATE *state,
                      register int index,
                      register int num_joints) {
  register unsigned int mask;
  register unsigned int result;

  index = (num_joints - index);
  if (index < 32) {
    mask = ~0;
    mask <<= index;
    result = (mask & state->part2) << 1;
    result |= (~mask & state->part2);
    state->part1 <<= 1;
    if (state->part2 & 0x80000000)
      state->part1 |= 1;
    state->part2 = result;
  }
  else {
    mask = ~0;
    mask <<= index - 32;
    result = (mask & state->part1) << 1;
    result |= (~mask & state->part1);
    state->part1 = result;
  }
}


/**********************************************************************
 * new_state
 *
 * Create a memory space for a new state variable.  Set its initial
 * value according to the parameters.
 **********************************************************************/
STATE *new_state(STATE *oldstate) {
  STATE *this_state;

  this_state = newstate ();
  this_state->part1 = oldstate->part1;
  this_state->part2 = oldstate->part2;
  return (this_state);
}


/*********************************************************************
 * ones_in_state
 *
 * Return the number of ones that are in this state.
 **********************************************************************/
int ones_in_state(STATE *state, int num_joints) {
  inT8 num_ones = 0;
  inT8 x;
  unsigned int mask;

  if (num_joints > 32)           /* Preset mask */
    mask = 1 << (num_joints - 1 - 32);
  else
    mask = 1 << (num_joints - 1);

  for (x = num_joints - 1; x >= 0; x--) {
                                 /* Iterate all bits */

    if (x < 32)
      num_ones += ((state->part2 & mask) ? 1 : 0);
    else
      num_ones += ((state->part1 & mask) ? 1 : 0);

    if (mask == 1)               /* Next mask value */
      mask = 1 << 31;
    else
      mask >>= 1;
  }

  return (num_ones);
}


/**********************************************************************
 * print_state
 *
 * Print out the current state variable on a line with a label.
 **********************************************************************/
void print_state(const char *label, STATE *state, int num_joints) {
  int x;
  unsigned int mask;             /* Bit mask */

  if (num_joints > 32)           /* Preset mask */
    mask = 1 << (num_joints - 1 - 32);
  else
    mask = 1 << (num_joints - 1);

  cprintf ("%s ", label);

  for (x = num_joints - 1; x >= 0; x--) {
                                 /* Iterate all bits */

    if (x < 32)
      cprintf ("%d", ((state->part2 & mask) ? 1 : 0));
    else
      cprintf ("%d", ((state->part1 & mask) ? 1 : 0));
    if (x % 4 == 0)
      cprintf (" ");

    if (mask == 1)               /* Next mask value */
      mask = 1 << 31;
    else
      mask >>= 1;
  }

  new_line();
}


/**********************************************************************
 * set_n_ones
 *
 * Set the first n bits in a state.
 **********************************************************************/
void set_n_ones(STATE *state, int n) {
  if (n < 32) {
    state->part2 = ~0;
    state->part2 >>= 32 - n;
    state->part1 = 0;
  }
  else {
    state->part2 = ~0;
    state->part1 = ~0;
    state->part1 >>= 64 - n;
  }
}


/**********************************************************************
 * compare_states
 *
 * Compare the 2 states at the given blob index. Return 1 if the given
 * blob is a fragment compared to reality, 2 if correct, 4 if a join,
 * and 5 if both a join and a fragment.
 * On return the blob index is set to the corresponding index in the
 * correct string.
 **********************************************************************/
int compare_states(STATE *true_state, STATE *this_state, int *blob_index) {
  int blob_count;                //number found
  int true_index;                //index of true blob
  int index;                     //current
  int result = 0;                //return value
  uinT32 mask;

  if (true_state->part1 == this_state->part1
    && true_state->part2 == this_state->part2)
    return 2;
  if (*blob_index == 0) {
    if (bits_in_states > 32) {
      for (mask = 1 << (bits_in_states - 33); mask != 0; mask >>= 1) {
        if (this_state->part1 & mask) {
          if (true_state->part1 & mask)
            return 2;
          else
            return 1;
        }
        else if (true_state->part1 & mask)
          return 4;
      }
      index = 31;
    }
    else
      index = bits_in_states - 1;
    for (mask = 1 << index; mask != 0; mask >>= 1) {
      if (this_state->part2 & mask) {
        if (true_state->part2 & mask)
          return 2;
        else
          return 1;
      }
      else if (true_state->part2 & mask)
        return 4;
    }
    return 2;
  }
  else {
    blob_count = 0;
    true_index = 0;
    if (bits_in_states > 32) {
      for (mask = 1 << (bits_in_states - 33); mask != 0; mask >>= 1) {
        if (true_state->part1 & mask)
          true_index++;
        if (this_state->part1 & mask) {
          blob_count++;
          if (blob_count == *blob_index) {
            if ((true_state->part1 & mask) == 0)
              result = 1;
            break;
          }
        }
      }
      if (blob_count == *blob_index) {
        for (mask >>= 1; mask != 0; mask >>= 1) {
          if (this_state->part1 & mask) {
            if ((true_state->part1 & mask) && result == 0)
              return 2;
            else
              return result | 1;
          }
          else if (true_state->part1 & mask)
            result |= 4;
        }
      }
      index = 31;
    }
    else
      index = bits_in_states - 1;
    mask = 1 << index;
    if (blob_count < *blob_index) {
      for (; mask != 0; mask >>= 1) {
        if (true_state->part2 & mask)
          true_index++;
        if (this_state->part2 & mask) {
          blob_count++;
          if (blob_count == *blob_index) {
            if ((true_state->part2 & mask) == 0)
              result = 1;
            break;
          }
        }
      }
      if (blob_count != *blob_index)
        return 2;
      mask >>= 1;
    }
    *blob_index = true_index;
    for (; mask != 0; mask >>= 1) {
      if (this_state->part2 & mask) {
        if ((true_state->part2 & mask) && result == 0)
          return 2;
        else
          return result | 1;
      }
      else if (true_state->part2 & mask)
        result |= 4;
    }
    return result == 0 ? 2 : result;
  }
}
