/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986,1987
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:dit3812.c 12.0$ */
/* $ACIS:dit3812.c 12.0$ */
/* $Source: /ibm/acis/usr/src/ibm/ditroff/dit3812/RCS/dit3812.c,v $ */

#ifndef lint
static char *rcsid = "$Header:dit3812.c 12.0$";
#endif

#include <stdio.h>
#include <ctype.h>
#include <utils.h>
#include <hash.h>
#include <trie.h>
#include <pmp/pmp.h>
#include <deviceattr.h>
#include <pmp/font3812.h>
#include <environ.h>
#include "setup_dit3812.h"
#include "ffont.h"
#include "info.h"

FILE  *infil;
FILE  *outfil;

static	struct dev	*printer=		NULL;
static	char       	*ptr_name= 		"3812";

	int		 d3_debug;
	int		 d3_bail=		FALSE;

static	int		 f_cursize=		0;
static	int		 f_szindex=		IF_ILLEGAL;
static	f_font		*f_curfont=		NULL;

static	int     	 f_newsize=    		0;
static	f_font		*f_newfont=     	NULL;
static	int     	 f_fntchanged=  	TRUE;

static	int		 pg_orient=    		P_PORTRAIT;

static	int 	 	 d3_tray=    		P_MAIN_TRAY;
static	int 	 	 d3_copies=  		1;
static	int 	 	 d3_pageknt= 		0;
static	int		 d3_pagenum=		1;

#define WHERE_AM_I	"dit3812.c"

/***============================================================***/

#define FFT_LOW		0
#define FFT_HIGH    	255
#define FFT_SIZE 	(FFT_HIGH-FFT_LOW+1)

static f_font	*d3_fft[FFT_SIZE];

#define fft_NdxOk(n)	(((n)>=FFT_LOW)&&((n)<=FFT_HIGH))
#define fft_Nth(n)	(fft_NdxOk(n)?(d3_fft[n]):NULL)
#define fft_Mount(f,n)	(fft_NdxOk(n)?((d3_fft[n]=(f)),TRUE):FALSE)

/***==================================================================***/

d3_NewFont(ndx)
register2 int    ndx;
{
register1 f_font *ftmp;

   D_ENTRY1(d3_debug,"d3_NewFont(%d)\n",ndx);
   ftmp= fft_Nth(ndx);
   if (!ftmp) {
      error1("Cannot activate %d, no font mounted\n",ndx);
      action("Font change ignored\n");
      RETURN(FALSE);
   }
   if (ftmp==f_newfont)
      RETURN(TRUE);
   f_fntchanged= TRUE;
   f_newfont= ftmp;
   RETURN(TRUE);
}

/***==================================================================***/

d3_NewSize(size)
register1 int     size;
{

   D_ENTRY1(d3_debug,"d3_NewSize(%d)\n",size);
   if (size<=0) {
      error1("Illegal size %d requested.\n",size);
      action("Size change ignored\n");
      RETURN(FALSE);
   }
   if (size==f_newsize)
      RETURN(TRUE);
   f_fntchanged= TRUE;
   f_newsize= size;
   RETURN(TRUE);
}

/***===================================================================***/

pmp_font *
d3_DeclareFont(font,size)
register3 f_font *font;
register4 int     size;
{
	   char		 tmp[100];
register1  pmp_font	*pfont;
register2  char  	*pname;

    D_ENTRY2(d3_debug,"d3_DeclareFont(%x,%d)\n",font,size);

    sprintf(tmp,ff_Codepage(font),size);
    pname= StrDup(tmp);
    pfont= p_fnt_open(pname,P_ACIS_FONT);
    if (pfont) {
	ff_FAdd(font,size,pfont);
    }
    RETURN(pfont);
}

/***===================================================================***/

