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

#include <intuition/intuition.h>
#include <utility/tagitem.h>
#include <devices/inputevent.h>
#include <graphics/rpattr.h>

#ifdef __SASC
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/diskfont.h>
#else
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/diskfont_protos.h>
#endif

#include "LeoLib.h"

#define VERSION "1.0"

#ifdef __SASC
static char *Ver = "$VER:Subtitle " VERSION " " __AMIGADATE__ "©1996 Leopold-Soft";
#else
static char *Ver = "$VER:Subtitle " VERSION "© 1996 Leopold-Soft";
#endif

#define MAX_LINES 6
#define PREFERABLE_LINES 2
#define MAX_LINE_LEN 256

#define RAW_ESC 69
#define RAW_UP 76
#define RAW_DOWN 77
#define RAW_LEFT 79
#define RAW_RIGHT 78
#define RAW_SPACE 64

#define USE_WIDTH 600
#define USE_HEIGHT_PAL 464
#define USE_HEIGHT_NTSC 400

#define BLANK_TIME 10 /* In 1/50 s */

enum FmtCode {
	fcPunct,
	fcWord,
	fcAny
};

static struct Screen *scr[MAX_LINES] = {NULL};
static struct Window *win[MAX_LINES] = {NULL};
static struct IntuiMessage *IDCMP;
static short emptyPens = ~0;
static BOOL quit = FALSE;

static ULONG GetTicks(void);
static int Cut(const UBYTE *s, int max, enum FmtCode fmtCode);
static int FormatText(char dstLines[MAX_LINES][MAX_LINE_LEN],
				const char srcLines[MAX_LINES][MAX_LINE_LEN],
				int nOfSrcL, enum FmtCode fmtCode);

static FILE *fp = NULL;

static struct TextExtent extent;

static char fontName[31]="CGTriumvirate";
static int Heights[MAX_LINES];
static UWORD __chip windowPointer[6] = {0, 0, 0, 0, 0, 0};

static struct TextAttr fontTextAttr = {
	(STRPTR)fontName,
				/* ta_Name */
	39,			/* ta_YSize */
	FS_NORMAL,	/* ta_Style */
	0x0			/* ta_Flags e.g. FSB_BOLD */
};

static struct TextFont *font[2] = {NULL, NULL};

static char lines[MAX_LINES][MAX_LINE_LEN], tmpLines[MAX_LINES][MAX_LINE_LEN];
static int xOffset;

struct Render {
	int x, y, pen; /* when pen = -1, quit */
};

static const struct Render coords[] = {
	/* Immediate outline ±2 pixels in every direction */
	{-2,  0,  1},
	{-1,  1,  1},
	{ 0,  2,  1},
	{ 1,  1,  1},
	{ 2,  0,  1},
	{ 1, -1,  1},
	{ 0, -2,  1},
	{-1, -1,  1},

	/* Shadow to the right upto +4 pixels */
	{ 2,  2,  1},
	{ 3,  1,  1},
	{ 4,  0,  1},
	{ 3, -1,  1},
	{ 2, -2,  1},

	/* Shadow to the right upto +6 pixels */
	{ 4,  2,  1},
	{ 5,  1,  1},
	{ 6,  0,  1},
	{ 5, -1,  1},
	{ 4, -2,  1},

	/* Grey outline ±1 pixel in every direction */
	{ 0, -1,  2},
	{ 0,  1,  2},
	{-1,  0,  2},
	{ 1,  0,  2},

	/* The text itself */
	{ 0,  0,  3},

	/* End tag */
	{ 0,  0, -1}
};



/* Main program. Should perhaps later be able to do italics */

