/*********************************************************************/
/*                                                                   */
/*                     Copyright (c) 1985, 1988                      */
/*                    Commodore-Amiga, Inc.                          */
/*                    All rights reserved.                           */
/*                                                                   */
/*     No part of this program may be reproduced, transmitted,       */
/*     transcribed, stored in retrieval system, or translated        */
/*     into any language or computer language, in any form or        */
/*     by any means, electronic, mechanical, magnetic, optical,      */
/*     chemical, manual or otherwise, without the prior written      */
/*     permission of:                                                */
/*                     Commodore-Amiga, Inc.                         */
/*                     16795 Lark Ave., Suite 106                    */
/*                     Los Gatos, CA. 95030                          */
/*                                                                   */
/*********************************************************************/
#include "exec/types.h"
#include "exec/ports.h"
#include "exec/tasks.h"
#include "exec/io.h"
#include "devices/clipboard.h"
#include "graphics/gfx.h"
#include "graphics/gfxbase.h"
#include "graphics/view.h"
#include "intuition/intuition.h"
#include "libraries/dos.h"
#include "libraries/dosextens.h"


struct Task *FindTask();
struct SatisfyMsg *GetMsg();

char buffer[80], *b, c;
int rawConsole, postID;

struct IOClipReq clipboardIO = 0;
struct MsgPort clipboardMsgPort = 0;
struct MsgPort satisfyMsgPort = 0;

int CBOpen(unit)
int unit;
{
    int error;

    /* open the clipboard device */
    if ((error = OpenDevice("clipboard.device", unit, &clipboardIO, 0)) != 0)
	return(error);

    /* Set up the message port in the I/O request */
    clipboardMsgPort.mp_Node.ln_Type = NT_MSGPORT;
    clipboardMsgPort.mp_Flags = 0;
    clipboardMsgPort.mp_SigBit = AllocSignal(-1);
    clipboardMsgPort.mp_SigTask = (struct Task *) FindTask((char *) NULL);
    AddPort(&clipboardMsgPort);
    clipboardIO.io_Message.mn_ReplyPort = &clipboardMsgPort;

    satisfyMsgPort.mp_Node.ln_Type = NT_MSGPORT;
    satisfyMsgPort.mp_Flags = 0;
    satisfyMsgPort.mp_SigBit = AllocSignal(-1);
    satisfyMsgPort.mp_SigTask = (struct Task *) FindTask((char *) NULL);
    AddPort(&satisfyMsgPort);

    return(0);
}

CBClose()
{
    RemPort(&satisfyMsgPort);
    FreeSignal(satisfyMsgPort.mp_SigBit);
    RemPort(&clipboardMsgPort);
    FreeSignal(clipboardMsgPort.mp_SigBit);
    CloseDevice(&clipboardIO);
}

CBCut(stream, length)
char *stream;
int length;
{
    clipboardIO.io_Command = CMD_WRITE;
    clipboardIO.io_Data = (STRPTR) stream;
    clipboardIO.io_Length = length;
    clipboardIO.io_Offset = 0;
    clipboardIO.io_ClipID = 0;
    DoIO(&clipboardIO);
    clipboardIO.io_Command = CMD_UPDATE;
    DoIO(&clipboardIO);
}

CBPaste(stream, length)
char *stream;
int length;
{
    clipboardIO.io_Command = CMD_READ;
    clipboardIO.io_Data = (STRPTR) stream;
    clipboardIO.io_Length = length;
    clipboardIO.io_Offset = 0;
    clipboardIO.io_ClipID = 0;
    DoIO(&clipboardIO);
    /* force end of file */
    clipboardIO.io_Command = CMD_READ;
    clipboardIO.io_Data = (STRPTR) 0;
    clipboardIO.io_Length = 999999999;
    DoIO(&clipboardIO);
}


writeLong(ldata)
LONG *ldata;
{
    clipboardIO.io_Command = CMD_WRITE;
    clipboardIO.io_Data = (STRPTR) ldata;
    clipboardIO.io_Length = 4;
    DoIO(&clipboardIO);
}


CBSatisfyPost(postID, string)
int postID;
char *string;
{
    int length;
    char *s;

    length = 0;
    s = string;
    while(*s++) length++;

    clipboardIO.io_ClipID = postID;
    clipboardIO.io_Offset = 0;
    writeLong("FORM");			/* "FORM"	*/
    length += 12;
    writeLong(&length);			/* #		*/
    writeLong("FTXT");			/* "FTXT"	*/
    writeLong("CHRS");			/* "CHRS"	*/
    length -= 12;
    writeLong(&length);			/* #		*/

    clipboardIO.io_Command = CMD_WRITE;
    clipboardIO.io_Data = (STRPTR) string;
    clipboardIO.io_Length = length;
    DoIO(&clipboardIO);			/* text string	*/

    clipboardIO.io_Command = CMD_UPDATE;
    DoIO(&clipboardIO);
}

