/*->c.code */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>
#include <stdarg.h> 

#include "h.os"
#include "h.wimp"
#include "h.bbc"
#include "h.flex"
#include "h.swis"

#include "h.Drawlevel0"

#include "h.def"

#include "h.wos"
#include "h.main"
#include "h.mym"
#include "h.fsx"
#include "h.timex"

#include "h.strdef"
#include "h.buffer"

#include "h.tiff"

#include "h.code"

#include "h.g3"
#include "h.g4"
#include "h.g3dec"
#include "h.g4dec"


static os_error * cputeop(codestr * cx)
{
 os_error * err;

 err=NULL;

 switch(cx->type)
 {
  case TIFFCCITT3:
  case  FAXCCITT3:
                  err=g3j_eop(cx->bf);
                  break;

  case TIFFCCITT4:
                  err=g4j_encode_EOFB(cx->bf);
                  break;

  case  FAXCCITT4:
                  err=g4k_puteop(cx);
                  break;
 }

 return(err);
}


static os_error * cputline(codestr * cx,int pad,int copies)
{
 os_error * err;
 int        i;
 int        count;
 int        width;
 int        x;
 int        run;
 int        ic;
 int        runminus;
 int        runlimit;

 err=NULL;

 for(ic=0;ic<copies;ic++)
 {
  width=cx->width;

  switch(cx->type)
  {
   case TIFFCCITT3:
   case  FAXCCITT3:
                  count=g3outcount+pad;
                  x=0;
                  runlimit=cx->run;
                  runminus=runlimit-1;

                  if(!runlimit) err=g3j_encode_white(cx->bf,width);
                  else
                  for(i=0;i<cx->run;i++)
                  {
                   run=cx->runs[i++];
                   x+=run;
                   if(x>width)
                   {
                    run-=(x-width);
                    x=width;
                   }
                   else
                   if(i>=runlimit && x<width) run+=(width-x);

                   err=g3j_encode_white(cx->bf,run);

                   if(i<runlimit)
                   {
                    run=cx->runs[i];
                    x+=run;
                    if(x>width)
                    {
                     run-=(x-width);
                     x=width;
                    }
                    err=g3j_encode_black(cx->bf,run);

                    if(i==runminus && x<width) 
                    {
                     run=width-x;
                     g3j_encode_white(cx->bf,run);
                    }
                   }
                  }

                  if(cx->type==FAXCCITT3)
                  {
                   g3j_padnull(cx->bf,count-g3outcount);
                  }

                  err=g3j_encode_new_row(cx->bf);
                  cx->line++;
                  break;

  case TIFFCCITT4:                           /* No EOL's, no padding */
                  x=0;
                  runlimit=cx->run;
                  runminus=runlimit-1;

                  if(!runlimit) err=g4j_encode_white(cx->bf,width);
                  else
                  for(i=0;i<runlimit;i++)
                  {
                   run=cx->runs[i++];
                   x+=run;

                   if(x>width)
                   {
                    run-=(x-width);
                    x=width;
                   }
                   else
                   if(i>=runlimit && x<width) run+=(width-x);

                   err=g4j_encode_white(cx->bf,run);

                   if(i<runlimit)
                   {
                    run=cx->runs[i];
                    x+=run;
                    if(x>width)
                    {
                     run-=(x-width);
                     x=width;
                    }

                    err=g4j_encode_black(cx->bf,run);

                    if(i==runminus && x<width) 
                    {
                     run=width-x;
                     g4j_encode_white(cx->bf,run);
                    }
                   }
                  }

                  err=g4j_encode_new_row(cx->bf); 
                  cx->line++;
                  break;

   case  FAXCCITT4:
                  err=g4k_putline(cx,pad);
                  break;
  }
 }

 cx->run=0;

 return(err);
}


os_error * codefinit(codestr * cx)
{
 os_error * err;

 err=NULL;

 switch(cx->type)
 {
  case TIFFCCITT3:
  case  FAXCCITT3:
                  break;

  case TIFFCCITT4:
                  err=g4j_finit();
                  break;

  case  FAXCCITT4:
                  err=g4k_finit(cx);
                  break;
 }


 if(cx->runs && cx->allocated)
 {
  flex_free((flex_ptr)&cx->runs);
  cx->allocated=0;
 }

 return(NULL);
}


