#include <stdlib.h>
#include <string.h>

#include <tos.h>

#include "portab.h"
#include "treiber.h"

/***************************/
/* Version 1.0 von 10.2.93 */
/* Markus Pristovsek       */
/* Nur 240*216 dpi         */
/***************************/
/* Version 1.1 von 1.3.93  */
/* Alle Auflsungen, d.h.  */
/* hor.: 240,120,90,80,72  */
/* ver.: 216,144,72 dpi    */
/***************************/
/* Version 1.2 von 23.8.93 */
/* Drehen per Assembler    */
/***************************/
/* Version 1.3 von 7.10.95 */
/* Quer- und Hochkant in   */
/* einem Treibermodul      */
/***************************/

#define BITS_PER_CHAR	20	/* Elite-Dichte! */
#define COMPRESSION 2	/* Von 2 bis 0 (so lassen) */
#define MAX_DPI	240L
#define WEITE 1920	 /* Fr DINA3 vergrern! */
#define HOEHE -1	/* Unbeschrnkt */

static UBYTE	dpi_modus[]={ 240, 3, 120, 1, 90, 6, 72, 5 };
static UBYTE	dpi_vmodus[]={ 216, 3, 144, 2, 72, 1 };
static UBYTE	*INIT="\33@\33M\33\63\1\15";
static UBYTE	*V_STEP="\0\33J\0";

LONG	max_puffer_laenge = 1;	/* Nur Semaphore bekommen (=<128)! */


/********************************************************************/

/* Komprimiert eine Zeile */
void write_compressed( WORD th, UBYTE *tmp, LONG len, long bpc )
{
	LONG	i, j;

	if(  len>0  )
	{
#if COMPRESSION==2
		/* Schneidet nur links und rechts ab */
		/* Diese Routine sollte mit nahezu jedem Drucker gehen! */
		/* wenn man BITS_PER_CHAR (bpc) kennt! */
	
		for(  i=0;  i<len  &&  tmp[5+i]==0;  i++  )
			;
		while(  tmp[len+4]==0  &&  len>i  )
			len--;
		if(  i<len  )
		{
			for(  j=0;  j<i/bpc;  j++  )				Fwrite( th,  1L, " " );			j *= bpc;			len -= j;			tmp[3] = (UBYTE)(len % 256);
			tmp[4] = (UBYTE)(len / 256);
			Fwrite( th, 5, tmp );
			Fwrite( th, len, tmp+j+5 );
		}
#elif COMPRESSION==1
		/* Schneidet nur rechts ab */
		for(  i=len;  i>0  && tmp[i+5]==0;  i--  )
			;
		len--;
		if(  i>0  )
		{
			len = i;
			tmp[3] = (UBYTE)(len % 256);
			tmp[4] = (UBYTE)(len / 256);
			Fwrite( th, 5L+len, tmp );
		}
#else
		/* Und unkomprimiert! */
		Fwrite( th, 5L+len, tmp );
#endif
	}
	Fwrite( th, 2L, "\015\012" );
}

/********************************************************************/
/* Erst Quer (Landscape) */

