#include "snap.h"

IMPORT LONGBITS startsignal, insertsignal, cancelsignal, donesignal;
IMPORT LONGBITS movesignal, clicksignal, timersignal, initsignal;
IMPORT ULONG startsignum, insertsignum, cancelsignum, donesignum;
IMPORT ULONG movesignum, clicksignum, timersignum, initsignum;

/* program */
IMPORT struct MsgPort *port;
IMPORT struct Task *MyTask;

/* Snap state machine */
IMPORT WORD action;
IMPORT WORD state;

/* clipboard */
IMPORT struct IOClipReq *ClipReq;
IMPORT struct MsgPort *ClipPort;

/* input device */
IMPORT struct MsgPort *inputDevPort;
IMPORT struct Interrupt handlerStuff;
IMPORT struct IOStdReq *inputRequestBlock;
IMPORT WORD Priority;

IMPORT UBYTE *CharData;

/* console */
IMPORT struct MsgPort *ConPort;
IMPORT struct IOStdReq *ConIOR;
IMPORT struct KeyMap keymap;

/* windows */
IMPORT struct MsgPort *Sharedport;
IMPORT SHORT Sharedrefs;

/* libraries */
IMPORT struct IntuitionBase *IntuitionBase;
IMPORT struct GfxBase       *GfxBase;
IMPORT struct LayersBase    *LayersBase;

/* graphics */
IMPORT struct RastPort TempRp;
IMPORT struct BitMap TempBM;
IMPORT UBYTE *TempRaster;

VOID CloseStuff()
{
    SafeRestore();
    if (TempRaster)         FreeRaster(TempRaster, 16L, 16L);
    if (CharData)           FreeMem(CharData, 256L*32);
    if (inputRequestBlock) {
        if (inputRequestBlock->io_Device) {
            inputRequestBlock->io_Command = IND_REMHANDLER;  /* Remove handler */
            inputRequestBlock->io_Data    = (APTR)&handlerStuff;
            DoIO(inputRequestBlock);
            CloseDevice(inputRequestBlock);
        }
        DeleteStdIO(inputRequestBlock);
    }
    if (inputDevPort)       DeletePort(inputDevPort);
    if (ConIOR) {
        CloseDevice(ConIOR);
        DeleteStdIO(ConIOR);
    }
    if (ConPort)            DeletePort(ConPort);
    if (ClipReq) {
        CloseDevice(ClipReq);
        FreeMem(ClipReq, (LONG)sizeof(*ClipReq));
    }
    if (ClipPort)           DeletePort(ClipPort);
    if (startsignum != -1)  FreeSignal(startsignum);
    if (donesignum != -1)   FreeSignal(donesignum);
    if (cancelsignum != -1) FreeSignal(cancelsignum);
    if (movesignum != -1)   FreeSignal(movesignum);
    if (insertsignum != -1) FreeSignal(insertsignum);
    if (clicksignum != -1)  FreeSignal(clicksignum);
    if (timersignum != -1)  FreeSignal(timersignum);
    if (initsignum != -1)   FreeSignal(initsignum);
    if (port) {
        DeletePort(port);
    }
    if (IntuitionBase)      CloseLibrary(IntuitionBase);
    if (GfxBase)            CloseLibrary(GfxBase);
    if (LayersBase)         CloseLibrary(LayersBase);

    _exit(0L);
}

VOID OpenStuff()
{
    action = noaction;
    state  = waiting;
    inputRequestBlock = NULL;

    Sharedrefs = 0;
    Sharedport = NULL;

    Forbid();
    if (port = FindPort(SNAPPORT)) {
        Signal(port->mp_SigTask, SIGBREAKF_CTRL_C);
        Permit();
        port = NULL;  /* Don't touch his port */
        CloseStuff();
    }

    Permit();

    /* OK, we're here to stay. Set up everything we need. */

    /* libraries */

    if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L)))
        CloseStuff();
    if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0L)))
        CloseStuff();
    if (!(LayersBase = (struct LayersBase *)OpenLibrary("layers.library", 0L)))
        CloseStuff();

    /* public port */

    if (!(port = CreatePort(SNAPPORT, 0L)))
        CloseStuff();

    /* signals */

    if ((startsignum = AllocSignal(-1L)) == -1L)
        CloseStuff();
    if ((insertsignum = AllocSignal(-1L)) == -1L)
        CloseStuff();
    if ((cancelsignum = AllocSignal(-1L)) == -1L)
        CloseStuff();
    if ((donesignum = AllocSignal(-1L)) == -1L)
        CloseStuff();
    if ((movesignum = AllocSignal(-1L)) == -1L)
        CloseStuff();
    if ((clicksignum = AllocSignal(-1L)) == -1L)
        CloseStuff();
    if ((timersignum = AllocSignal(-1L)) == -1L)
        CloseStuff();
    if ((initsignum = AllocSignal(-1L)) == -1L)
        CloseStuff();
    MyTask = FindTask(0L);                   /* Find myself to Signal me.  */
    startsignal  = 1L << startsignum;         /* No good to use bit numbers */
    insertsignal = 1L << insertsignum;
    cancelsignal = 1L << cancelsignum;
    donesignal   = 1L << donesignum;
    movesignal   = 1L << movesignum;
    clicksignal  = 1L << clicksignum;
    timersignal  = 1L << timersignum;
    initsignal   = 1L << initsignum;

    /* input devive */

    if (!(inputDevPort = CreatePort(0L, 0L)))
        CloseStuff();
    if (!(inputRequestBlock = CreateStdIO(inputDevPort)))
        CloseStuff();
    if (OpenDevice("input.device", 0L, inputRequestBlock, 0L))
        CloseStuff();

    /* clipboard device */

    if (!(ClipPort = CreatePort(0L, 0L)))
        CloseStuff();
    if (!(ClipReq = AllocMem((LONG)sizeof(*ClipReq), MEMF_PUBLIC|MEMF_CLEAR)))
        CloseStuff();
    if (OpenDevice("clipboard.device", 0L, ClipReq, 0L))
        CloseStuff();
    ClipReq->io_Message.mn_ReplyPort = ClipPort;
    ClipReq->io_ClipID = 0L;

    /* console device */

    if (!(ConPort = CreatePort(0L, 0L)))
        CloseStuff();
    if (!(ConIOR = CreateStdIO(ConPort)))
        CloseStuff();
    if (OpenDevice("console.device", -1L, ConIOR, 0L))
        CloseStuff();

    /* temporary raster */

    if (!(TempRaster = AllocRaster(16L, 16L)))
        CloseStuff();
    InitRastPort(&TempRp);                   /* Init RastPort used for */
    InitBitMap(&TempBM, 1L, 16L, 16L);       /* Locating position of   */
    TempBM.Planes[0] = TempRaster;           /* first character.       */
    TempRp.BitMap = &TempBM;


    /* Aligned font bitmap to use when matching */

    CharData = AllocRaster(16L, 256L*16);
    if (!CharData) {
        CloseStuff();
    }


    /* input handler */

    handlerStuff.is_Data = 3;             /* Set up for installation of */
    handlerStuff.is_Code = myhandler;        /* myhandler.                 */
    handlerStuff.is_Node.ln_Pri = Priority;  /* Ahead of intuition, please */

    inputRequestBlock->io_Command = IND_ADDHANDLER;
    inputRequestBlock->io_Data    = (APTR)&handlerStuff;

    DoIO(inputRequestBlock);  /* Add me. */

}