f_font *
d3_InitFont(font)
register3 char *font;
{
register5 f_font *ffont;
register4 struct fontattr *fnt;
register2 char *cpage;
register1 char  *dot;
char  tmp[20];

   D_ENTRY1(d3_debug,"d3_InitFont(%x)\n",font);
   if (!printer) {
       printer= (struct dev *)u_malloc(sizeof(struct dev));
       if (!ip_Info(IP_ALL,printer))
          fatal("can't init printer\n");
   }

   fnt= if_Info(font);
   if (!fnt)
      RETURN(NULL);

   cpage= u_malloc(strlen(fnt->intname)+10);
   strcpy(cpage,fnt->intname);
   dot= rindex(cpage,'.');
   if (!dot)
      dot= rindex(cpage,'\0');
   strcpy(tmp,dot);
   strcpy(dot,".%d");
   strcat(dot,tmp);

   if (!(ffont= ff_Info(font))) {
       ff_Add(font,0,NULL);
       ffont= ff_Info(font);
   }
   ff_SetCodepage(ffont,cpage);
   RETURN(ffont);
}

/***===================================================================***/

static short *sq_sizes=NULL;

pmp_font *
d3_Squeeze(font,size)
register1 f_font *font;
register2 int     size;
{
register3 int		 knt;
register4 pmp_font	*pfont;
register5 int		 ndx;

    D_ENTRY2(d3_debug,"d3_Squeeze(0x%x,%d)\n",font,size);
    if (!sq_sizes) {
	sq_sizes= ip_Sizes();
    }
DEBUG2(d3_debug,1,"looking for font %s at %d\n",ff_Name(font),size);
    ndx= ip_Info(IP_SIZE,size);
    if (ndx!=IF_ILLEGAL) {
	for (knt=ndx;knt>=0;knt--) {
	    pfont= d3_DeclareFont(font,sq_sizes[knt]);
DEBUG2(d3_debug,1,"size %d= 0x%x\n",sq_sizes[knt],pfont);
	    if (pfont) {
		RETURN(pfont);
	    }
	}
	for (knt=ndx+1;sq_sizes[knt];knt++) {
	    pfont= d3_DeclareFont(font,sq_sizes[knt]);
DEBUG2(d3_debug,1,"size %d= 0x%x\n",sq_sizes[knt],pfont);
	    if (pfont) {
		RETURN(pfont);
	    }
	}
    }
DEBUG(d3_debug,1,"oh well.  nothing found\n");
    RETURN(NULL);
}

/***==================================================================***/

d3_CheckFont()
{
register1 pmp_font	*pfont;

   D_ENTRY(d3_debug,"d3_CheckFont()\n");
   if (!f_newfont)
      fatal("Need an active font to print. (shouldn't happen)\n");

   if (f_newsize==0)
      fatal("Need a font size to print. (shouldn't happen)\n");

   f_curfont= f_newfont;
   f_cursize= f_newsize;
   f_szindex= ip_Info(IP_SIZE,f_cursize);
   if (f_szindex==IF_ILLEGAL)
       WSGO1("d3_CheckFont -- point size %d has no index\n",f_cursize);
   f_fntchanged= FALSE;

   pfont= ff_PFont(f_newfont,f_newsize);

   if (!pfont)
      pfont= d3_DeclareFont(f_newfont,f_newsize);

   if (!pfont) {
       pfont= d3_Squeeze(f_newfont,f_newsize);
       if (pfont) {
	   ff_FAdd(f_newfont,f_newsize,pfont);
       }
       else {
	   error3("Can't activate printer font %x (%s at %d)\n",
				pfont,ff_Name(f_newfont),f_newsize);
	   action("Font change ignored\n");
	   RETURN(FALSE);
       }
   }
   p_fnt_activate(pfont);
   RETURN(TRUE);
}

/***==================================================================***/