int main(int argc, char **argv) {
	int i, j, offset = (argc > 1 && !strcmp(argv[1], "-f")) ? 1 : 0;
	int error = EXIT_FAILURE;
	int useHeight;

	if (argc < 2 || argc > 4+offset) {
		printf(	"Subtitle v" VERSION " ©1996 Leopold-Soft / Henrik Herranen\n"
				"e-mail: leopold@cs.tut.fi\n"
				"URL: http://www.cs.tut.fi/~leopold/\n"
				"\nUsage: %s [-f] FileName [FontName [FontSize]]\n"
				"Defaults: FontName=%s, FontSize=%d\n"
				,argv[0], fontName, fontTextAttr.ta_YSize);
		return EXIT_SUCCESS;
	}

	if (!(fp = fopen(argv[1+offset], "r"))) {
		printf("*** ERROR: Couldn't open file %s for reading\n", argv[1+offset]);
		goto cleanup;
	}

	if (argc > 3+offset) {
		i = atoi(argv[3+offset]);
		if (i < 8) {
			printf("Illegal font size %s, defaulting to 8\n", argv[3+offset]);
			i = 8;
		}
		fontTextAttr.ta_YSize = i;
	} else {
		i = fontTextAttr.ta_YSize;
	}

	if (argc > 2+offset) {
		strncpy(fontTextAttr.ta_Name, argv[2+offset], 25);
		fontTextAttr.ta_Name[25] = '\0';
	}
	strcat(fontTextAttr.ta_Name, ".font");
	if (!(font[0] = OpenDiskFont(&fontTextAttr))) {
		printf("*** ERROR: Couldn't open %s %d\n",
			fontTextAttr.ta_Name, fontTextAttr.ta_YSize);
		goto cleanup;
	}
	if (font[0]->tf_YSize != i)
		printf("Warning: Asked for font size %d (normal), but got %d\n",
		i, font[0]->tf_YSize);

	fontTextAttr.ta_Style = FSF_ITALIC;
	if (!(font[1] = OpenDiskFont(&fontTextAttr))) {
		printf("*** ERROR: Couldn't open %s %d\n",
			fontTextAttr.ta_Name, fontTextAttr.ta_YSize);
		goto cleanup;
	}
	if (font[1]->tf_YSize != i)
		printf("Warning: Asked for font size %d (italic), but got %d\n",
		i, font[1]->tf_YSize);

	for (i=0; i<4; i++) {
		if (!(scr[i] = OpenScreenTags(NULL,
					SA_Depth, 2,
					SA_Title, "Subtitle " VERSION " by Leopold-Soft",
					SA_Overscan, OSCAN_TEXT,
					SA_SysFont, 1,
					SA_DisplayID, HIRESLACE_KEY,
					SA_Pens, &emptyPens,
					SA_Quiet, TRUE,
					SA_ShowTitle, FALSE,
					TAG_END))) {
			printf("*** ERROR: Couldn't open screen! Perhaps low on memory?\n");
			goto cleanup;
		}
		SetRGB4(&scr[i]->ViewPort, 0, 8,10, 8);
		SetRGB4(&scr[i]->ViewPort, 1, 0, 0, 0);
		SetRGB4(&scr[i]->ViewPort, 2, 7, 7, 7);
		SetRGB4(&scr[i]->ViewPort, 3,15,15,15);

		if (!(win[i] = OpenWindowTags(NULL,
					WA_IDCMP, IDCMP_RAWKEY,
					WA_CustomScreen, scr[i],
					WA_Activate, TRUE,
					WA_NoCareRefresh, TRUE,
					WA_WBenchWindow, FALSE,
					WA_ScreenTitle, "Subtitle " VERSION " by Leopold-Soft",
					WA_Backdrop, TRUE,
					WA_Borderless, TRUE,
					TAG_END))) {
			printf("*** ERROR: Couldn't open window!\n");
			goto cleanup;
		}
		SetPointer(win[i], windowPointer, 1, 16, -1, -1);

		SetRPAttrs(win[i]->RPort,
			RPTAG_Font, font[0],
			RPTAG_APen, 1,
			RPTAG_DrMd, JAM1,
			TAG_END);
	}

	useHeight = (scr[0]->Height >= 512) ? USE_HEIGHT_PAL : USE_HEIGHT_NTSC;
	if (scr[0]->Height < useHeight) {
		printf("*** ERROR: System vertical overscan only %d pixels, "
				"while %d required!\n", scr[0]->Height, useHeight);
		goto cleanup;
	}
	Heights[0] = win[0]->Height - (win[0]->Height - useHeight)/2 -
					font[0]->tf_YSize + font[0]->tf_Baseline;
	for (i=1; i<MAX_LINES; i++)
		Heights[i] = Heights[i-1] - font[0]->tf_YSize;
	xOffset = (win[0]->Width - USE_WIDTH)/2;

	Move(win[2]->RPort, (long)xOffset, 100);
	Text(win[2]->RPort, "Subtitle " VERSION " ©1996 Leopold-Soft    ", 32);
	Move(win[2]->RPort, (long)xOffset, 200);
	Text(win[2]->RPort, "Press -> (Cursor right)", 23);
	ScreenToFront(scr[2]);

	while (!quit) {
		static int cw = -1;
		ULONG now;
		static BOOL blankInFront = FALSE;
		int l;
		cw++;
		cw &= 3;
		if (!cw)
			Delay(1);
		while (IDCMP = (struct IntuiMessage *) GetMsg(win[cw] -> UserPort)) {
			int code = IDCMP->Code;
			int class = IDCMP->Class;
			struct Window *tmpWin;
			ReplyMsg((APTR) IDCMP);

			if (class & IDCMP_RAWKEY) {
				switch (code) {
				case RAW_ESC + IECODE_UP_PREFIX:
					quit = TRUE;
					error = EXIT_SUCCESS;
					break;
				case RAW_SPACE:
					ScreenToFront(scr[3]);
					blankInFront = TRUE;
					break;
				case RAW_UP:
				case RAW_DOWN:
					ScreenToFront(scr[3]);
					now = GetTicks();
					if (!blankInFront)
						while (GetTicks() < now + BLANK_TIME);
					blankInFront = FALSE;
					ScreenToFront(win[1]->WScreen);
					break;
				case RAW_LEFT:
					ScreenToFront(scr[3]);
					now = GetTicks();
					if (!blankInFront)
						while (GetTicks() < now + BLANK_TIME);
					blankInFront = FALSE;
					ScreenToFront(win[2]->WScreen);
					break;
				case RAW_RIGHT:
					ScreenToFront(scr[3]);
					now = GetTicks();
					if (!blankInFront)
						while (GetTicks() < now + BLANK_TIME);
					blankInFront = FALSE;
					ScreenToFront(win[0]->WScreen);
					for (i=0; i<MAX_LINES; i++)
						lines[0][i] = tmpLines[0][i] = '\0';
					tmpWin = win[2];
					win[2] = win[1];
					win[1] = win[0];
					win[0] = tmpWin;
					j = 0;
					/* Read the input lines to be processed */
					do {
						int pos=0, c;
						while((c = fgetc(fp)) != '\n' && c != EOF && pos < MAX_LINE_LEN-1)
							tmpLines[j][pos++] = c;
						tmpLines[j][pos] = '\0';
					} while (strlen(tmpLines[j]) && ++j < MAX_LINES);

					if (j >= MAX_LINES) {
						printf("*** ERROR: Too many consecutive source lines, read up to:\n");
						for (i=0; i<MAX_LINES; i++)
							printf("> %s\n", tmpLines[i]);
						goto cleanup;
					}

					if (j && !strcmp(tmpLines[0], "#i")) {
						j--;
						SetRPAttrs(win[0]->RPort,
							RPTAG_Font, font[1],
							TAG_END);
						for (i=0; i<j; i++)
							strcpy(tmpLines[i], tmpLines[i+1]);
						tmpLines[j][0] = '\0';
					}
					/* j holds the number of src lines */
					l = FormatText(lines, tmpLines, j, fcPunct);
					if (l > PREFERABLE_LINES) {
						int newL = FormatText(lines, tmpLines, j, fcWord);
						if (newL > PREFERABLE_LINES) {
							int newestL = FormatText(lines, tmpLines, j, offset ? fcWord : fcAny);
							if (newestL > MAX_LINES) {
								printf("*** ERROR: Cant fit following text in %d lines:\n",
									MAX_LINES);
								for (i=0; i<j; i++)
									printf("> %s\n", tmpLines[i]);
									goto cleanup;
							} else if (newestL == l) {
								l = FormatText(lines, tmpLines, j, fcPunct);
							} else if (newestL == newL) {
								l = FormatText(lines, tmpLines, j, fcWord);
							} else {
								l = newestL;
							}
						} else if (newL == l) {
							l = FormatText(lines, tmpLines, j, fcPunct);
						} else {
							l = newL;
						}
					}

/*					for (i=0; i<MAX_LINES; i++)
						printf("print line %d = %s\n", i, lines[i]);
*/
					if (l) {
						static char t[MAX_LINE_LEN];
						for (i=0; i<l>>1; i++) {
							strcpy(t, lines[i]);
							strcpy(lines[i], lines[l-i-1]);
							strcpy(lines[l-i-1], t);
						}
					}

					SetRPAttrs(win[0]->RPort, RPTAG_APen, 0, TAG_END);
					BltPattern(win[0]->RPort, NULL, 0, 0,
						(long)win[0]->Width, (long)win[0]->Height, 0);
					for (i=0; i<MAX_LINES; i++) {
						int len = strlen(lines[i]);
/*						printf("print line %d = %s\n", i, lines[i]);*/
						if (len) {
							j = 0;
							while(coords[j].pen != -1) {
								SetRPAttrs(win[0]->RPort, RPTAG_APen,
									coords[j].pen, TAG_END);
								Move(win[0]->RPort, (long)xOffset + coords[j].x,
									(long)Heights[i] + coords[j].y);
								Text(win[0]->RPort, lines[i], (ULONG)len);
								j++;
							}
						}
					}
					SetRPAttrs(win[0]->RPort,
						RPTAG_Font, font[0],
						TAG_END);
					break;
				}
			}
		}
	}

	ScreenToFront(scr[3]);
	error = EXIT_SUCCESS;

cleanup:
	for (i=0; i<4; i++)
		if (win[i]) {
			ClearPointer(win[i]);
			CloseWindow(win[i]);
		}
	for (i=0; i<4; i++)
		if (scr[i])
			CloseScreen(scr[i]);
	if (font[1])
		CloseFont(font[1]);
	if (font[0])
		CloseFont(font[0]);
	if (fp)
		fclose(fp);

	return error;
}

