#include <stdio.h>
#include <sys/param.h>
#include <errno.h>
extern char **sys_errlist;

#include <suntool/sunview.h>
#include <suntool/panel.h>
#include <suntool/canvas.h>

extern char MifClipboardFileName[];

static Frame baseFrame;
static Canvas ssCanvas; 
static Panel controlPanel;
	static Panel_item facetsItem, shapeItem, isInternItem, insetFileNameItem;
static Menu fileMenu, pasteMenu;

static short blackSquareImage[] = {
#include <images/square_black.pr>
}; 
mpr_static(blackSquare, 16, 16, 1, blackSquareImage);

#define toggle_bit_on(value, bit) ((value) & (1 << (bit)))

/*
Workhorse called by Paste buttons and PUT to
compute an "inset MIF" file.
*/

Export(isPaste)
{
char insetFileName[MAXPATHLEN + 1];
FILE *stream;
int isSolid;

isSolid = (int)panel_get_value(shapeItem);

if (! isPaste)
	unlink(MifClipboardFileName);
if (panel_get_value(isInternItem) == 0) {
	strcpy(insetFileName, (char *)panel_get_value(insetFileNameItem));
	if (! isPaste) {
		char command[MAXPATHLEN + 1];

		sprintf(command, "ln -s %s %s", insetFileName, MifClipboardFileName);
		system(command);
		SetSelnFileName(insetFileName); /* external inset */
	}
}
else if (isPaste)
/* don't contend w/ selection */ 
	sprintf(insetFileName, "/tmp/rected.%s", getenv("USER")); 
else {
	strcpy(insetFileName, MifClipboardFileName);
	SetSelnFileName(""); /* internal inset */
}
stream = fopen(insetFileName, "w");
if (! stream) {
	fprintf(stderr, "Can't open %s because %s.\n", insetFileName, sys_errlist[errno]);
	return;
}

fprintf(stream, "<MIFFile 2.0> # Generated by rected 2.0\n");
fprintf(stream, "include(mif_read.m4)\n\n");

fprintf(stream, "\t<ImportObject\n");
fprintf(stream, "\t\t<BRect 0 0 0.25\" 0.25\">\n");
fprintf(stream, "\t\t<Pen 15> <Fill 15>\n");
if (! panel_get_value(isInternItem)) {
/*
TODO
	fprintf(stream, "\t\t<ImportObFileDI>\n");
*/
	fprintf(stream, "\t\t<ImportObFile %s>\n", (char *)panel_get_value(insetFileNameItem));
}
fprintf(stream, "\t\t<ImportObEditor rected>\n");

/*
Write the facets.
*/

if (isSolid)
	fprintf(stream, "=rected.shape\n&%%vs\n");
else fprintf(stream, "=rected.shape\n&%%vo\n");

fprintf(stream, "=rected.mask\n&%%v\\x0%x\\x\n", panel_get_value(facetsItem));
if (toggle_bit_on((int)panel_get_value(facetsItem), 1)) {
/*
TODO
FrameImage
*/
}
if (toggle_bit_on((int)panel_get_value(facetsItem), 0)) {
	fprintf(stream, "=EPSI\n");
	fprintf(stream, "&%%v\n");
	fprintf(stream, "&%%!PS-Adobe-2.0 EPSF-2.0\\n\n");
	fprintf(stream, "&%%%%BoundingBox: 0 0 18 18\\n\n");
	fprintf(stream, "&%%%%Pages: 0\\n\n");
	fprintf(stream, "&%%%%Creator: %s\\n\n", getenv("USER"));
	{
	char s26[26];
	long now;

	now = time(0);
	strcpy(s26, ctime(&now));
	s26[24] = 0;
	fprintf(stream, "&%%%%CreationDate: %s\\n\n", s26); 
	}
	fprintf(stream, "&%%%%EndComments\\n\n");
/*
18 pixels can be expressed in 3 bytes:
FF FF C0
*/
	fprintf(stream, "&%%%%BeginPreview: 18 18 1 18\\n\n");
	if (! isSolid) {
		int i;

		fprintf(stream, "&%%FFFFC0\\n\n");
		for (i = 1; i < 18 - 1; ++i)
			fprintf(stream, "&%%800040\\n\n");
		fprintf(stream, "&%%FFFFC0\\n\n");
	}
	else {
		int i;

		for (i = 0; i < 18; ++i)
			fprintf(stream, "&%%FFFFC0\\n\n");
	}
	fprintf(stream, "&%%%%EndPreview\\n\n");
	fprintf(stream, "&%%%%EndProlog\\n\n");
	fprintf(stream, "&%%%%Page: \"one\" 1\\n\n");
	fprintf(stream, "&0 0 moveto 18 0 rlineto 0 18 rlineto -18 0 rlineto closepath 0 setgray\\n\n");
	if (isSolid)
		fprintf(stream, "&fill\\n\n");
	else fprintf(stream, "&1 setlinewidth stroke\\n\n");
	fprintf(stream, "&%%%%Trailer\\n\n");
}
fprintf(stream, "=EndInset\n");

/* End the inset object. */
fprintf(stream, "\t> # End ImportObject\n");

fclose(stream);

if (isPaste)
	if (Import(insetFileName) == -1)
		pleaseNote("Cannot Paste.");
}

