#include <itk/raster.h>
#include <itk/bit_count.h>
#include <ocr/find_chars.h>


#ifndef DO_OCR_INLINE
#include <ocr/find_chars.inl>
#endif


Char_Def::Char_Def()
{
  set_pos( 0, 0, 0, 0);
}

Char_Def::Char_Def( unsigned new_tl_x, unsigned new_tl_y
                  , unsigned new_br_x, unsigned new_br_y)
{
  set_pos( new_tl_x, new_tl_y, new_br_x, new_br_y);
}


Char_Def::Char_Def( Char_Def &rhs)
{
  copy( rhs);
}


Char_Def::Char_Def( const Char_Def &rhs)
{
  copy( rhs);
}


Char_Def::~Char_Def()
{
}


const Char_Def &
Char_Def::operator=( Char_Def &rhs)
{
  copy( rhs);
  return *this;
}


const Char_Def &
Char_Def::operator=( const Char_Def &rhs)
{
  copy( rhs);
  return *this;
}



Find_Chars::Find_Chars( unsigned new_min_line_size
                      , unsigned new_black_threshold)
: m_min_line_size( new_min_line_size)
, m_black_threshold( new_black_threshold)
{
}
 

Find_Chars::~Find_Chars()
{
}


bool
Find_Chars::find_chars( const Raster &raster)
{
  signed line_start = -1;
  signed line_end   = -1;

  m_page.resize( 0);
  while (find_line( raster, line_start, line_end)) {
    Char_Defs  vc;
    signed   char_start = -1;
    signed   char_end   = -1;
    while (find_char( raster, line_start, line_end, char_start, char_end)) {
      vc.push_back( Char_Def( char_start, line_start, char_end, line_end));
    }
    m_page.push_back( vc);
  }
  return m_page.size();
}


bool
Find_Chars::find_line( const Raster &raster
                     ,       signed &line_start
                     ,       signed &line_end)
{
  int ls;
  int i = line_end + 1;

  while (i < raster.height()) {
    while ((i < raster.height()) &&
           (bit_count( raster[ i], raster.width()) < black_threshold())) {
      ++i;
    }
    if (i < raster.height()) {
      ls = i;
      ++i;
      while ((i < raster.height()) &&
             (bit_count( raster[ i], raster.width()) >= black_threshold())) {
        ++i;
      }
      if ((i - ls) > min_line_size()) {
        line_start = ls;
        line_end   = i;
        return true;
      }
    }
  }
  return false;
}


bool
Find_Chars::find_char( const Raster &raster
                     ,       signed &line_start
                     ,       signed &line_end
                     ,       signed &char_start
                     ,       signed &char_end)
{
  int  i;
  int  j;
  int  cs = -1;

  for (i = char_end + 1; (cs < 0) && (i < raster.width()); ++i) {
    for (j = line_start; j < line_end; ++j) {
      if (raster[ j][ i / 8] & (1 << (7-(i & 0x07)))) {
        cs = i;
      }
    }
  }
  if (cs >= 0) {
    char_start = cs;
    for (i = cs + 1; i < raster.width(); ++i) {
      bool found = false;
      for (j = line_start; j < line_end; ++j) {
        if (raster[ j][ i / 8] & (1 << (7 - (i & 0x07)))) {
          found = true;
          break;
        }
      }
      if (!found) {
        char_end   = i;
        return true;
      }
    }
    char_start = cs;
    char_end   = raster.width();
    return true;
  }
  return false;
}
