/***********************************************\
*                                               *
*                     Snap                      *
*           © Mikael Karlsson 1988              *
*                                               *
\***********************************************/

#include "snap.h"

/* signals */
LONGBITS startsignal, insertsignal, cancelsignal, donesignal;
LONGBITS movesignal, clicksignal, timersignal, initsignal;
ULONG startsignum = -1L;
ULONG insertsignum = -1L;
ULONG cancelsignum = -1L;
ULONG donesignum = -1L;
ULONG movesignum = -1L;
ULONG clicksignum = -1L;
ULONG timersignum = -1L;
ULONG initsignum = -1L;
ULONG WaitSignal;

/* program */
struct MsgPort *port = NULL;
struct Task *MyTask;

/* Snap state machine */
WORD action;
WORD state;
WORD StartUnit = UNIT_FRAME;

/* clipboard */
struct IOClipReq *ClipReq = NULL;
struct MsgPort *ClipPort = NULL;

/* input device */
struct MsgPort *inputDevPort = NULL;
struct Interrupt handlerStuff;
struct IOStdReq *inputRequestBlock = NULL;
struct InputEvent SimEvent;
WORD Priority = 51; /* Default priority for input handler */
WORD textqual = IEQUALIFIER_LCOMMAND;
WORD gfxqual = IEQUALIFIER_RCOMMAND;
WORD insertkey = 23;
WORD xerox = 0;

UBYTE *CharData = NULL;

/* console */
struct MsgPort *ConPort = NULL;
struct IOStdReq *ConIOR = NULL;
struct KeyMap keymap;
LONG linedelay = 0;
LONG chardelay = 0;

/* windows */
struct MsgPort *Sharedport = NULL;
SHORT Sharedrefs;

/* libraries */
struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase       *GfxBase = NULL;
struct LayersBase    *LayersBase = NULL;
/* struct DosLibrary    *DosBase = NULL; */

/* graphics */
struct Screen *theScreen;
struct Layer *theLayer;
struct Layer_Info *LockedLayerInfo = NULL;
struct RastPort rp, TempRp, MyRP;
struct BitMap TempBM, MyBM;
UBYTE *TempRaster = NULL;
UWORD CrawlPtrn = 0x7777;
WORD FrameMask = 1;

/* detaching */
ULONG _BackGroundIO = 0;
ULONG _stack = 4096L;
ULONG _priority = 4L;
char *_procname = "Snap";

int isdigit(c)
REGISTER char c;
{
    return (c>='0' && c<='9');
}

long dectoint(str)
REGISTER char *str;
{
    REGISTER long val = 0;
    REGISTER char c;
    while (isdigit(c = *str)) {
        val = (((val<<2)+val)<<1) + c-'0';
        str++;
    }
    return(val);
}

long hextoint(str)
REGISTER char *str;
{
    REGISTER long val = 0;
    REGISTER char c;
    while (c = *str) {
        val <<= 4;
        val |= (c & 15) + (isdigit(c) ? 0 : 9);
        str++;
    }
    return(val);
}

