#if __SASC
#include "snap.h"
#endif

/* Auto: make
*/

IMPORT BOOL Kick36;

IMPORT struct GfxBase *GfxBase;

IMPORT struct SnapRsrc *SnapRsrc;
IMPORT struct Image DiskImage;
IMPORT struct Image ClipImage;
IMPORT struct Gadget DiskGad;
IMPORT struct Gadget ClipGad;
IMPORT struct Gadget VProp, HProp;
IMPORT struct PropInfo VInfo, HInfo;
IMPORT struct Image VImage, HImage;
IMPORT struct NewWindow Nw;
IMPORT UBYTE *WindowTitle;

IMPORT LONG xl; /* leftmost x position */
IMPORT LONG xr; /* rightmost x position */
IMPORT LONG yt; /* topmost y position */
IMPORT LONG yb; /* bottommost y position */
IMPORT LONG mx, my; /* Mouse position in pixels */

#define GfxFrame 4L
IMPORT Point OldFrame[];
IMPORT Point NewFrame[];
IMPORT LONG OFType;        /* Old frame type: ShortFrame/LongFrame */
IMPORT UWORD Ptrn;
IMPORT WORD Pattern[];

IMPORT struct RastPort MyRP;
IMPORT struct BitMap MyBM;
IMPORT struct Screen *theScreen;
struct Layer_Info *LockedLayerInfo;
IMPORT struct RastPort rp;

IMPORT struct timerequest MyTR;

IMPORT LONGBITS cancelsignal, donesignal, movesignal;
IMPORT LONGBITS clicksignal, ticksignal, timersignal;
IMPORT WORD action;

LONG TopBar;
LONG LeftBar;
LONG RightBar;
LONG BottomBar;
LONG ScreenFontHeight;
struct TextFont *ScreenFont;

VOID FixHeights()
{
    struct Screen WBScreen;

    OpenWorkBench();
    if (GetScreenData((char *)&WBScreen, (LONG)sizeof(struct Screen), WBENCHSCREEN, NULL)) {
          /* Now this is a good practice */
        TopBar = WBScreen.WBorTop + WBScreen.RastPort.TxHeight + 1;
        LeftBar = WBScreen.WBorLeft;
        RightBar = WBScreen.WBorRight;
        BottomBar = WBScreen.WBorBottom;
        ScreenFont = WBScreen.RastPort.Font;
        if (!ScreenFont) {
            Forbid();
            ScreenFont = GfxBase->DefaultFont;
            Permit();
        }
        ScreenFontHeight = ScreenFont->tf_YSize;
    } else {
          /* Sorry, but I don't realise how this could fail.
             Well, if we're snapping on another screen and
             WB is closed and it can't be opened by GetScreenData()...
             Anyway, IF this should happen -- Use Topaz 8 */
        TopBar = 10;
        LeftBar = 2;
        RightBar = 2;
        BottomBar = 1;
        ScreenFontHeight = 8;
        Forbid();
        ScreenFont = GfxBase->DefaultFont;
        Permit();
    }
}

/* SnapGfx is the actual graphics snapper.
** It steals the bitmap data from the given rastport
** and puts it in a separate bitmap.
** It also prepares the NewWindow structure according
** to the snapped bitmap.
** The coordinates are assumed to be valid.
*/

struct GfxSnap *SnapGfx(rp)
struct RastPort *rp;
{
    struct GfxSnap *GS;
    LONG i;

    GS = Create(GfxSnap);
    if (!GS) {
        return NULL;
    }

    GS->x = xl;
    GS->y = yt;
    GS->width = xr - xl + 1;
    GS->height = yb - yt + 1;
    if (xr < xl + MINWIDTH) {          /* Can't have too small windows */
        xr = xl + MINWIDTH;
    }
    if (yb < yt + MINHEIGHT) {
        yb = yt + MINHEIGHT;
    }
    GS->depth = rp->BitMap->Depth;
    GS->viewmode = theScreen->ViewPort.Modes;
    GS->pagew = theScreen->Width;
    GS->pageh = theScreen->Height;
    i = (GS->viewmode & HAM ? 16 : 1L << GS->depth);
      /* Copy the color map in case we should need it later */
    while (i--) {
        ULONG col = GetRGB4(theScreen->ViewPort.ColorMap, i);
        GS->rgb[i][0] = ((col >> 8) & 0x0f) << 4;
        GS->rgb[i][1] = ((col >> 4) & 0x0f) << 4;
        GS->rgb[i][2] = ((col >> 0) & 0x0f) << 4;
    }
      /* Set up a nice bitmap */
    InitBitMap(&GS->BM, GS->depth, GS->width, GS->height);
      /* Get a handle on the bitmap */
    InitRastPort(&MyRP);
    MyRP.BitMap = &GS->BM;
    if (!AllocPlanes(&GS->BM, GS->width, GS->height)) {
        FreePlanes(&GS->BM, GS->width, GS->height);
        Kill(GS);
        return NULL;
    }
      /* Copy the selected part of the screen */
    ClipBlit(rp, xl, yt, &MyRP, 0L, 0L, GS->width, GS->height, 0xC0L);
    if (!Kick36) {
        VInfo.Flags |= PROPBORDERLESS;
        HInfo.Flags |= PROPBORDERLESS;
    }
    CopyMem((char *)&DiskGad, (char *)&GS->DiskGad,
      (LONG)sizeof(DiskGad) + sizeof(ClipGad) + sizeof(VProp) + sizeof(HProp) +
      sizeof(VInfo) + sizeof(HInfo) + sizeof(VImage) + sizeof(HImage));
    GS->topbar = TopBar;
    GS->leftbar = LeftBar;
    GS->rightbar = 18; /* (Kick36 ? RightBar : 18); */
    GS->bottombar = 10;