/*******************************************************\
*														*
*	GetTicks()											*
*														*
*	Returns the current time in fiftieth of seconds		*
*														*
\*******************************************************/

static ULONG GetTicks(void) {
	static struct DateStamp ds;
	DateStamp(&ds);
	return (ULONG) (ds.ds_Tick + (ds.ds_Minute + ds.ds_Days*24*60)*60*TICKS_PER_SECOND);
}

#define CF 2	/* Consonant */
#define VF 1	/* Vowel */
#define PF 4	/* Punctuation */

static const UBYTE charTab[257] = {
	    0, /* $-1  -1    */
	    0, /* $ 0   0    */
	    0, /* $ 1   1    */
	    0, /* $ 2   2    */
	    0, /* $ 3   3    */
	    0, /* $ 4   4    */
	    0, /* $ 5   5    */
	    0, /* $ 6   6    */
	    0, /* $ 7   7    */
	    0, /* $ 8   8    */
	    0, /* $ 9   9    */
	    0, /* $ A  10    */
	    0, /* $ B  11    */
	    0, /* $ C  12    */
	    0, /* $ D  13    */
	    0, /* $ E  14    */
	    0, /* $ F  15    */
	    0, /* $10  16    */
	    0, /* $11  17    */
	    0, /* $12  18    */
	    0, /* $13  19    */
	    0, /* $14  20    */
	    0, /* $15  21    */
	    0, /* $16  22    */
	    0, /* $17  23    */
	    0, /* $18  24    */
	    0, /* $19  25    */
	    0, /* $1A  26    */
	    0, /* $1B  27    */
	    0, /* $1C  28    */
	    0, /* $1D  29    */
	    0, /* $1E  30    */
	    0, /* $1F  31    */
	    0, /* $20  32    */
 PF	     , /* $21  33 !  */
	    0, /* $22  34 "  */
	    0, /* $23  35 #  */
	    0, /* $24  36 $  */
	    0, /* $25  37 %  */
	    0, /* $26  38 &  */
	    0, /* $27  39 '  */
	    0, /* $28  40 (  */
	    0, /* $29  41 )  */
	    0, /* $2A  42 *  */
	    0, /* $2B  43 +  */
 PF		 , /* $2C  44 ,  */
	    0, /* $2D  45 -  */
 PF	     , /* $2E  46 .  */
	    0, /* $2F  47 /  */
	    0, /* $30  48 0  */
	    0, /* $31  49 1  */
	    0, /* $32  50 2  */
	    0, /* $33  51 3  */
	    0, /* $34  52 4  */
	    0, /* $35  53 5  */
	    0, /* $36  54 6  */
	    0, /* $37  55 7  */
	    0, /* $38  56 8  */
	    0, /* $39  57 9  */
 PF	     , /* $3A  58 :  */
 PF	     , /* $3B  59 ;  */
	    0, /* $3C  60 <  */
	    0, /* $3D  61 =  */
	    0, /* $3E  62 >  */
 PF	     , /* $3F  63 ?  */
	    0, /* $40  64 @  */
	   VF, /* $41  65 A  */
	CF   , /* $42  66 B  */
	CF   , /* $43  67 C  */
	CF   , /* $44  68 D  */
	   VF, /* $45  69 E  */
	CF   , /* $46  70 F  */
	CF   , /* $47  71 G  */
	CF   , /* $48  72 H  */
	   VF, /* $49  73 I  */
	CF   , /* $4A  74 J  */
	CF   , /* $4B  75 K  */
	CF   , /* $4C  76 L  */
	CF   , /* $4D  77 M  */
	CF   , /* $4E  78 N  */
	   VF, /* $4F  79 O  */
	CF   , /* $50  80 P  */
	CF   , /* $51  81 Q  */
	CF   , /* $52  82 R  */
	CF   , /* $53  83 S  */
	CF   , /* $54  84 T  */
	   VF, /* $55  85 U  */
	CF   , /* $56  86 V  */
	CF   , /* $57  87 W  */
	CF   , /* $58  88 X  */
	   VF, /* $59  89 Y  */
	CF   , /* $5A  90 Z  */
	    0, /* $5B  91 [  */
	    0, /* $5C  92 \  */
	    0, /* $5D  93 ]  */
	    0, /* $5E  94 ^  */
	    0, /* $5F  95 _  */
	    0, /* $60  96 `  */
	   VF, /* $61  97 a  */
	CF   , /* $62  98 b  */
	CF   , /* $63  99 c  */
	CF   , /* $64 100 d  */
	   VF, /* $65 101 e  */
	CF   , /* $66 102 f  */
	CF   , /* $67 103 g  */
	CF   , /* $68 104 h  */
	   VF, /* $69 105 i  */
	CF   , /* $6A 106 j  */
	CF   , /* $6B 107 k  */
	CF   , /* $6C 108 l  */
	CF   , /* $6D 109 m  */
	CF   , /* $6E 110 n  */
	   VF, /* $6F 111 o  */
	CF   , /* $70 112 p  */
	CF   , /* $71 113 q  */
	CF   , /* $72 114 r  */
	CF   , /* $73 115 s  */
	CF   , /* $74 116 t  */
	   VF, /* $75 117 u  */
	CF   , /* $76 118 v  */
	CF   , /* $77 119 w  */
	CF   , /* $78 120 x  */
	   VF, /* $79 121 y  */
	CF   , /* $7A 122 z  */
	    0, /* $7B 123 {  */
	    0, /* $7C 124 |  */
	    0, /* $7D 125 }  */
	    0, /* $7E 126 ~  */
	    0, /* $7F 127    */
	    0, /* $80 128    */
	    0, /* $81 129    */
	    0, /* $82 130    */
	    0, /* $83 131    */
	    0, /* $84 132    */
	    0, /* $85 133    */
	    0, /* $86 134    */
	    0, /* $87 135    */
	    0, /* $88 136    */
	    0, /* $89 137    */
	    0, /* $8A 138    */
	    0, /* $8B 139    */
	    0, /* $8C 140    */
	    0, /* $8D 141    */
	    0, /* $8E 142    */
	    0, /* $8F 143    */
	    0, /* $90 144    */
	    0, /* $91 145    */
	    0, /* $92 146    */
	    0, /* $93 147    */
	    0, /* $94 148    */
	    0, /* $95 149    */
	    0, /* $96 150    */
	    0, /* $97 151    */
	    0, /* $98 152    */
	    0, /* $99 153    */
	    0, /* $9A 154    */
	    0, /* $9B 155    */
	    0, /* $9C 156    */
	    0, /* $9D 157    */
	    0, /* $9E 158    */
	    0, /* $9F 159    */
	    0, /* $A0 160 hard space		*/
 PF	     , /* $A1 161 ! upside down		*/
	    0, /* $A2 162 cent				*/
	    0, /* $A3 163 pound 			*/
	    0, /* $A4 164 equ sun 			*/
	    0, /* $A5 165 yen				*/
	    0, /* $A6 166 double pipe		*/
	    0, /* $A7 167 rule (SS)			*/
	    0, /* $A8 168 Umlaut "			*/
	    0, /* $A9 169 (C)				*/
	    0, /* $AA 170 a over -			*/
	    0, /* $AB 171 <<				*/
	    0, /* $AC 172 overscore (-) w/ hook	*/
	    0, /* $AD 173 strikethru (-)	*/
	    0, /* $AE 174 (R)				*/
	    0, /* $AF 175 overscore (-)		*/
	    0, /* $B0 176 degree			*/
	    0, /* $B1 177 +-				*/
	    0, /* $B2 178 ^2				*/
	    0, /* $B3 179 ^3				*/
	    0, /* $B4 180 single umlaut '	*/
	    0, /* $B5 181 micro, u			*/
	    0, /* $B6 182 pi				*/
	    0, /* $B7 183 dot				*/
	    0, /* $B8 184 accent ,			*/
	    0, /* $B9 185 ^1				*/
	    0, /* $BA 186 o over -			*/
	    0, /* $BB 187 >>				*/
	    0, /* $BC 188 1/4				*/
	    0, /* $BD 189 1/2				*/
	    0, /* $BE 190 3/4				*/
 PF	     , /* $BF 191 ? upside down		*/
	   VF, /* $C0 192 A` */
	   VF, /* $C1 193 A' */
	   VF, /* $C2 194 A^ */
	   VF, /* $C3 195 A~ */
	   VF, /* $C4 196 A" */
	   VF, /* $C5 197 Ao */
	   VF, /* $C6 198 AE */
	CF   , /* $C7 199 C, */
	   VF, /* $C8 200 E` */
	   VF, /* $C9 201 E' */
	   VF, /* $CA 202 E^ */
	   VF, /* $CB 203 E" */
	   VF, /* $CC 204 I` */
	   VF, /* $CD 205 I' */
	   VF, /* $CE 206 I^ */
	   VF, /* $CF 207 I" */
	CF   , /* $D0 208 -D */
	CF   , /* $D1 209 N~ */
	   VF, /* $D2 210 O` */
	   VF, /* $D3 211 O' */
	   VF, /* $D4 212 O^ */
	   VF, /* $D5 213 O~ */
	   VF, /* $D6 214 O" */
	    0, /* $D7 215 ×  */
	   VF, /* $D8 216 O/ */
	   VF, /* $D9 217 U` */
	   VF, /* $DA 218 U' */
	   VF, /* $DB 219 U^ */
	   VF, /* $DC 220 U" */
	   VF, /* $DD 221 Y' */
	   VF, /* $DE 222 |O */
	CF   , /* $DF 223 |B */
	   VF, /* $E0 224 a` */
	   VF, /* $E1 225 a' */
	   VF, /* $E2 226 a^ */
	   VF, /* $E3 227 a~ */
	   VF, /* $E4 228 a" */
	   VF, /* $E5 229 ao */
	   VF, /* $E6 230 ae */
	CF   , /* $E7 231 c, */
	   VF, /* $E8 232 e` */
	   VF, /* $E9 233 e' */
	   VF, /* $EA 234 e^ */
	   VF, /* $EB 235 e" */
	   VF, /* $EC 236 i` */
	   VF, /* $ED 237 i' */
	   VF, /* $EE 238 i^ */
	   VF, /* $EF 239 i" */
	CF   , /* $F0 240 d- */
	CF   , /* $F1 241 n~ */
	   VF, /* $F2 242 o` */
	   VF, /* $F3 243 o' */
	   VF, /* $F4 244 o^ */
	   VF, /* $F5 245 o~ */
	   VF, /* $F6 246 o" */
	    0, /* $F7 247 '-.*/
	   VF, /* $F8 248 o/ */
	   VF, /* $F9 249 u` */
	   VF, /* $FA 250 u' */
	   VF, /* $FB 251 u^ */
	   VF, /* $FC 252 u" */
	   VF, /* $FD 253 y' */
	   VF, /* $FE 254 |o */
	   VF  /* $FF 255 y" */
};