d3_DeviceCommand(infil)
register1 FILE  *infil;
{
int    itmp;
int    itmp2,itmp3;
char   cmd[40];
char   str[100];
register2 f_font *ftmp;

   D_ENTRY1(d3_debug,"d3_DeviceCommand(%x)\n",infil);
   fscanf(infil,"%s",cmd);
   switch (cmd[0]) {
      when 'T': /*** NAME OF TYPESETTER IS 's' ***/
                fscanf(infil,"%s",str);
		ptr_name= "3812";
                if      (StrMatch(str,"3812"))	  pg_orient=P_PORTRAIT;
                else if (StrMatch(str,"3812-l"))  pg_orient=P_RIGHT_LANDSCAPE;
                else if (StrMatch(str,"3812-r"))  pg_orient=P_LEFT_LANDSCAPE;
                else if (StrMatch(str,"3812-inv")) pg_orient=P_INVERTED;
                else {
                    pg_orient= P_PORTRAIT;
		    ptr_name= (char *)u_malloc(strlen(str)+1);
		    strcpy(ptr_name,str);
                }
		sprintf(str,DIT_FONT_DIR,ptr_name);
		p_add_dir(str);
   		ip_Load(ptr_name,NULL);
      when 'i': /*** INIT ***/
		p_open(outfil);
                p_rotate(pg_orient);
		p_set_display(1);
      when 'r': /*** RESOLUTION IS 'n'/INCH           ***/
                /*** MINIMUM HORIZONTAL MOTION IS 'h' ***/
                /*** MINIMUM VERTICAL MOTION IS 'v'   ***/
                fscanf(infil,"%d %d %d",&itmp,&itmp2,&itmp3);
                if (itmp!=240) {
                   error1("Document prepared for %d pels/inch\n",itmp);
                   action("I'll do my best.  (should be 240)\n");
                }
                if (itmp2!=1) {
                   error1("Prepared for %d pels horizontal resolution",itmp);
                   action("I'll do my best.  (should be 1)\n");
                }
                if (itmp3!=1) {
                   error1("Prepared for %d pels vertical resolution",itmp);
                   action("I'll do my best.  (should be 1)\n");
                }
      when 'p': /*** PAUSE (CAN RESTART) ***/
                warning("Pause requested\n");
                action("Ignored\n");
      when 's': /*** STOP -- DONE FOREVER ***/
                /***       NO ACTION      ***/
      when 't': /*** GENERATE TRAILER ***/
		p_eject(TRUE);
		d3_pageknt+= d3_copies;
		p_set_display(d3_pagenum++);
		p_close();
      when 'f': /*** FONT POSITION 'n' CONTAINS FONT 's' ***/
                fscanf(infil,"%d",&itmp);
                fscanf(infil,"%s",str);
		if (isdigit(str[0])) 
		    ftmp= fft_Nth(atoi(str));
		else {
		    ftmp= ff_Info(str);
		    if (ftmp==NULL) {
			ftmp= d3_InitFont(str);
		    }
		}

                if (ftmp) {
                   if (!fft_Mount(ftmp,itmp)) {
		       warning2("Trying to mount %s at %d\n",str,itmp);
		       action("Illegal index, request ignored.\n");
                   }
		}
		else {
		    warning2("Trying to mount %s at %d\n",str,itmp);
		    if (isdigit(str[0])) 
			action1("No font at %d, request ignored\n",atoi(str));
		    else
			action("Unknown font, request ignored.\n");
		}
      when 'H': /*** SET CHARACTER HEIGHT TO 'n' ***/
                fscanf(infil,"%d",&itmp);
                error1("Attempt to set character height to %d\n",itmp);
                action("Ignored.\n");
      when 'S': /*** SET SLANT TO 'n' ***/
                fscanf(infil,"%d",&itmp);
                error1("Attempt to set slant to %d\n",itmp);
                action("Ignored.\n");
      otherwise:error1("Unknown device command %s encountered\n",cmd);
                action("Ignored.\n");
   }
   while (getc(infil)!='\n');
   RETURN(TRUE);
}

/***==================================================================***/

