/*
 * $Id: hp500c.trm%v 3.50.1.11 1993/08/10 03:55:03 woo Exp $
 *
 */
/* GNUPLOT - hp500c.trm */
/*
 * Copyright (C) 1993
 *
 * Permission to use, copy, and distribute this software and its
 * documentation for any purpose with or without fee is hereby granted, 
 * provided that the above copyright notice appear in all copies and 
 * that both that copyright notice and this permission notice appear 
 * in supporting documentation.
 *
 * Permission to modify the software is granted, but not the right to
 * distribute the modified code.  Modifications are to be distributed 
 * as patches to released version.
 *  
 * This software  is provided "as is" without express or implied warranty.
 * 
 * This file is included by ../term.c.
 *
 * This terminal driver supports:
 *  hpdj 500c
 *
 * AUTHORS
 *  John Engels      -- \
 *  Russell Lang     ----> HPLJII.trm
 *  Maurice Castro   -- /
 *  UdoHessenauer    ----> derived this version from the above one
 *
 * send your comments or suggestions to (info-gnuplot@dartmouth.edu).
 * 
 */

/* The following HP Deskjet500c  driver uses generic bit mapped graphics
   routines from bitmap.c to build up a bit map in memory.  The driver
   interchanges colomns and lines in order to access entire lines
   easily and returns the lines to get bits in the right order :
   (x,y) -> (y,XMAX-1-x). */
/* This interchange is done by calling b_makebitmap() with reversed 
   xmax and ymax, and then setting b_rastermode to TRUE.  b_setpixel()
   will then perform the interchange before each pixel is plotted */
/* by John Engels JENGELS@BNANDP51.BITNET, inspired by the hpljet driver
   of Jyrki Yli-Nokari */

#ifdef HP500C

/* We define 4 different print qualities : 300ppi, 150ppi, 100ppi and
   75ppi.  (Pixel size = 1, 2, 3, 4 dots) */

#define HP500C_DPP (hpdj_dpp)   /* dots per pixel */
#define HP500C_PPI (300/HP500C_DPP) /* pixel per inch */
/* make XMAX and YMAX a multiple of 8 */
#define HP500C_XMAX (8*(unsigned int)(xsize*1920/HP500C_DPP/8.0+0.9))
#define HP500C_YMAX (8*(unsigned int)(ysize*1920/HP500C_DPP/8.0+0.9))

#define HP500C_VCHAR (HP500C_PPI/6) /* Courier font with 6 lines per inch */
#define HP500C_HCHAR (HP500C_PPI/10) /* Courier font with 10 caracters
per inch */

/* default values for term_tbl */
#define HP500C_75PPI_XMAX (1920/4)
#define HP500C_75PPI_YMAX (1920/4)
#define HP500C_75PPI_HCHAR (1920/4/6)
#define HP500C_75PPI_VCHAR (1920/4/10)
#define HP500C_75PPI_VTIC 5
#define HP500C_75PPI_HTIC 5


#define HP500C_PUSH_CURSOR fprintf(outfile,"\033&f0S") /* Save current
cursor position */
#define HP500C_POP_CURSOR fprintf(outfile,"\033&f1S") /* Restore
cursor position */
#define HP500C_COURIER fprintf(outfile,"\033(0N\033(s0p10.0h12.0v0s0b3T\033&l6D")
/* be sure to use courier font with 6lpi and 10cpi */

static int hpdj_dpp=4;
static int HP_COMP_MODE = 0;

/* bm_pattern not appropriate for 300ppi graphics */
#ifndef HPLJII
static unsigned int b_300ppi_pattern[] = {
  0xffff, 0x1111,
  0xffff, 0x3333, 0x0f0f, 0x3f3f, 0x0fff, 0x00ff, 0x33ff};
#endif