    Nw.LeftEdge = xl;
    Nw.TopEdge = yt;
    Nw.Width = xr - xl + 1 + GS->leftbar + GS->rightbar;
    Nw.Height = yb - yt + 1 + GS->topbar + GS->bottombar;
    Nw.Flags &= ~(SIMPLE_REFRESH | SMART_REFRESH | NOCAREREFRESH);
    Nw.Flags |= (SnapRsrc->flags & SIMPLEREFRESH ?
      SIMPLE_REFRESH : SMART_REFRESH | NOCAREREFRESH);

    Nw.Title = WindowTitle;
    Nw.MinWidth = MINWIDTH + 1 + GS->leftbar + GS->rightbar;
    Nw.MinHeight = MINHEIGHT + 1 + GS->topbar + GS->bottombar;
    Nw.MaxWidth = Nw.Width;
    Nw.MaxHeight = Nw.Height;

    if (Kick36) Nw.Flags |= SIZEBBOTTOM|SIZEBRIGHT;

    return GS;
}

VOID ExtendGfx()
{
    /* Fix which row we're talking about */
    if (my - yt < yb - my) {   /* Find closest row */
        yt = my;               /* change top row */
    } else {
        yb = my;               /* change bottom row */
    }
    if (mx - xl < xr - mx) {
        xl = mx;
    } else {
        xr = mx;
    }
}

VOID gfx_frame()
{
    NewFrame[0].x = xl;  NewFrame[0].y = yt;
    NewFrame[1].x = xr;  NewFrame[1].y = yt;
    NewFrame[2].x = xr;  NewFrame[2].y = yb;
    NewFrame[3].x = xl;  NewFrame[3].y = yb;
    NewFrame[4].x = xl;  NewFrame[4].y = yt;
    draw_frame(GfxFrame);
}