/* Cycle procs. */

static setIntern(item, value, eventp)
Panel_item item;
unsigned int value;
Event *eventp;
{
if (value == 0)
	panel_set(insetFileNameItem, PANEL_SHOW_ITEM, TRUE, 0);
/* File N/A if internal inset. */
else panel_set(insetFileNameItem, PANEL_SHOW_ITEM, FALSE, 0);
}

static setSolid(item, value, eventp)
Panel_item item;
unsigned int value;
Event *eventp;
{
repaintSsCanvas(ssCanvas, canvas_pixwin(ssCanvas), NULL); 
}

/* Button procs. */

static pasteEvent(item, eventp)
Panel_item item;
Event *eventp;
{
if (event_id(eventp) == MS_RIGHT && (event_is_up(eventp) || event_is_down(eventp))) {
	if (event_is_down(eventp)) {
		int selection; 

		selection = (int)menu_show(pasteMenu, controlPanel, eventp, 0);
		switch (selection) {
		case 1:
			Export(1);
			break;
		case 2:
			Export(1);
			window_set(baseFrame, FRAME_NO_CONFIRM, TRUE, 0);
			window_destroy(baseFrame);
			break;
		}
	}
}
else panel_default_handle_event(item, eventp);
}

static pasteNotify()
{
Export(1);
}

static fileEvent(item, eventp)
Panel_item item;
Event *eventp;
{
if (event_id(eventp) == MS_RIGHT && (event_is_up(eventp) || event_is_down(eventp))) {
	if (event_is_down(eventp)) {
		int selection; 

		selection = (int)menu_show(fileMenu, controlPanel, eventp, 0);
		switch (selection) {
		case 1:
			if (panel_get_value(isInternItem) == 0) {
				char insetFileName[MAXPATHLEN + 1];

				strcpy(insetFileName, (char *)panel_get_value(insetFileNameItem));
				Edit(insetFileName , 0 /* don't intern */);
			}
			else pleaseNote("Please type an external inset file name first.");
			break;
		case 2:
			if (panel_get_value(isInternItem) == 0) {
				Export(0 /* not paste */);
			}
			else pleaseNote("Please type an external inset file name first.");
			break;
		case 3:
			{
			char helpDoc[MAXPATHLEN];

			sprintf(helpDoc, "%s/.fminit2.0/english/helpdir/%s", getenv("FMHOME"), "rected.doc");
			OpenDoc(helpDoc);
			}
			break;
		}
	}
}
else panel_default_handle_event(item, eventp);
}

/* Canvas procs. */