static int type(int d) {
    return charTab[d+1]&(CF|VF);
}

static const int state[3][3] = {
    { 0, 1,   0 },
    { 2, 1,   0 },
    { 2, 1+4, 0 }
};

/*
	Returns the length of the longest possible substring in the source string,
	according to the given constraints:
		s = string
		max = maximum number of characters to be examined
		fmtCode = format code: where lines can change
*/
static int Cut(const UBYTE *s, int max, enum FmtCode fmtCode) {
	int pos = 0, top = 16384, cc, r;
	if (fmtCode == fcAny) {
		int p = 0;
	    while ((cc = s[pos]) != '\0' && pos <= max) {
	        p = state[p][2-type(cc)];
	        if (p & 4) {		/* Handle possible flag in table */
	            p &= ~4;
				if (!(pos >= 3 && IsSpace(s[pos-3])))
		            top = 32768 + pos - 1;
	        }
			pos++;
			if (IsSpace(cc) && !(s[pos] == '-' && s[pos+1] == '\0') &&
					!(pos >= 2 && s[pos-1] == '-' && IsSpace(s[pos-2])))
				top = pos;
	    }
	} else if (fmtCode == fcWord) {
		while ((cc = s[pos]) != '\0' && pos++ < max)
			if (IsSpace(cc) && !(s[pos] == '-' && s[pos+1] == '\0') &&
					!(pos >= 2 && s[pos-1] == '-' && IsSpace(s[pos-2])))
				top = pos;
	} else {
		while ((cc = s[pos]) != '\0' && pos++ < max)
			if ((charTab[cc+1] & PF) && IsSpace(s[pos]) && pos < max &&
								!(s[pos] == '-' && s[pos+1] == '\0') &&
					!(pos >= 2 && s[pos-1] == '-' && IsSpace(s[pos-2])))
				top = pos+1;
	}
	r = (cc == '\0' && pos <= max) ? pos : top;
/*	printf("Cut: fmtCode = %d, pos = %d, max = %d, r=%d\n%s\n", fmtCode, pos, max, r, s);
	for (pos=0; pos<(r&~(32768|16384))-1; pos++)
		printf(" ");
	printf("^last\n");*/
	return r;
}



