/*
 * asc2fax.c
 *
 * Copyright (C) 1993 by Olaf 'Rhialto' Seibert. All rights reserved.
 *
 * V24.05.93: Initial release
 * V29.05.93: Fixed unsigned character bug
 *
 * $Id: asc2fax.c,v 1.2 1993/06/11 16:33:37 Rhialto Exp $
 * $Log: asc2fax.c,v $
 * Revision 1.2  1993/06/11  16:33:37  Rhialto
 * First real RCS checkin
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define INTUI_V36_NAMES_ONLY
#include <utility/tagitem.h>
#include <intuition/intuition.h>
#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>
#include <clib/diskfont_protos.h>

#include "faxfile.h"
#include "debug_proto.h"

#define RASTERWIDTH LINE_BITS
#define ESC	    "\33"
#define CSI	    "\233"
#define uchar(x)    ((unsigned char)(x))

extern int FaxFine;

void OpenFaxFile(int);
void dochar(char);
int		verbose;
int		xoffset = 0;
int		yoffset = 0;
int		invert;
void	       *IntuitionBase;
void	       *GfxBase;
void	       *DiskFontBase;
struct BitMap	BitMap;
struct RastPort EmergencyRastPort;
struct RastPort *RastPort;
struct Window  *Window = 0;
struct TextFont *Font;
struct TextFont *OldFont;
struct NewWindow NewWindow = {
    0, 20,		    /* LeftEdge, TopEdge */
    640, 0,		    /* Width, Height (calculated and set) */
    1, 1,		    /* DetailPen, BlockPen */
    0,			    /* IDCMPFlags */
    WFLG_SUPER_BITMAP | WFLG_GIMMEZEROZERO | WFLG_NOCAREREFRESH |
	WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_SIZEGADGET | WFLG_SIZEBRIGHT, /* Flags */
    NULL,		    /* FirstGadget */
    NULL,		    /* CheckMark */
    NULL,		    /* Title */
    NULL,		    /* Screen */
    &BitMap,		    /* BitMap */
    20,20, -1,0,	    /* Min/Max Width/Height */
    WBENCHSCREEN	    /* Type */
};
struct TagItem TextTags[] = {
    TA_DeviceDPI, X_DPI | Y_DPI << 16,
    TAG_END
};

char fontWanted[100] = "courier.font";

struct TTextAttr TextAttr = {
    fontWanted, 30, FSF_TAGGED, 0, TextTags
};

void
meminvert(unsigned char *d, int size)
{
    if (((long) d & 0x01) == 0) {
	while (size >= 4) {
	    *(long *)d ^= 0xFFFFFFFF;
	    d += 4;
	    size -= 4;
	}
    }
    while (size > 0) {
	*d++ ^= 0xFF;
	size--;
    }
}

struct TextInfo {
    struct RastPort *rp;
    int 	    xoffset;
} ti;

unsigned char  *
DoText(unsigned char *text, int len)
{
    if (len > 0)
	Text(ti.rp, text, len);
    return text + len;
}

unsigned char  *
DoCSI(unsigned char *text)
{
    int 	    arg[8];
    int 	    narg = 0;
    int 	    i;

    memset(arg, 0, sizeof(arg));
    /* CSI 0 x and CSI x are indistinguishable */
    for(;;text++) {
	while (isdigit(text[0])) {
	    if (narg < 8) {
		arg[narg] *= 10;
		arg[narg] += text[0] - '0';
	    }
	    text++;
	}
	narg++;
	if (text[0] != ';')
	    break;
    }
    if (narg > 8)
	narg = 8;

    switch (*text++) {
    case 'm':   /* Select graphic rendition */
	for (i = 0; i < narg; i++) {
	    switch (arg[i]) {
	    case 0:	/* plain */
		SetSoftStyle(ti.rp, FS_NORMAL, FSF_BOLD|FSF_ITALIC|FSF_UNDERLINED);
		SetDrMd(ti.rp, JAM1);
		break;
	    case 1:	/* bold */
		SetSoftStyle(ti.rp, FSF_BOLD, FSF_BOLD);
		break;
	    case 3:	/* italic */
		SetSoftStyle(ti.rp, FSF_ITALIC, FSF_ITALIC);
		break;
	    case 4:	/* underline */
		SetSoftStyle(ti.rp, FSF_UNDERLINED, FSF_UNDERLINED);
		break;
	    case 7:	/* inverse video */
		SetDrMd(ti.rp, JAM1 | INVERSVID);
		break;
	    case 22:	 /* not bold */
		SetSoftStyle(ti.rp, 0, FSF_BOLD);
		break;
	    case 23:	 /* not italic */
		SetSoftStyle(ti.rp, 0, FSF_ITALIC);
		break;
	    case 24:	 /* not underline */
		SetSoftStyle(ti.rp, 0, FSF_UNDERLINED);
		break;
	    case 27:	 /* not inverse video */
		SetDrMd(ti.rp, JAM1);
		break;
	    }
	}
	break;
    case 'x':           /* set left offset */
	ti.xoffset = arg[0];
	break;
    }

    return text;
}