CBCutS(string)
char *string;
{
    CBSatisfyPost(0, string);
}


CBPasteS(string)
char *string;
{
    int length;

    clipboardIO.io_Command = CMD_READ;
    clipboardIO.io_Data = (STRPTR) 0;
    clipboardIO.io_Length = 16;
    clipboardIO.io_Offset = 0;
    clipboardIO.io_ClipID = 0;
    DoIO(&clipboardIO);

    clipboardIO.io_Command = CMD_READ;
    clipboardIO.io_Data = (STRPTR) &length;
    clipboardIO.io_Length = 4;
    DoIO(&clipboardIO);

    clipboardIO.io_Command = CMD_READ;
    clipboardIO.io_Data = (STRPTR) string;
    clipboardIO.io_Length = length;
    DoIO(&clipboardIO);

    string[length] = '\0';

    /* force end of file to terminate read */
    clipboardIO.io_Command = CMD_READ;
    clipboardIO.io_Length = 1;
    clipboardIO.io_Data = (STRPTR) 0;
    DoIO(&clipboardIO);
}

int
CBPost()
{
    clipboardIO.io_Command = CBD_POST;
    clipboardIO.io_Data = (STRPTR) &satisfyMsgPort;
    clipboardIO.io_ClipID = 0;
    DoIO(&clipboardIO);
    return(clipboardIO.io_ClipID);
}

int
CBCurrentReadID()
{
    clipboardIO.io_Command = CBD_CURRENTREADID;
    DoIO(&clipboardIO);
    return(clipboardIO.io_ClipID);
}

int
CBCurrentWriteID()
{
    clipboardIO.io_Command = CBD_CURRENTWRITEID;
    DoIO(&clipboardIO);
    return(clipboardIO.io_ClipID);
}

BOOL
CBCheckSatisfy(idVar)
int *idVar;
{
    struct SatisfyMsg *sm;

    if (*idVar == 0)
	return(TRUE);
    if (*idVar < CBCurrentWriteID()) {
	*idVar = 0;
	return(TRUE);
    }
    if (sm = (struct SatisfyMsg *) GetMsg(&satisfyMsgPort)) {
	if (*idVar == sm->sm_ClipID)
	    return(TRUE);
    }
    return(FALSE);
}


readS()
{
    b = buffer;
    while (Read(rawConsole, &c, 1), (c != '\r')) {
	*b++ = c;
	Write(rawConsole, &c, 1);
    }
    *b = '\0';
}


main()
{
    int i;

    i = CBOpen(PRIMARY_CLIP);
    if (i != 0) {
	printf("CBOpen returned %ld.\n", i);
	exit(20);
    }

    rawConsole = Open("RAW:25/25/615/150/clipboard.device test", MODE_OLDFILE);

    Write(rawConsole, "\033[20h", 5);

    c = 0;
    postID = 0;
    while (c != '\033') {
	while((postID) && (!WaitForChar(rawConsole, 1000000)))
	    if (CBCheckSatisfy(&postID)) {
		if (postID) {
		    Write(rawConsole, "Satisfy post data\n", 18);
		    readS();
		    Write(rawConsole, "\nsatisfying \"", 13);
		    Write(rawConsole, buffer, strlen(buffer));
		    Write(rawConsole, "\"\n", 2);
		    CBSatisfyPost(postID, buffer);
		    postID = 0;
		}
	    }
	Read(rawConsole, &c, 1);
	switch (c) {
	    case 'w':
		Write(rawConsole, "Enter cut data\n", 15);
		readS();
		Write(rawConsole, "\ncutting \"", 11);
		Write(rawConsole, buffer, strlen(buffer));
		Write(rawConsole, "\"\n", 2);;
		CBCutS(buffer);
		break;
	    case 'r':
		if ((postID) && (CBCurrentReadID() == postID)) {
		    Write(rawConsole, "previous post is still valid\n", 29);
		}
		else {
		    CBPasteS(buffer);
		    Write(rawConsole, "paste is \"", 10);
		    Write(rawConsole, buffer, strlen(buffer));
		    Write(rawConsole, "\"\n", 2);
		}
		break;
	    case 'p':
		Write(rawConsole, "Posting post...\n", 16);
		postID = CBPost();
		break;
	    case '\033':
		break;
	    default:
		Write(rawConsole,
			"w (Cut), r (Paste), p (Post), <ESC> (Quit)\n", 43);
	}
    }

    /* check if need to satisfy post before exiting */
    if (postID) {
	if (postID >= CBCurrentWriteID()) {
	    Write(rawConsole, "Satisfy post data before exiting\n", 18);
	    readS();
	    Write(rawConsole, "\nsatisfying \"", 13);
	    Write(rawConsole, buffer, strlen(buffer));
	    Write(rawConsole, "\"\n", 2);
	    CBSatisfyPost(postID, buffer);
	    postID = 0;
	}
    }
    CBClose();
    Close(rawConsole);
}