HP500Coptions()
{
  char opt[6];
  
#define HPDJCERROR "expecting dots per inch size 75, 100, 150 or 300 and/or compression method"
  while (!END_OF_COMMAND) {
    if (token[c_token].length>4)
      int_error(HPDJCERROR,c_token);
    
    /* almost_equals() won't accept numbers - use strcmp() instead */
    capture(opt,c_token,c_token);
    if (!strcmp(opt,"75")) {
      hpdj_dpp = 4;
      HP_COMP_MODE = 0;
    
}
    else if (!strcmp(opt,"100")) {
      hpdj_dpp = 3;
      HP_COMP_MODE = 0;
    }
    else if (!strcmp(opt,"150")) {
      hpdj_dpp = 2;
      HP_COMP_MODE = 0;
    }
    else if (!strcmp(opt,"300")) {
      hpdj_dpp = 1;
      HP_COMP_MODE = 0;
    }
    else if (!strcmp(opt,"rle")){
      HP_COMP_MODE = 1;
    }
    else if (!strcmp(opt,"tiff")){
      HP_COMP_MODE = 2;
    }
    c_token++;
  }
  
  term_tbl[term].xmax = HP500C_XMAX;
  term_tbl[term].ymax = HP500C_YMAX;
  switch(hpdj_dpp) {
  case 1:
    strcpy(term_options,"300");
    term_tbl[term].v_tic = 15;
    term_tbl[term].h_tic = 15;
    break;
  case 2:
    strcpy(term_options,"150");
    term_tbl[term].v_tic = 8;
    term_tbl[term].h_tic = 8;
    break;
  case 3:
    strcpy(term_options,"100");
    term_tbl[term].v_tic = 6;
    term_tbl[term].h_tic = 6;
    break;
  case 4:
    strcpy(term_options,"75");
    term_tbl[term].v_tic = 5;
    term_tbl[term].h_tic = 5;
    break; 
  }
  switch(HP_COMP_MODE) {
  case 0:
    strcat(term_options," no comp");
    break;
  case 1:
    strcat(term_options," RLE");
    break;
  case 2:
    strcat(term_options," TIFF");
    break;
  case 3:     /* not implemented yet */
    strcat(term_options," Delta Row");
    break;
  }
}

HP500Cinit()
{
#ifdef vms
	reopen_binary();
#endif /* vms */
#ifdef PC
	reopen_binary();
#endif /* PC */
}

HP500Creset()
{
#ifdef vms
	fflush_binary();
#endif
}



/* HP DeskJet 500c routines */

HP500Clinetype(linetype)
int linetype;
{
	if (linetype < 0)
		linetype = 7;
	else if (linetype >=8){
		linetype %=8;
	}
	switch (linetype){
	case 0 :
		linetype = 6;
		break;
	case 1 :
		linetype = 5;
		break;
	case 2 :
		linetype = 3;
		break;
	case 3 :
		linetype = 2;
		break;
	case 4 :
		linetype = 1;
		break;
	case 5 :
		linetype = 4;
		break;
	case 6 :
		linetype = 7;
	}
	b_setvalue(linetype);

}

/*
HP500Cpoint(x,y,value)
int x;
int y;
int value;
{
	 HP500Clinetype(value);
	 do_point(x,y,value);
}
*/

HP500Cgraphics()
{
	switch(hpdj_dpp) {
	case 1:
		b_charsize(FNT13X25);
		term_tbl[term].v_char = FNT13X25_VCHAR;
		term_tbl[term].h_char = FNT13X25_HCHAR;
		break;
	case 2:
		b_charsize(FNT13X25);
		term_tbl[term].v_char = FNT13X25_VCHAR;
		term_tbl[term].h_char = FNT13X25_HCHAR;
		break;
	case 3:
		b_charsize(FNT9X17);
		term_tbl[term].v_char = FNT9X17_VCHAR;
		term_tbl[term].h_char = FNT9X17_HCHAR;
		break;
	case 4:
		b_charsize(FNT5X9);
		term_tbl[term].v_char = FNT5X9_VCHAR;
		term_tbl[term].h_char = FNT5X9_HCHAR;
		break;
	}
	/* rotate plot -90 degrees by reversing XMAX and YMAX and by 
	setting b_rastermode to TRUE */
	b_makebitmap(HP500C_YMAX,HP500C_XMAX,3);
	b_rastermode = TRUE;
}
/*
 * Run-length encoding for the DeskJet. We have pairs of <count>
 * <what>, where count goes from 0 (meaning one count) to 255
 * this might double the size of the image.
 */

static int  compress(op, oe, cp)
unsigned char *op, *oe, *cp;
{
	unsigned char *ce = cp;
	while ( op < oe ) {
		unsigned char prevchar;
		unsigned char count;

		prevchar = *op;     /* remember char */
		count = 1;          /* its read the first time */

		while ( ++op < oe && *op == prevchar && count < 255){  /* set op to the next char */
			count++;                                             /* and count it  */
		}
		*ce++ = --count; /* were ready, so correct the count */
		*ce++ = prevchar; /* and store <what> */
	}
	*ce = 0;	  	/* just to be safe   */
	return ce - cp;    /* length of  cbufs */
}

unsigned char complement(c)
int c;
{
	return (unsigned char)(256 - c);
}