static repaintSsCanvas(canvas, pixwinp, repaintAreap) 
Canvas canvas;
Pixwin *pixwinp;
Rectlist *repaintAreap;
{
unsigned int w, h;

h = (unsigned int)window_get(canvas, CANVAS_HEIGHT); 
w = (unsigned int)window_get(canvas, CANVAS_WIDTH); 
if ((int)panel_get_value(shapeItem))
	pw_replrop(pixwinp, 0, 0, w, h, PIX_SRC, &blackSquare, 0, 0);
else {
	pw_writebackground(pixwinp, 0, 0, w - 1, h - 1, PIX_SRC);
/* top */
	pw_vector(pixwinp, 0, 0, w - 1, 0, PIX_SRC, 1);
/* bottom */
	pw_vector(pixwinp, 0, h - 1, w - 1, h - 1, PIX_SRC, 1);
/* left */
	pw_vector(pixwinp, 0, 0, 0, h - 1, PIX_SRC, 1);
/* right */
	pw_vector(pixwinp, w - 1, 0, w - 1, h - 1, PIX_SRC, 1);
}
}

static ssCanvasEventProc(window, eventp, arg)
Window window;
Event *eventp;
caddr_t arg;
{
ReportSelnEvent(eventp);
}

main(argc, argv)
char **argv;
{
/* Layout UI. */

baseFrame = window_create(NULL, FRAME,
	FRAME_ARGS, argc, argv,
	FRAME_LABEL, argv[0],
	0);

controlPanel = window_create(baseFrame, PANEL, 
	WIN_ROW_HEIGHT, 14,
	WIN_ROW_GAP, 4,
	WIN_COLUMN_WIDTH, 14 * strlen("FM Paste"),
	WIN_COLUMN_GAP, 4,
	0);

/* Two buttons on row 0. */

panel_create_item(controlPanel, PANEL_BUTTON,
	PANEL_LABEL_IMAGE, panel_button_image(controlPanel, "File", 0, 0),
	PANEL_EVENT_PROC, fileEvent,
	PANEL_ITEM_Y, ATTR_ROW(0),
	0);
fileMenu = menu_create(MENU_STRINGS, "Open", "Save", "Help", 0, 0); 

panel_create_item(controlPanel, PANEL_BUTTON,
	PANEL_LABEL_IMAGE, panel_button_image(controlPanel, "FM Paste", 0, 0),
	PANEL_EVENT_PROC, pasteEvent,
	PANEL_NOTIFY_PROC, pasteNotify,
	PANEL_ITEM_Y, ATTR_ROW(0),
	0);
pasteMenu = menu_create(MENU_STRINGS, "Paste", "Paste & Quit", 0, 0); 

/* A cycle on row 1. */

shapeItem = panel_create_item(controlPanel, PANEL_CYCLE,
	PANEL_ITEM_Y, ATTR_ROW(1),
	PANEL_ITEM_X, ATTR_COL(0),
	PANEL_CHOICE_STRINGS, "Outline", "Solid", 0,
	PANEL_NOTIFY_PROC, setSolid,
	0);

/* Two toggles on row 2. */ 

facetsItem = panel_create_item(controlPanel, PANEL_TOGGLE,
	PANEL_ITEM_Y, ATTR_ROW(2),
	PANEL_ITEM_X, ATTR_COL(0),
	PANEL_LAYOUT, PANEL_HORIZONTAL,
	PANEL_CHOICE_STRINGS, "EPSI", "FrameImage (TODO)", 0,
	PANEL_TOGGLE_VALUE, 0, TRUE,
	PANEL_TOGGLE_VALUE, 1, TRUE, 
	0);

/* A cycle & text box on row 3. */

isInternItem = panel_create_item(controlPanel, PANEL_CYCLE,
	PANEL_ITEM_Y, ATTR_ROW(3),
	PANEL_ITEM_X, ATTR_COL(0),
	PANEL_LAYOUT, PANEL_HORIZONTAL,
	PANEL_NOTIFY_PROC, setIntern,
	PANEL_CHOICE_STRINGS, "External File:", "Internal", 0,
	0);
insetFileNameItem = panel_create_item(controlPanel, PANEL_TEXT,
	PANEL_ITEM_Y, ATTR_ROW(4),
	PANEL_ITEM_X, ATTR_COL(0),
	PANEL_VALUE_DISPLAY_LENGTH, 20,
	PANEL_VALUE, "/tmp/myinset.mif",
	0);

window_fit(controlPanel);

ssCanvas = window_create(baseFrame, CANVAS,
	WIN_RIGHT_OF, controlPanel,
/*
	WIN_HEIGHT, 18,
	WIN_WIDTH, 18,
	CANVAS_WIDTH, 18,
	CANVAS_HEIGHT, 18,
*/
	CANVAS_REPAINT_PROC, repaintSsCanvas,
	CANVAS_RETAINED, FALSE,
/* In case re-sized. */
	CANVAS_AUTO_CLEAR, TRUE,
	CANVAS_AUTO_EXPAND, TRUE,
	CANVAS_AUTO_SHRINK, TRUE,
	CANVAS_FIXED_IMAGE, FALSE,
	WIN_EVENT_PROC, ssCanvasEventProc,
	CANVAS_MARGIN, 3,
/* For PUT and GET in canvas. */
	WIN_CONSUME_KBD_EVENTS, WIN_LEFT_KEYS, WIN_UP_EVENTS, 0,
	0); 

window_fit(baseFrame);

/* 
Prepare to serve OpenMaker remote procedures:
	FM_RPC_LAUNCH
	FM_RPC_EDIT
*/
InitServer();
/* Prepare to cooperate with Selection Service. */ 
InitSeln();

/* Pass control to Notifier. */
window_main_loop(baseFrame);

/* Yield selection (if holder) and unregister with Selection Service. */ 
FreeSeln();
}