WORD HandleGfx()
{
    theScreen = WhichScreen();   /* Find out where we are */
    if (!theScreen) {            /* Don't know? Forget it. */
        action = noaction;
        return 0;
    }
      /* Lock everything - find out what happens */
    LockedLayerInfo = &theScreen->LayerInfo;
    LockLayers(LockedLayerInfo);

      /* Get a copy. Don't mess with somebody else's RP. */
    CopyMem((char *)&theScreen->RastPort, (char *)&rp, (long)sizeof(struct RastPort));
    SetDrMd(&rp, COMPLEMENT);

    xl = theScreen->MouseX + theScreen->ViewPort.RasInfo->RxOffset;
    if (xl < 0) {
        xl = 0;
    }
    if (xl >= theScreen->Width) {  /* Check those corners. Check those corners. */
        xl = theScreen->Width - 1;
    }
    yt = theScreen->MouseY + theScreen->ViewPort.RasInfo->RyOffset;
    if (yt < 0) {
        yt = 0;
    }
    if (yt >= theScreen->Height) {
        yt = theScreen->Height - 1;
    }
    xr = xl;
    yb = yt;
    Ptrn = (SnapRsrc->CrawlPtrn ? SnapRsrc->CrawlPtrn : Pattern[UNIT_FRAME]);
    OFType = 0L;
    gfx_frame();

    FOREVER {
        REGISTER LONGBITS sig;

        MyTR.tr_time.tv_secs = 0;
        MyTR.tr_time.tv_micro = 500000;
        MyTR.tr_node.io_Command = TR_ADDREQUEST;
        SendIO((struct IORequest *)&MyTR);

        sig = Wait(movesignal | clicksignal | cancelsignal |
          donesignal | ticksignal | timersignal);

        if (CheckIO((struct IORequest *)&MyTR)) {
            WaitIO((struct IORequest *)&MyTR);
            erase_frame();
            UnlockLayers(LockedLayerInfo);  /* Unlock things */
            sig = Wait(ticksignal);         /* Wait for input handler to become avtive */
            LockLayers(LockedLayerInfo);    /* Re-lock */
              /* I guess I should check to see that the window is still
                 there. Aw, what the heck. Apologies to anyone who gets
                 bitten by this. */
            DisplayBeep(NULL);
            gfx_frame();
        } else {
            AbortIO((struct IORequest *)&MyTR);
            WaitIO((struct IORequest *)&MyTR);
            SetSignal(0, timersignal);
        }

        if ((sig & ticksignal) && (SnapRsrc->CrawlPtrn != 0xffff)) {
            crawl_frame(1L);
        }

        if (sig & movesignal || sig & clicksignal) {
            mx = theScreen->MouseX + theScreen->ViewPort.RasInfo->RxOffset;
            if (mx < 0) {
                mx = 0;
            }
            if (mx>=theScreen->Width) {
                mx = theScreen->Width - 1;
            }
            my = theScreen->MouseY + theScreen->ViewPort.RasInfo->RyOffset;
            if (my < 0) {
                my = 0;
            }
            if (my>=theScreen->Height) {
                my = theScreen->Height - 1;
            }
            ExtendGfx();
            gfx_frame();
        }
        if (sig & cancelsignal) {          /* Cancelled? */
            erase_frame();
            UnlockLayers(LockedLayerInfo);
            return 0;
        }
        if (sig & donesignal) {            /* Finished. Copy gfx. */
            struct GfxSnap *GS;

            erase_frame();
            if (xl == xr || yt == yb) {
                action = noaction;
                UnlockLayers(LockedLayerInfo);
                return 0;
            }
            if (xr >= theScreen->Width) {
                xl -= xr - theScreen->Width - 1;
                xr = theScreen->Width - 1;
            }
            if (yb >= theScreen->Height) {
                yt -= yb - theScreen->Height - 1;
                yb = theScreen->Height - 1;
            }
            FixHeights();
            GS = SnapGfx(&rp); /* Snap! */
            UnlockLayers(LockedLayerInfo);
            if (GS) {
                if (GS->window = opensharedwindow(&Nw)) {
                    if (SnapRsrc->flags & SIMPLEREFRESH) {
                        ModifyIDCMP(GS->window,
                          GS->window->IDCMPFlags | REFRESHWINDOW);
                    }
                    if (Kick36) {
                        GS->topbar = GS->window->BorderTop;
                        GS->leftbar = GS->window->BorderLeft;
                        GS->rightbar = GS->window->BorderRight;
                        GS->bottombar = 10;/*GS->window->BorderBottom;*/

                        GS->HProp.TopEdge = -7;
                        GS->HProp.Height = 6;
                    }

                    GS->DiskGad.TopEdge    = GS->topbar;
                    GS->DiskGad.LeftEdge   = (Kick36 ? -17 : -14);
                    GS->DiskGad.Width      = (Kick36 ? 18 : 14);
                    GS->ClipGad.TopEdge    = GS->DiskGad.TopEdge + 12;
                    GS->ClipGad.LeftEdge   = (Kick36 ? -17 : -14);
                    GS->ClipGad.Width      = (Kick36 ? 18 : 14);
                    GS->HProp.GadgetRender = (APTR)&GS->HImage;
                    GS->HProp.SpecialInfo  = (APTR)&GS->HInfo;
                    GS->VProp.TopEdge      = 
                      GS->ClipGad.TopEdge + (Kick36 ? 14 : 15);
                    GS->VProp.LeftEdge     = (Kick36 ? 5 : 7) - GS->rightbar;
                    GS->VProp.Width        = GS->rightbar - (Kick36 ? 8 : 10);
                    GS->VProp.Height       = 
                      (Kick36 ? -28 : -27) - GS->bottombar - GS->topbar;
                    GS->VProp.GadgetRender = (APTR)&GS->VImage;
                    GS->VProp.SpecialInfo  = (APTR)&GS->VInfo;

                    GS->DiskGad.NextGadget = &GS->ClipGad;
                    GS->ClipGad.NextGadget = &GS->VProp;
                    GS->VProp.NextGadget   = &GS->HProp;
                    GS->HProp.NextGadget   = NULL;

                    AddGList(GS->window, &GS->DiskGad, -1, -1, NULL);
                    GS->window->UserData = (BYTE *)GS;
                      /* Put gfx in our new window */
                    AdjustSize(GS);
                } else {
                    FreePlanes(&GS->BM, GS->width, GS->height);
                    Kill(GS);
                }
            } else { /* Good question */
            }
            action = noaction;
            return 0;
        }
    }
}