unsigned char  *
DoCtrl(unsigned char *text)
{
    switch (*text++) {
    case '\t':          /* tab */
	{
	    int 	    charpos;

	    charpos = (ti.rp->cp_x - ti.xoffset) / ti.rp->TxWidth;
	    charpos = (charpos + 8) & ~7;
	    Move(ti.rp, ti.xoffset + charpos * ti.rp->TxWidth, ti.rp->cp_y);
	}
	break;
    case '\n':          /* newline */
	Move(ti.rp, ti.xoffset, ti.rp->cp_y + ti.rp->TxHeight);
	break;
    case '\f':          /* formfeed */
	SetRast(ti.rp, 0);
	Move(ti.rp, ti.xoffset, ti.rp->TxBaseline);
	break;
    case uchar('\233'): /* control sequence introducer */
	goto csi;
    case '\033':        /* escape */
	switch (*text++) {
	case '#':
	  text++;
	  break;
	case 'c':       /* reset */
	    ti.xoffset = 0;
	    ti.rp->Mask = 0x0001;
	    SetAPen(ti.rp, 1);
	    SetBPen(ti.rp, 0);
	    DoCtrl("\f");
	    DoCSI("0m");
	    break;
	case '[':       /* CSI */
	csi:
	    text = DoCSI(text);
	    break;
	}
	break;
    }

    return text;
}

void
WinWrite(unsigned char *text)
{
    while (*text) {
	unsigned char  *p;
	int		len;

	/* First, determine how much real text we have */
	for (len = 0, p = text; isprint(*p); p++) {
	    len++;
	}
	text = DoText(text, len);
	if (*text && !isprint(*text))
	    text = DoCtrl(text);
    }
}

void WinWriteInit(void)
{
    ti.rp = RastPort;
    DoCtrl(ESC"c");
}

static int cp = 0;

void finalizeDoChar(void) {
  if (cp) dochar('\n');
}

void initializeDoChar(void) {
  cp = 0;
}

void dochar(char c) {
  static unsigned char line[512];
  extern void* FaxHandle;
  unsigned char  *plane;
  struct RastPort *rp = RastPort;
  int i;

  switch (c) {
  case 0:
    break;
  case '\r':
    /* printf("Got <cr>\n"); */
    break;
  case '\n':
    line[cp] = '\0';
    /* printf("line=%s\n", line); */

    if (!FaxHandle) {
      OpenFaxFile(1); /* signal that we started printing text first */
    }

    WinWrite("\f");
    WinWrite(line);
    if (Window)
      SyncSBitMap(rp->Layer);
    plane = BitMap.Planes[0];

    if (FaxHandle) {
      for (i = 0; i < Font->tf_YSize; i++) {
	if (invert)
	  meminvert(plane, BitMap.BytesPerRow);
	tofax(FaxHandle, plane, RASTERWIDTH);
	plane += BitMap.BytesPerRow;
	if (!FaxFine) {
	  plane += BitMap.BytesPerRow; /* decimate -- skip the next row */
	  i++;
	}
      }
    }
    cp = 0;
    break;
  default:
    // printf("dochar('%c')\n", c);
    line[cp++] = c;
    break;
  }
}