void main(argc, argv)
WORD argc;
char *argv[];
{
    int i;
    Enable_Abort = 0;
    i = 1; /* Don't parse program name */
    while (i<argc) {
        char *arg = argv[i];
        if (arg[0] == '-') { /* Argument coming up */
            switch(arg[1]) {
                case 'p': {  /* Priority */
                    int pri = dectoint(&arg[2]);
                    if (pri>50 && pri<128) {
                        Priority = pri;
                    }
                    break;
                }
                case 't': {
                    textqual = hextoint(&arg[2]);
                    break;
                }
                case 'g': {
                    gfxqual = hextoint(&arg[2]);
                    break;
                }
                case 'i': {
                    insertkey = hextoint(&arg[2]);
                    break;
                }
                case 'c': {
                    chardelay = dectoint(&arg[2]);
                    break;
                }
                case 'l': {
                    linedelay = dectoint(&arg[2]);
                    break;
                }
                case 'a': {
                    CrawlPtrn = hextoint(&arg[2]);
                    break;
                }
                case 'x': {
                    xerox = 1;
                }
                case 'u': {
                    switch(dectoint(&arg[2])) {
                        case 1: {
                            StartUnit = UNIT_CHAR;
                            break;
                        }
                        case 0:
                        default: {
                            StartUnit = UNIT_FRAME;
                            break;
                        }
                    }
                    break;
                }
                case 'b': {
                    FrameMask = hextoint(&arg[2]);
                    break;
                }
                default: {
                    break;
                }
            }
        }
        i++; /* Next argument, please */
    }

    OpenStuff();

    /* This is what we're waiting for */
    WaitSignal = startsignal | insertsignal | initsignal | cancelsignal |
                 SIGBREAKF_CTRL_C | 1L << port->mp_SigBit;

    FOREVER {
        REGISTER LONGBITS sig =
          Wait(WaitSignal |
               (Sharedport ? (1L << Sharedport->mp_SigBit) : 0L));
        if (Sharedport) {
            REGISTER SHORT CloseTime = 0;
            REGISTER struct IntuiMessage *Msg;
            REGISTER struct Window *MyWin;
            while (Msg = (struct IntuiMessage *)GetMsg(Sharedport)) {
                if (Msg->Class == CLOSEWINDOW) {  /* Want to close? */
                    CloseTime = 1;                /* Set a flag */
                    MyWin = Msg->IDCMPWindow;     /* Window to close*/
                }
                ReplyMsg(Msg);
            }
            if (CloseTime) {
                closesharedwindow(MyWin);
            }
        }
        if (sig & SIGBREAKF_CTRL_C) {
            /* This is my cue. Exit if there are no open windows depending on us */
            if (Sharedrefs) {
                DisplayBeep(NULL);
            } else {
                CloseStuff();
            }
        }
        if (sig & initsignal) {
            SafePatch();                   /* Patch dangerous functions */
        }
        if (sig & cancelsignal) {
            SafeRestore();
        }
        if (sig & startsignal) { /* The handler wants a word in. */
            if (action == snapgfx) {       /* Check user action */
                HandleGfx();               /* Get the picture :-) */
            } else if (action == snaptext) {
                if (HandleChars()) {             /* Snap some chars */
                    if (xerox) {
                        sig |= insertsignal;
                    }
                }
            } else {
                  /* Previous snap wasn't finished when this one started. */
                SetSignal(0L,
                  movesignal|cancelsignal|donesignal|clicksignal|timersignal);
                DisplayBeep(NULL);
                action = noaction;
            }
            if (!(sig & insertsignal)) {
                SafeRestore();             /* Layers unlocked - all safe */
            }
        }

        if (sig & insertsignal) {
            LONG i;
            UBYTE *SnapSpace;
            ULONG ascii;
            action = insert;
            if (SnapSpace = FetchClip()) {  /* Get clipboard data */
                  /* Not necessary to patch here but it guarantees
                     that all inserted chars end up in the same window. */
                SafePatch();
                  /* get the current keymap  */
                ConIOR->io_Command =  CD_ASKDEFAULTKEYMAP;
                ConIOR->io_Length  = sizeof (struct KeyMap);
                ConIOR->io_Data    = (APTR) &keymap;
                ConIOR->io_Flags   = 1;    /* no IOQuick   */
                DoIO(ConIOR);
                  /* Set up an input request */
                inputRequestBlock->io_Command = IND_WRITEEVENT;
                inputRequestBlock->io_Flags   = 0L;
                inputRequestBlock->io_Length  = (long)sizeof(struct InputEvent);
                inputRequestBlock->io_Data    = (APTR)&SimEvent;
                  /* Translate chars in SnapSpace and insert them
                     into the input stream. */
                for (i=4; SnapSpace[i] && (action == insert); i++) {
                    ascii = SnapSpace[i];
                    if (ascii == 10) {
                        ascii = 13;     /* WYSIWYG? Hah! */
                        if (linedelay) {           /* Almost missed this one */
                            Delay(linedelay);      /* Give the man some air */
                        }
                    }
                    InvertKeyMap(ascii, &SimEvent, &keymap);
                    DoIO(inputRequestBlock);
                    if (chardelay) {
                        Delay(chardelay);
                    }
                }
                SafeRestore();  /* "Depatch" */
                  /* Free memory given to us by FetchClip() */
                FreeMem(SnapSpace, *(ULONG *)SnapSpace);
            }
            action = noaction;
        }
    }

    CloseStuff();  /* Guess what */
}