/* Zwischenspeicher fr eine Zeile */static UBYTE	tmp1[WEITE+6L];static UBYTE	tmp2[WEITE+6L];static UBYTE	tmp3[WEITE+6L];static LONG	bit_table[]={	0x00800000L,0x00400000L,0x00200000L,0x00100000L,	0x00080000L,0x00040000L,0x00020000L,0x00010000L,	0x00008000L,0x00004000L,0x00002000L,0x00001000L,	0x00000800L,0x00000400L,0x00000200L,0x00000100L,	0x00000080L,0x00000040L,0x00000020L,0x00000010L,	0x00000008L,0x00000004L,0x00000002L,0x00000001L};/* Querdruck in 216, 144, 72 Dpi */WORD	drucke_quer( UBYTE *p, LONG start_x, LONG weite, LONG hoehe, LONG h_dpi, LONG v_dpi, WORD th, WORD flag )
{	LONG	max_spalte, max_zeile, zeile, lz;	LONG	len, bytes_per_row, offset, i, j, k;	UBYTE	t;
	for(  i=6;  i>0  &&  v_dpi>dpi_modus[i]*11/10;  i-=2  )
		;
	t = dpi_modus[i+1];
	v_dpi = dpi_modus[i];

	for(  i=6;  i>0  &&  h_dpi>dpi_vmodus[i]*11/10;  i-=2  )
		;
	h_dpi = dpi_vmodus[i];
	bytes_per_row = dpi_vmodus[i+1];

		/* Ab hier wird es ernst */	if(  hoehe>(WEITE*h_dpi)/MAX_DPI  )		max_spalte = (WEITE*h_dpi)/MAX_DPI;
	else		max_spalte = (hoehe*h_dpi)/MAX_DPI;
		/* Diverse Variablen initialisieren */	zeile = 0;	max_zeile = weite-start_x;	if(  HOEHE>0	&&	(max_zeile*v_dpi)/MAX_DPI>HOEHE  )
		max_zeile = ((HOEHE-start_x)*v_dpi)/MAX_DPI;
	weite = (weite+15L)/16L;	weite *= 2;		/* Reset + LQ-Mode */
	if(  flag&1  )		Fwrite( th, 8L, INIT );	/* Endlich drucken */	max_zeile--;	while(	max_zeile>0  &&  flag&2  )	{		for(  lz=0;  ist_next_leer( p+lz, weite, hoehe )  &&  lz*8<max_zeile;  lz++  )			;		if(	 lz>0	)		{	/* Leerzeilen berspringen */			zeile += lz*8;			p += lz;
			if(  zeile>max_zeile  )
				lz = max_zeile-(zeile-lz*8);
			lz = lz*8*3/bytes_per_row;	 		while(  lz>0  )			{				if(  lz>255  )					V_STEP[3] = 255;				else					V_STEP[3] = lz;				Fwrite( th, 4L, V_STEP );				lz -= 255;			}		}		if(  zeile>=max_zeile  )			break;		len = max_spalte;		if(  max_spalte<(WEITE*h_dpi)/MAX_DPI  )			offset = (WEITE*h_dpi)/MAX_DPI-max_spalte;		else			offset = 0;		tmp1[0] = '\033';		tmp1[1] = '*';		tmp1[2] = t;		switch(  (int)bytes_per_row  )		{			case 1:	for(  lz=0;  lz<len;  lz++  )								tmp1[4L+offset+len-lz] = p[lz*weite];							memset( tmp1+5, 0, offset );							write_compressed( th, tmp1, len+offset, (BITS_PER_CHAR*v_dpi)/MAX_DPI );							p += 1;						break;			case 2:	memset(  tmp1+5, 0, offset+len );							memcpy(  tmp2, tmp1, 5+offset+len );							for(  lz=0;  lz<len;  lz++  )							{								i = 256L*p[lz*weite]+p[lz*weite+1];								if(  i==0L  )									continue;								for(  j=8,k=0;  k<8;  k++  )								{									if(  (i&bit_table[j++])!=0L  )										tmp1[4L+offset+len-lz] |= bit_table[16+k];									if(  (i&bit_table[j++])!=0L  )										tmp2[4L+offset+len-lz] |= bit_table[16+k];								}							}							/* Komprimiert schreiben */							write_compressed( th, tmp1, len+offset, (BITS_PER_CHAR*v_dpi)/MAX_DPI );							write_compressed( th, tmp2, len+offset, (BITS_PER_CHAR*v_dpi)/MAX_DPI );							p += 2;						break;			case 3:	memset(  tmp1+5, 0, offset+len );							memcpy(  tmp2, tmp1, 5+offset+len );							memcpy(  tmp3, tmp1, 5+offset+len );							for(  lz=0;  lz<len;  lz++  )							{								i = p[lz*weite]*65536L+p[lz*weite+1]*256L+p[lz*weite+2];								if(  i==0  )									continue;								for(  j=k=0;  k<8;  k++  )								{									if(  (i&bit_table[j++])!=0  )										tmp1[4L+offset+len-lz] |= bit_table[16+k];									if(  (i&bit_table[j++])!=0  )										tmp2[4L+offset+len-lz] |= bit_table[16+k];									if(  (i&bit_table[j++])!=0  )										tmp3[4L+offset+len-lz] |= bit_table[16+k];								}							}							write_compressed( th, tmp1, len+offset, (BITS_PER_CHAR*v_dpi)/MAX_DPI );							write_compressed( th, tmp2, len+offset, (BITS_PER_CHAR*v_dpi)/MAX_DPI );							write_compressed( th, tmp3, len+offset, (BITS_PER_CHAR*v_dpi)/MAX_DPI );							p += 3;						break;		}		V_STEP[3] = 24-bytes_per_row;		Fwrite( th, 4L, V_STEP );		zeile += bytes_per_row*8;	}	/* Ende Seite */	if(  flag&4  )
		Fwrite( th, 2L, " \014" );

	return 0;}/* 17.1.93 */
/********************************************************************/
/* dann Hochkant (Portrait) */