/* Formats text to the given destination from a given source */
static int FormatText(char dstLines[MAX_LINES][MAX_LINE_LEN],
				const char srcLines[MAX_LINES][MAX_LINE_LEN],
				int nOfSrcL, enum FmtCode fmtCode) {
	int nOfDstL = 0, i, srcL=0;
	for (i=0; i<MAX_LINES; i++)
		dstLines[i][0] = '\0';
/*	printf("FormatText: fmtCode = %d\n", fmtCode);*/

	while(srcL < nOfSrcL) {
		int pos = 0, srcLLen = strlen(srcLines[srcL]);
/*		printf("srcLLen = %d, l=\"%s\"\n", srcLLen, srcLines[srcL]);*/
		while(pos < srcLLen) {
			BOOL broken = FALSE;
			int width;
/*			printf("srcL=%d, nOfSrcL=%d, pos=%d, srcLLen = %d\n",
				srcL, nOfSrcL, pos, srcLLen);*/
			width = TextFit(win[0]->RPort, (char *)srcLines[srcL]+pos,
				(ULONG)strlen(srcLines[srcL]+pos),
				&extent, NULL, 1, USE_WIDTH, 32767);
			width = Cut(srcLines[srcL]+pos, width, fmtCode);
			if (width & 16384)
				return MAX_LINES+1;
			if (width & 32768) {
				broken = TRUE;
				width &= ~32768;
			}
			if (nOfDstL < MAX_LINES) {
				memcpy(dstLines[nOfDstL], srcLines[srcL]+pos, width);
				dstLines[nOfDstL][width] = broken ? '-' : '\0';
				dstLines[nOfDstL][width+1] = '\0';
/*				printf("l=%d, dst=%s\n", nOfDstL, dstLines[nOfDstL]);
			} else {
				printf("l=%d\n", nOfDstL);*/
			}
			nOfDstL++;
			pos += width;
			if (IsSpace(srcLines[srcL][pos]))
				pos++;
		}
		srcL++;
	}
	return nOfDstL;
}