d3_DrawCommand(infil)
register1 FILE   *infil;
{
char  cmd[20];
int   itmp,itmp2,itmp3,itmp4;
static int beenhere= FALSE;

    D_ENTRY1(d3_debug,"d3_DrawCommand(%x)\n",infil);
    if (!beenhere) {
       p_vec_set_width(2);
       v_set_dflt_width(2);
    }
    fscanf(infil,"%s",cmd);
    switch (cmd[0]) {
       when 'l':	/*** DRAW LINE FROM CURRENT POSITION BY dh dv ***/
                  	fscanf(infil,"%d %d",&itmp,&itmp2);
			if ( itmp == 0 && itmp2 == 0 )
			{
				p_vec_relative (1,0);
				p_mv_relative (-1,0);
			}
                  	else p_vec_relative(itmp,itmp2);
       when 'c':  	/*** DRAW CIRCLE OF DIAMETER 'd' TO RIGHT ***/
                  	fscanf(infil,"%d",&itmp);
			circle(itmp/2);
       when 'e':  	/*** DRAW ELLIPSE OF DIAMETERS d1 d2 ***/
                  	fscanf(infil,"%d %d",&itmp,&itmp2);
			ellipse(itmp,itmp2);
       when 'a':  	/*** DRAW ARC where dh dv and dh2 dv2 define arc ***/
                  	fscanf(infil,"%d %d %d %d",&itmp,&itmp2,&itmp3,&itmp4);
                  	d2cirarc(itmp,itmp2,itmp3,itmp4);
       when '~':  	/*** DRAW B-SPLINE TO dh1 dv1, THEN TO dh2 dv2 ... ***/
			spline(infil); 
			/*** Original code no longer needed, now that splines
			 *** have been implemented
			{
				register2 char  ch;
				warning("Spline requested\n");
				action("Cursor updated, but nothing drawn\n");
				while (TRUE) {
					do { 
						ch = getc(infil);
					} while (isspace(ch)&&(ch !='\n'));
					if (ch=='\n') return(TRUE);
					else ungetc(ch,infil);
					fscanf(infil,"%d %d",&itmp,&itmp2); 
					p_mv_relative(itmp,itmp2);
				}
			}
			***/
       otherwise: 	error1("Unknown drawing command %s encountered\n",cmd);
                  	action("Ignored.\n");
    }
    while (getc(infil)!='\n');
    RETURN(TRUE);
}

/***===================================================================***/

d3_PrintChar(ch)
register1 char  *ch;
{
register2 int		 tmp;
register3 char		*fname;
struct	  charinfo	 tch;
register4 f_font	*old_font= NULL;
register5 f_font	*new_font= NULL;

   D_ENTRY1(d3_debug,"d3_PrintChar(%s)\n",ch);
   fname= ff_Name(f_curfont);
   tmp= ic_Info(fname,ch,IC_ALL,&tch);
   if (tmp==IC_NOTFOUND) {
       char *newname;

       tmp= ic_Search(fname,&newname,ch,IC_ALL,&tch);
       if (tmp==IC_NOERROR) {
DEBUG1(d3_debug,1,"newname= %s\n",newname);
	   old_font= f_curfont;
	   new_font= ff_Info(newname);
	   if (new_font) {
	       f_fntchanged= TRUE;
               f_newfont= new_font;
	       d3_CheckFont();
	       tmp= ic_Info(ff_Name(new_font),ch,IC_ALL,&tch);
	   }
	   else WSGO1("d3_PrintChar can't find printer font %s\n",newname);
       }
   }
   switch (tmp) {
       when IF_NOTFOUND:   WSGO2("d3_PrintChar -- %s IF_NOTFOUND on %s\n",ch,
	       							       fname);
       when IC_ILLEGAL:	   WSGO2("d3_PrintChar -- %s IC_ILLEGAL on %s\n",ch,
								       fname);
       when IC_NOTFOUND:   error2("character %s not defined on font %s\n",ch,
								       fname);
			   action("ignored.\n");
       otherwise:	   if ((StrMatch(ch,"\\|")||StrMatch(ch,"\\^")))
				/* just a horizontal motion */;
			   else {
				 p_putchar(tch.code);
				 p_mv_h_relative(-tch.widths[f_szindex]);
			   }
   }
   if (new_font) {
       f_fntchanged= TRUE;
       f_newfont= old_font;
   }
   RETURN(TRUE);
}

/***==================================================================***/

static int firstpage=TRUE;