/*
Remote procedures:
	FM_RPC_LAUNCH
	FM_RPC_EDIT
*/

static char *findFacet(stream, facetName, facetType)
FILE *stream;
char *facetName;
char facetType;
{
static char aLine[256]; 
char facetNameLine[256];
int lastC, c;

rewind(stream);

sprintf(facetNameLine, "=%s\n", facetName);
for (;;) {
	if (feof(stream) || fgets(aLine, sizeof(aLine) - 1, stream) == NULL)
		return (NULL);
	else if (strcmp(aLine, facetNameLine) == 0)
		break;
}

lastC = '\n';
for (;;) {
	c = getc(stream);
	if (c == EOF)
		return (NULL);
	else if (lastC == '\n' && c != '&')
		return (NULL);
	else if (lastC == '%') 
		if (c != facetType)
			return (NULL);
		else break;
	lastC = c;
}

/* Skip over \n& pairs. */
for (;;) {
	c = getc(stream);
	if (c == EOF)
		return (NULL);
	else if (c == '\n') {
		c = getc(stream);
		if (c != '&')
			return (NULL);
	}
	else {
		ungetc(c, stream);
		return (fgets(aLine, sizeof(aLine) - 1, stream));
	}
}
}

/*
Called by GET and FrameMaker. 
*/
Edit(fileName, isIntern)
char *fileName;
{
FILE *stream;
char *aValue;

Launch();

stream = fopen(fileName, "r");
if (! stream) {
	fprintf(stderr, "Cannot edit %s because %s.\n", fileName, sys_errlist[errno]);
	return;
}

aValue = findFacet(stream, "rected.shape", 'v');
if (! aValue)
	fprintf(stderr, "No rected.shape facet.\n");
else if (aValue[0] == 'o')
	panel_set_value(shapeItem, 0);
else if (aValue[0] == 's')
	panel_set_value(shapeItem, 1);
setSolid(NULL, NULL, NULL);

panel_set_value(isInternItem, isIntern);
if (! isIntern)
	panel_set_value(insetFileNameItem, fileName);
setIntern(NULL, isIntern, NULL);

aValue = findFacet(stream, "rected.mask", 'v');
if (! aValue)
	fprintf(stderr, "No rected.mask facet.\n");
else {
	int i;

	sscanf(aValue, "\\x%x", &i);
	panel_set_value(facetsItem, i);
}

fclose(stream);
}

Launch()
{
window_set(baseFrame, FRAME_CLOSED, FALSE, 0);
window_bell(baseFrame);
}