WORD	drucke( UBYTE *p, LONG start_y, LONG weite, LONG hoehe, LONG h_dpi, LONG v_dpi, WORD th, WORD flag, WORD quer, UBYTE *option )
{
	LONG	modus, v_modus;
	LONG	max_spalte, zeile, lz, links, linker_rand, rechts;
	LONG	h_len, len, i;

	(void)option;	/* ignorieren */

	if(  th<-2  )
		th = (WORD)Fopen( "PRN:", FO_WRITE );

	if(  quer>0  )
		return drucke_quer( p, start_y, weite, hoehe, h_dpi, v_dpi, th, flag );

		/* Auflsung feststellen */
	for(  i=4;  i>0  &&  h_dpi>dpi_modus[i];  i-=2  )
		;
	modus = dpi_modus[i+1];
	h_dpi = dpi_modus[i];

	for(  i=6;  i>0  &&  v_dpi>dpi_vmodus[i]*11/10;  i-=2  )
		;
	v_dpi = dpi_vmodus[i];
	v_modus = dpi_vmodus[i+1];

		/* Ab hier wird es ernst */
	if(  weite<WEITE*h_dpi/MAX_DPI  )
		max_spalte = (weite+7)/8;
	else
		max_spalte = (WEITE*h_dpi)/(8*MAX_DPI);

	weite = (weite+15L)/16L;
	weite *= 2;
	if(  flag&1  )
		Fwrite( th, 8L, INIT ); /* Reset + Elite-Dichte + Zeilenabstand 1/216 */

	/* Linken Rand festlegen */
	for(  lz=0;  ist_next_leer( p+lz, weite, hoehe )  &&   lz<max_spalte;  lz++  )
		;
	linker_rand = lz;

	lz = links = 0;
	zeile = start_y;
	hoehe += start_y;

	/* Endlich drucken */
	while(  flag&2  )
 	{
 		/* Leerzeilen berspringen */
 		for(  lz=0;  ist_leerzeile( p, max_spalte )  &&  zeile<hoehe;  lz++, zeile++  )
 			p += weite;

		lz = links+(lz+lz+lz)/v_modus;
		while(  lz>0  )
		{
			if(  lz>255  )
				V_STEP[3] = 255;
			else
				V_STEP[3] = lz;
			Fwrite( th, 4L, V_STEP );
			lz -= 255;
		}
		if(  zeile>=hoehe  )
			break;

			/* Rnder feststellen */
 		for(  rechts=max_spalte-1;  ist_next_leer( p+rechts, weite, v_modus*8 )  &&  rechts>linker_rand;  rechts--  )
 			;
 		rechts++;
		/* Leerzeichen am linken Rand */
		for(  links=linker_rand;  ist_next_leer( p+links, weite, v_modus*8 )  &&   links<rechts;  links++  )
			;
		/*  gleichen Anfang festlegen */
		tmp1[0] = 27;
		tmp1[1] = '*';
		tmp1[2] = modus;
		h_len = links*8;
		len = 8*rechts;
		if(  h_len>0  )
			memset( tmp1+5, 0, h_len );
		tmp1[3] = (UBYTE)(len % 256);
		tmp1[4] = (UBYTE)(len / 256);

		/* 24 Zeilen (3x Druckkopfhhe an den Drucker! */
		/* Oder auch weniger bei geringerer Auflsung */
		for(  lz=0;  lz<v_modus;  lz++  )
		{
			block_it( tmp1+5+h_len, p+links, (WORD)(rechts-links), weite*v_modus, 1 );
			p += weite;
			/* Letzte Zeile gesondert behandeln */
			if(  zeile+v_modus*8+lz>=hoehe  )
			{
				int	bit, byte, and_it;

				bit = (int)((zeile+v_modus*8+lz - hoehe)/v_modus);
				and_it = (0x00FF<<(bit&7));
				for(  byte=0;  byte<len-h_len;  byte++  )
					tmp1[5L+h_len+byte] &= and_it;
			}
			write_compressed( th, tmp1, len, (h_dpi*BITS_PER_CHAR)/MAX_DPI );
  	}
		p += weite*v_modus*7L;
		links = 24-v_modus;
		if(  zeile+(8*v_modus)>=hoehe  )
			links = hoehe-zeile-v_modus;
		zeile += (8*v_modus);
 }

		/* Ende Seite */
  if(  (flag&4)  )
  {
  	if(  2!=Fwrite( th, 2L, " \014" )  )
	  	/* Platz reichte nicht aus */
			return -1;
  }
	return 0;
}
/* 17.1.93 */