d3_ReadCommands(infil)
register1 FILE  *infil;
{
register2 int    ch;
char  sname[3];
int   itmp,tmpi;

   D_ENTRY1(d3_debug,"d3_ReadCommands(%x)\n",infil);
   while (((ch=getc(infil))!=EOF)&&!d3_bail) {
     switch(ch) {
	 when 'f':       /* SWITCH TO FONT MOUNTED AT 'n' */
	      fscanf(infil,"%d",&itmp);
	      d3_NewFont(itmp);
	 when 's':       /* SWITCH TO SIZE 'n'           */
	      fscanf(infil,"%d",&itmp);
	      d3_NewSize(itmp);
	 when 'C':       /* PRINT SPECIAL CHARACTER NAMED 's' */
	      fscanf(infil,"%2s",sname);
              if (f_fntchanged)
	         d3_CheckFont();
	      d3_PrintChar(sname);
	 when 'c':       /* PRINT ASCII CHARACTER 'c' */
	      fscanf(infil,"%1s",sname);
              if (f_fntchanged)
	         d3_CheckFont();
	      d3_PrintChar(sname);
	 when 'H':       /* MOVE HORIZONTALLY TO 'x' */
	      fscanf(infil,"%d",&itmp);
	      p_mv_h_absolute(itmp);
	 when 'V':       /* MOVE VERTICALLY TO 'y' */
	      fscanf(infil,"%d",&itmp);
	      p_mv_v_absolute(itmp);
	 when 'h':       /* MOVE HORIZONTALLY BY 'dh' */
	      fscanf(infil,"%d",&itmp);
	      p_mv_h_relative(itmp);
	 when 'v':       /* MOVE VERTICALLY BY 'dv' */
	      fscanf(infil,"%d",&itmp);
	      p_mv_v_relative(itmp);
                         /* END OF LINE (INFORMATION ONLY) */
	 when 'n':       /* SPACE BEFORE 'b', AFTER 'a'    */
	      fscanf(infil,"%d %d",&itmp,&tmpi);
	 when 'p':       /* NEW PAGE 'n' BEGINS */
	      fscanf(infil,"%d",&itmp);
	      if (firstpage)
	           firstpage= FALSE;
	      else p_eject(TRUE);
	      p_set_display(d3_pagenum++);
	      d3_pageknt+= d3_copies;
	 when 'w':       /* PADDABLE WORD SPACE (INFO ONLY) */
	      /*tr_WordSpace();*/
	 when 'x':       /* DEVICE CONTROL FUNCTIONS */
	      d3_DeviceCommand(infil);
	 when 'D':       /* DRAWING FUNCTIONS (GRAPHICS) */
	      d3_DrawCommand(infil);
	 otherwise:      /* COULD BE 'nnc': MOVE 'nn', PRINT 'c' */
	      if (isspace(ch)) break;
	      if (isdigit(ch)) {
		 ungetc(ch,infil);
		 fscanf(infil,"%2d%c",&itmp,sname);
		 if (sname[0]==' ') {
		     strcpy(sname,"SP");
		 }
		 else sname[1]= '\0';
                 p_mv_h_relative(itmp);
                 if (f_fntchanged)
		    d3_CheckFont();
		 d3_PrintChar(sname);
		 break;
	      }
	      error2("Unknown command %c (%o)\n",ch,ch);
	      d3_bail= TRUE;
     }
   }
   if (d3_bail) {
	p_set_display(d3_pagenum);
	p_eject(TRUE);
	p_close();
   }
   RETURN(!d3_bail);
}

/***===================================================================***/

static env_enum
	    tray[]= {
	{"main_tray", P_MAIN_TRAY}, {"alt_tray", P_ALTERNATE_TRAY},{NULL, 0}
	    };

d3_Init(env,in,out)
register1 environ *env;
register2 FILE    *in;
register3 FILE    *out;
{

    D_ENTRY3(d3_debug,"d3_Init(0x%x,0x%x,0x%x)\n",env,in,out);
    infil= in;
    outfil= out;
#ifdef DEBUG_UTILS
    {
    register4 char *pmp_debug;
    pmp_debug= env_String(env,"pmp_debug",NULL);
    if (pmp_debug)
       p_set_debug(pmp_debug);
    }
#endif /* DEBUG_UTILS */
    p_open(outfil);
    d3_tray=   	env_SetVal(env,	tray,			DFL_TRAY);
    d3_copies= 	env_Int(env,	"copies",		1);
    p_set_copies(d3_copies);
    RETURN(TRUE);
}

/***==================================================================***/

d3812(env,in,out)
register1 environ *env;
register2 FILE    *in;
register3 FILE    *out;
{

    D_ENTRY3(d3_debug,"d3812(0x%x,0x%x,0x%x)\n",env,in,out);
    d3_Init(env,in,out);
    d3_ReadCommands(infil);
    RETURN(d3_pageknt);
}
