// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I

// class for grey scale for laserwriter

#include <defines.h>
#include <gf_lw.h>
#include <surface.h>

#include <ctype.h>
#include <iostream.h>
#include <stdlib.h>

// constructor
grey_font_laserwriter::grey_font_laserwriter(const uint16 width,
															const uint16 height) :
  grey_font(width, height)
{ bias = (w * h < 50 ? 65 : 0);
  heap_check(pr = new char* [w * h + 1]);
  _generate_squares();
}


// destructor
grey_font_laserwriter::~grey_font_laserwriter(void)
{ if (pr) then
  { for (int n = 0; n <= w * h; n++)
    { if (pr[n]) then
        delete [] pr[n];
    }
    delete [] pr;
  }
}

uint16 grey_font_laserwriter::_rebuild(const uint16 width, const uint16 height)
{ if (pr) then
  { for (int n = 0; n <= w * h; n++)
    { if (pr[n]) then
        delete [] (pr[n]);
    }
    delete [] pr;
  }

  w = width;
  h = height;
  bias = (w * h < 50 ? 65 : 0);

  heap_check(pr = new char* [w * h + 1]);

  font_number = ++fonts_created;

  _generate_squares();
  index = 0;

  return (width * height);
};

// private -- generate a memory map of a single square
void* grey_font_laserwriter::_generate_square(const uint16 n_black)
{ char *ptr;

  const int square_size = w * h,
            breakpoint = square_size / 2;

  int  n_marked = 0, put_value, n_to_do, default_value = 1;

// create the empty square and a pointer to it. Each byte can store eight
// bits
  const int octets_per_square = (w * h) / 8 + ( ( (w * h) % 8 ) ? 1 : 0 );

  heap_check(ptr = new char [octets_per_square]);    // CAREFUL!

// clear the characters
  for (int n = 0; n < octets_per_square; n++)
    ptr[n] = 0;
  
  if (n_black > breakpoint) then
  { for (int i = 0; i < w; i++)
      for (int j = 0; j < h; j++)
        _set_bit(ptr, i, j, default_value);
    put_value = 0;
    n_to_do = square_size - n_black;
  }
  else
  { put_value = default_value;
    n_to_do = n_black;
  }
  if (n_to_do)
  { for (int j = 1; n_marked < n_to_do; j++)
    { for (int i = 0; (i < square_size) && (n_marked < n_to_do); i++)
      { if ((_get_bit(ptr, i % w, i / w) != put_value) && 
            ((rand()  / (2147483648.0)) < (1.0 / (10.0 * w)))) 
        { _set_bit(ptr, i % w, i / w, put_value);
          n_marked++;
        }
      }
    }
  }
  return ptr;
}

// private -- generate memory versions of all the squares
void grey_font_laserwriter::_generate_squares(void)
{ for (int n_black = 0; n_black <= w * h; n_black++)
    pr[n_black] = _generate_square(n_black);
}

// private -- create the hex DREstring used to define a particular
// character
DREstring grey_font_laserwriter::_character_bitmap(const int n_black) 
{ byte image_byte[MAX_SIZE];

  char* ptr= pr[n_black];

  const int bytes_per_line = (w - 1) / 8 + 1,
                             total_bytes = bytes_per_line * h;

  DREstring rv;
  
  for (int n = 0; n < w * h; n++)
    image_byte[n] = 0;
  for (int row_nr = 0; row_nr < h; row_nr++)
    for (int column_nr = 0; column_nr < w; column_nr++)
    { if (_get_bit(ptr, column_nr, row_nr)) then
      { int byte_nr = row_nr * bytes_per_line + (column_nr / 8);
        image_byte[byte_nr] = image_byte[byte_nr] | (1 << (7 - (column_nr % 8)));
      }
    }

// convert the array to a DREstring of hex characters
  rv = DREstring(image_byte[0], "%2.2X");
  for (int byte_nr = 1; byte_nr < total_bytes; byte_nr++)
    rv += DREstring(image_byte[byte_nr], "%2.2X");

  return rv;
}

// private -- generate a single PostScript character
DREstring grey_font_laserwriter::_ps_character(const int n_black)
{ DREstring height_DREstring(h, 10), width_DREstring(w, 10), rv("/C");
  
  const int n = n_black + bias,
            n1 = n % 26,
            n2 = (n / 26) % 26;

  DREstring id;
  id += (char)(65 + n2);
  id += (char)(65 + n1);

  rv += id;
  DREstring space(" ");
  rv += (DREstring)" [1 0 0 " + width_DREstring + space + height_DREstring +
        space + width_DREstring + space + height_DREstring + (DREstring)" 0 0 <" +
        _character_bitmap(n_black) + (DREstring)">] def";

  return rv;
}