void
openall(void)
{
  char* userDefinedFont = 0;
  char* userDefinedFontSize = 0;

  /* Libraries */
  IntuitionBase = OpenLibrary("intuition.library", 33);
  if (IntuitionBase == NULL) {
    printf("Needs intuition V33+.\n");
    showError('e', "Needs intuition V33+.");
    exit(10);
  }
  GfxBase = OpenLibrary("graphics.library", 33);
  if (GfxBase == NULL) {
    printf("Needs gfx V33+.\n");
    showError('e', "Needs gfx V33+.");
    exit(10);
  }
  DiskFontBase = OpenLibrary("diskfont.library", 34);
  if (DiskFontBase == NULL) {
    printf("Needs diskfont V34+.\n");
    showError('e', "Needs diskfont V34+.");
    exit(10);
  }
  
  userDefinedFont = (char*)getenv("AVMFAXFONT");
  userDefinedFontSize = (char*)getenv("AVMFAXFONTSIZE");
  
  if (userDefinedFont) strcpy(fontWanted, userDefinedFont);
  if (userDefinedFontSize) TextAttr.tta_YSize = atoi(userDefinedFontSize);

  /* Font for window; sorry for the strange order */
  printf("Opening DiskFont... (This may take a while)\n");
  showError('x', "Opening DiskFont... (This may take a while)");
  Font = OpenDiskFont((struct TextAttr *)&TextAttr);
  if (Font == NULL) {
    printf("No font %s/%d!\n", TextAttr.tta_Name, TextAttr.tta_YSize);
    showError('e', "No font %s/%d!", TextAttr.tta_Name, TextAttr.tta_YSize);
    
    strcpy(fontWanted, "CGTimes.font");
    printf("Opening CGTimes DiskFont... (This may take a while)\n");
    showError('e', "Opening CGTimes DiskFont... (This may take a while)");

    Font = OpenDiskFont((struct TextAttr*)&TextAttr);
    if (Font == NULL) {
      printf("No font %s/%d!\n", TextAttr.tta_Name, TextAttr.tta_YSize);
      showError('e', "No font %s/%d!", TextAttr.tta_Name, TextAttr.tta_YSize);
      printf("Cannot contuine.\n");
      showError('e', "Cannot contuine.");
      exit(10);
    }
  }

  NewWindow.Height = Font->tf_YSize + 16;  /* slight safety fudge */
  /* Raster for text */
  InitBitMap(&BitMap, 1, RASTERWIDTH, NewWindow.Height);
  if ((BitMap.Planes[0] = AllocRaster(RASTERWIDTH, NewWindow.Height)) == NULL) {
	printf("No plane\n");
	showError('e', "No plane");
	exit(10);
      }
  /* Window for raster. For showing-off purposes only. */
  
#if 0
    if ((Window = OpenWindow(&NewWindow)) == NULL) {
	printf("No window (probably too large). Will do without.\n");
	showError('e', "No window (probably too large). Will do without.");
    }
#else
    Window = 0;
#endif

    if (Window) {
	RastPort = Window->RPort;
    } else {
	RastPort = &EmergencyRastPort;
	InitRastPort(RastPort);
	RastPort->BitMap = &BitMap;
    }
    RastPort->Mask = 0x0001;
    OldFont = RastPort->Font;
    SetFont(RastPort, Font);
}


/*
 * Clean up system stuff in case of exit
 */
void
cleanup(void)
{
    if (Font) {
	SetFont(RastPort, OldFont);
	CloseFont(Font);
    }
    if (Window) {
	CloseWindow(Window);
    }
    if (GfxBase) {
	if (BitMap.Planes[0]) {
	    FreeRaster(BitMap.Planes[0], RASTERWIDTH, NewWindow.Height);
	    BitMap.Planes[0] = NULL;
	}
	CloseLibrary(GfxBase);
    }
    if (IntuitionBase) {
	CloseLibrary(IntuitionBase);
    }
    if (DiskFontBase) {
	CloseLibrary(DiskFontBase);
    }
}