static int compress_to_TIFF(op,oe,cp)
     unsigned char *op;     /* original pointer */
     unsigned char *oe;     /* end of orig string */
     unsigned char *cp;     /* pointer for compressed data */
{
  unsigned char *countposition;
  unsigned char *ce = cp;
  while ( op < oe ) {
    unsigned char prevchar;
    unsigned char count;
    
    prevchar = *op;     /* gelesenes Zeichen aufbewaren */
    count = 1;          /* bisher wurde es einmal gelesen */
    
    while ( ++op < oe && *op == prevchar && count < 128){  
      count++;                                           
    }
    *ce = complement(count-1);
    countposition = ce++;           /* remember count for building blocks of literal bytes */
    *ce++ = prevchar;           
    
    if (count < 2) {      
      while(op < oe && (prevchar!=*op||*op != *(op + 1))){/* only use rle for at leat 3 equal bytes */
	
	*ce++ = *op;                                       
	count++;                                         
	prevchar = *op++;                              
	if (op > oe)
	  puts("FATAL op> oe!!\n");
      }
      if (op < oe && prevchar == *op){                             
	op--;                                           
	count--;                                       
	ce--;                                         
      }
      
      *countposition = count-1;                           
    }
  }
  return ce - cp;  
  
}

static int
nocompress(op,oe,cp)
     unsigned char *op;
     unsigned char *oe;
     unsigned char *cp;
{
  unsigned char *ce = cp;
  while(op < oe)
    *ce++ = *op++;
  return ce - cp;
}

/* 0 compression raster bitmap dump. Compatible with HP DeskJet 500
   hopefully compatible with other HP Deskjet printers */

HP500Ctext()
{
  register int x,j,row,count;
  char *obuf,*oe,*cbuf,*ce;
  
  if((obuf = (char *) malloc(100*b_psize))==0)
    puts("FATAL!-- couldn't get enough memory for obuf");
  if((cbuf = (char *) malloc(400*b_psize))==0)
    puts("FATAL!-- couldn't get enough memory for cbuf");
  
  oe = obuf;
  
  fprintf(outfile,"\033*t%dR", HP500C_PPI);
  fprintf(outfile, "\033*r1A");
  fprintf(outfile,"\033*b%1dM",HP_COMP_MODE);
  fprintf(outfile, "\033*r%dS",b_ysize);
  fprintf(outfile,"\033*r-3U");
  
  
  /* dump bitmap in raster mode */
  for (x = b_xsize-1; x >= 0; x--) {
    row = (b_ysize/8)-1;
    for (j = row; j >= 0; j-- ) {
      *oe++ =  (char)(*((*b_p)[j]+x));    
    }
    switch (HP_COMP_MODE){
    case 2 :
      count = compress_to_TIFF(obuf,oe,cbuf);
      break;
    case 1 :
      count = compress(obuf,oe,cbuf);
      break;
    case 0 :
      count = nocompress(obuf,oe,cbuf);
      break;
    }
    fprintf(outfile, "\033*b%dV", count);
    ce = cbuf;
    while(count--)
      fputc(*ce++,outfile);
    oe = obuf;
    
    for (j = row; j >=0; j-- ) {
      *oe++ = (char)(*((*b_p)[j+b_psize]+x));
    }
    switch (HP_COMP_MODE){
    case 2 :
      count = compress_to_TIFF(obuf,oe,cbuf);
      break;
    case 1 :
      count = compress(obuf,oe,cbuf);
      break;
    case 0 :
      count = nocompress(obuf,oe,cbuf);
      break;
      
    }
    
    fprintf(outfile, "\033*b%dV", count);
    ce = cbuf;
    while(count--)
      fputc(*ce++,outfile);
    oe = obuf;
    
    for (j = row; j >=0; j-- ) {
      *oe++ =  (char)(*((*b_p)[j+(2*b_psize)]+x));
    }
    switch (HP_COMP_MODE){
    case 2 :
      count = compress_to_TIFF(obuf,oe,cbuf);
      break;
    case 1 :
      count = compress(obuf,oe,cbuf);
      break;
    case 0 :
      count = nocompress(obuf,oe,cbuf);
      break;
    }
    fprintf(outfile, "\033*b%dW", count);
    ce = cbuf;
    while(count--)
      fputc(*ce++,outfile);
    oe = obuf;
    
  }
  fprintf(outfile, "\033*rbC");
  free(cbuf);
  free(obuf);  
  b_freebitmap();
  
#ifndef vms  /* most vms spoolers add a formfeed character */
  fprintf(outfile,"\f");
#endif /* not vms */
}

#define HP500Ctext_angle b_text_angle
#define HP500Cput_text b_put_text
#define HP500Cmove b_move
#define HP500Cvector b_vector

#endif /* HP500C */