os_error * codeinit(codestr * cx)
{
 os_error * err;

 codefinit(cx);

 cx->line=0;

 err=NULL;

 switch(cx->type)
 {
  case TIFFCCITT3:
                  g3j_initialize(cx->putbyte);
                  break;

  case  FAXCCITT3:
                  g3j_initialize(cx->putbyte);
                  break;

  case TIFFCCITT4:
                  err=g4j_initialize(cx->putbyte,cx->width);
                  break;

  case  FAXCCITT4:
                  err=g4k_init(cx);
                  break;
 }


 if(!err && cx->newbuffer)
 {
  err=flex_alloce((flex_ptr)&cx->runs,sizeof(*(cx->runs))*(cx->width+8));
  if(!err) cx->allocated=1;
 }

 cx->run=0;

 cx->putline=(putlinefn)cputline;
 cx->puteop=(puteopfn)cputeop;

 return(err);
}


/***************************************************************************/


static os_error * cgetline(codestr * cx,int * eof)
{
 os_error * err;

 err=NULL;

 switch(cx->type)
 {
  case TIFFCCITT3:
                  err=g3i_getlineT(cx,eof);
                  break;

  case  FAXCCITT3:
                  err=g3i_getline(cx,eof);
                  break;

  case TIFFCCITT4:
                  err=g4i_getline(cx,eof);
                  break;

  case  FAXCCITT4:
                  err=g5i_getline(cx,eof);
                  break;
 }

 return(err);
}



os_error * decodefinit(codestr * cx)
{
 os_error * err;

 err=NULL;

 switch(cx->type)
 {
  case TIFFCCITT3:
  case  FAXCCITT3:
                  break;

  case TIFFCCITT4:
                  err=g4i_finit();
                  break;

  case  FAXCCITT4:
                  err=g5i_finit(cx);
                  break;
 }

 if(cx->runs && cx->allocated) 
 {
  flex_free((flex_ptr)&cx->runs);
  cx->allocated=0;
 }

 return(err);
}


os_error * decodeinit(codestr * cx)
{
 os_error * err;

 decodefinit(cx);

 cx->line=0;

 err=NULL;

 switch(cx->type)
 {
  case TIFFCCITT3:
  case  FAXCCITT3:
                  g3i_initialize(cx->width,cx->height,cx->getbyte,cx->bitrev);
                  break;

  case TIFFCCITT4:
                  err=g4i_initialize(cx->width,cx->height,
                                               cx->getbyte,cx->bitrev);
                  break;

  case  FAXCCITT4:
                  err=g5i_init(cx);
                  break;
 }


 if(!err && cx->newbuffer)
 {
  err=flex_alloce((flex_ptr)&cx->runs,sizeof(*(cx->runs))*(cx->width+8));
  if(!err) cx->allocated=1;
 }

 cx->run=0;

 cx->getline=(getlinefn)cgetline;

 return(err);
}



/***************************************************************************/

void codebitstart(codestr * cx)
{
 cx->run=0;
 cx->colour=1;
 cx->column=0;
 cx->crun=0;
}

void codebitend(codestr * cx)
{
 if(cx->colour==0) /* we are writing black */
 {
  cx->runs[cx->run++]=cx->crun;
  if(cx->column<cx->width) cx->runs[cx->run++]=cx->width-cx->column;
 }
 else              /* we are writing white */
 {
  if(cx->column<cx->width) cx->crun+=cx->width-cx->column;
  cx->runs[cx->run++]=cx->crun;
 }

}


void codebit(codestr * cx,int bit)
{
 if(cx->column<cx->width)
 {
  if(bit==cx->colour) cx->crun++;
  else
  {
   cx->runs[cx->run++]=cx->crun;

   cx->crun=1;
   cx->colour=bit;
  }
  cx->column++;
 }
}

