/*      SPACE CADET

        by Melissa Jordan Grey and Todor Fay

        (c) 1989 Blue Ribbon Bakery

*/

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <libraries/filehandler.h>
#include <stdio.h>
#include <intuition/intuition.h>
#include <graphics/gfxmacros.h>
#include <graphics/gfxbase.h>
#include <graphics/gfx.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <string.h>

extern struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

/* Window structure definition. */

struct NewWindow NewWindowStructure = {
        40,20,460,84,0,1,
        CLOSEWINDOW+DISKINSERTED+ACTIVEWINDOW+NEWSIZE,
        WINDOWSIZING+WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE+ACTIVATE+NOCAREREFRESH,
        NULL,NULL,"The Space Cadet    \251 1989 AMIGA Plus",
        NULL,NULL,25,25,-1,-1,WBENCHSCREEN
};

/* Icon of red space cadet (disk full.) */

UWORD fullspacecadet[] = {
  0x0,   0x0,   0x0,
  0x3,   0xfe00,   0x0,
  0x1f,   0xffc0,   0x0,
  0x7f,   0xfff0,   0x0,
  0xf0,   0xfff8,   0x0,
  0x1e6,   0x7ffc,   0x0,
  0x1e6,   0x783c,   0x0,
  0x1f0,   0xf39c,   0x0,
  0xff,   0xf838,   0x0,
  0x7e,   0x1ff0,   0x0,
  0x1e,   0xfc0,   0x0,
  0x7,   0x1e00,   0x0,
  0x0,   0xf800,   0x0,
  0x0,   0x7000,   0x0,
  0x0,   0x7000,   0x0,
  0x0,   0x7000,   0x0,
  0x0,   0x7800,   0x0,
  0xf,   0xffe0,   0x0,
  0x7f,   0xfff8,   0x0,
  0xff,   0xfff8,   0x0,
  0xe0,   0xfe1c,   0x0,
  0xe0,   0xfe0c,   0x0,
  0xe0,   0xfe06,   0x0,
  0xe0,   0xff03,   0x0,
  0x7fc0,   0xfe03,   0x0,
  0x3000,   0xfe03,   0x0,
  0x0,   0xfe07,   0x0,
  0x1,   0xfe01,   0x0,
  0x3,   0xfe00,   0x0,
  0x3,   0x8e00,   0x0,
  0x3,   0x8e00,   0x0,
  0x3,   0xf00,   0x0,
  0x3,   0xf00,   0x0,
  0x3,   0xe00,   0x0,
  0xff,   0xe00,   0x0,
  0x1ff,   0x8ffc,   0x0,
  0x0,   0x0,   0x0,
  0x3,   0xfe00,   0x0,
  0x1f,   0xffc0,   0x0,
  0x7f,   0xfff0,   0x0,
  0xff,   0xfff8,   0x0,
  0x1ff,   0xfffc,   0x0,
  0x3ff,   0xfffe,   0x0,
  0x3ff,   0xfffe,   0x0,
  0x3ff,   0xfffe,   0x0,
  0x1ff,   0xfffc,   0x0,
  0xff,   0xfff8,   0x0,
  0x7f,   0x3ff0,   0x0,
  0x1f,   0xffc0,   0x0,
  0x7,   0xfe00,   0x0,
  0x0,   0xf800,   0x0,
  0x0,   0xf800,   0x0,
  0x0,   0xf800,   0x0,
  0x1f,   0xfff0,   0x0,
  0xff,   0xfffc,   0x0,
  0x1ff,   0xfffc,   0x0,
  0x1ff,   0xfffe,   0x0,
  0x1ff,   0xfffe,   0x0,
  0x1f1,   0xff3f,   0x0,
  0x1f1,   0xff9f,   0x8000,
  0xfff1,   0xff8f,   0x8000,
  0xfff1,   0xff87,   0x8000,
  0x7fe1,   0xff0f,   0x8000,
  0x7803,   0xff0f,   0x8000,
  0x7,   0xff07,   0xc000,
  0x7,   0xff03,   0x8000,
  0x7,   0xff00,   0x0,
  0x7,   0xdf80,   0x0,
  0x7,   0x9f80,   0x0,
  0x7,   0x9f80,   0x0,
  0x1ff,   0x9f80,   0x0,
  0x7ff,   0xdffe,   0x0,
  0x7ff,   0xdfff,   0x0,
  0x3ff,   0xdffe,   0x0
};

struct Image fullspacecadetimage = {
    0,0,34,37,2,fullspacecadet,
    0x1f,0x00,NULL,
 };

/* Icon for empty space cadet. */

UWORD emptyspacecadet[] = {
  0x0,   0x0,   0x0,
  0x3,   0xfe00,   0x0,
  0x1f,   0xffc0,   0x0,
  0x7f,   0xfff0,   0x0,
  0xf0,   0xfff8,   0x0,
  0x1e6,   0x7ffc,   0x0,
  0x1e6,   0x783c,   0x0,
  0x1f0,   0xf39c,   0x0,
  0xff,   0xf838,   0x0,
  0x7e,   0x1ff0,   0x0,
  0x1e,   0xfc0,   0x0,
  0x7,   0x1e00,   0x0,
  0x0,   0xf800,   0x0,
  0x0,   0x7000,   0x0,
  0x0,   0x7000,   0x0,
  0x0,   0x7000,   0x0,
  0x0,   0x7800,   0x0,
  0xf,   0xffe0,   0x0,
  0x7f,   0xfff8,   0x0,
  0xff,   0xfff8,   0x0,
  0xe0,   0xfe1c,   0x0,
  0xe0,   0xfe0c,   0x0,
  0xe0,   0xfe06,   0x0,
  0xe0,   0xff03,   0x0,
  0x7fc0,   0xfe03,   0x0,
  0x3000,   0xfe03,   0x0,
  0x0,   0xfe07,   0x0,
  0x1,   0xfe01,   0x0,
  0x3,   0xfe00,   0x0,
  0x3,   0x8e00,   0x0,
  0x3,   0x8e00,   0x0,
  0x3,   0xf00,   0x0,
  0x3,   0xf00,   0x0,
  0x3,   0xe00,   0x0,
  0xff,   0xe00,   0x0,
  0x1ff,   0x8ffc,   0x0,
  0x0,   0x0,   0x0,
  0x3,   0xfe00,   0x0,
  0x1c,   0x1c0,   0x0,
  0x60,   0x30,   0x0,
  0x80,   0x8,   0x0,
  0x10f,   0x4,   0x0,
  0x21f,   0x8002,   0x0,
  0x21f,   0x87c2,   0x0,
  0x20f,   0xfe2,   0x0,
  0x100,   0x7c4,   0x0,
  0x81,   0xe008,   0x0,
  0x61,   0x3030,   0x0,
  0x18,   0xe1c0,   0x0,
  0x7,   0x600,   0x0,
  0x0,   0x8800,   0x0,
  0x0,   0x8800,   0x0,
  0x0,   0x8800,   0x0,
  0x1f,   0x87f0,   0x0,
  0xf0,   0x1c,   0x0,
  0x180,   0x4,   0x0,
  0x100,   0x6,   0x0,
  0x11f,   0x1e2,   0x0,
  0x111,   0x133,   0x0,
  0x111,   0x199,   0x8000,
  0xff11,   0x8c,   0x8000,
  0x8031,   0x184,   0x8000,
  0x4fe1,   0x10c,   0x8000,
  0x7803,   0x108,   0x8000,
  0x6,   0x106,   0xc000,
  0x4,   0x103,   0x8000,
  0x4,   0x7100,   0x0,
  0x4,   0x5180,   0x0,
  0x4,   0x9080,   0x0,
  0x4,   0x9080,   0x0,
  0x1fc,   0x9180,   0x0,
  0x700,   0xd1fe,   0x0,
  0x600,   0x5003,   0x0,
  0x3ff,   0xdffe,   0x0
};

struct Image emptyspacecadetimage = {
    0,0,34,37,2,emptyspacecadet,
    0x1f,0x00,NULL,
};

/* We need a data structure to store info about each disk. */

struct Volume {
    struct Volume *next;        /* Linked list of volumes. */
    char name[100];             /* Volume name. */
    int ratio;                  /* Used / Full ratio. */
    short width;                /* Width of name text. */
    short leftedge;             /* Left edge for drawing. */
    short topedge;              /* Top edge for drawing. */
};

struct Volume *getvolumes()

/*      Getvolumes finds out what disk volumes are
        currently in the system and returns a
        linked list of Volume structures with all the
        needed information.
*/

{
    extern struct DosLibrary *DOSBase;
    struct RootNode *rootnode;
    struct DosInfo *dosinfo;
    struct DeviceNode *devicenode;
    struct InfoData *infodata;
    struct Volume *top = 0;
    struct Volume *volume;
    int lock;
    char *bptrname;
    char name[100];
    int width;
    infodata = (struct InfoData *) AllocMem(sizeof(struct InfoData),0);
    rootnode = (struct RootNode *)  DOSBase->dl_Root;
    dosinfo = (struct DosInfo  *)  BADDR(rootnode->rn_Info);
    devicenode = (struct DeviceNode *) BADDR(dosinfo->di_DevInfo);
    for (;BADDR(devicenode);
      devicenode = (struct DeviceNode *) BADDR(devicenode->dn_Next)) {
        if((devicenode->dn_Type==2) && BADDR(devicenode->dn_Name)) {
            bptrname = (char *) BADDR(devicenode->dn_Name);
            memcpy(name,&bptrname[1],(ULONG)bptrname[0]+1L);
            name[bptrname[0]] = 0;
            strcat(name,":");
            if (stricmp(name,"Ram Disk:"))
                lock = Lock(name,ACCESS_READ);
            else lock = 0;
            if (lock) {
                if (Info(lock,infodata)) {
                    volume = (struct Volume *) AllocMem(sizeof(struct Volume),0);
                    if (volume) {
                        volume->next = top;
                        top = volume;
                        name[strlen(name)-1] = 0;
                        strcpy(volume->name,name);
                        width = strlen(name) << 3;
                        if (width < 50) width = 50;
                        volume->width = width + 12;
                        volume->ratio = (infodata->id_NumBlocksUsed << 16) /
                            infodata->id_NumBlocks;
                    }
                }
                UnLock(lock);
            }
        }
    }
    FreeMem(infodata,sizeof(struct InfoData));
    return(top);
}

void freevolumes(volume)

/*      Dispose of a list of volumes.
*/

struct Volume *volume;

{
    struct Volume *next;
    for (;volume;) {
        next = volume->next;
        FreeMem(volume,sizeof(struct Volume));
        volume = next;
    }
}

drawslice(rp,image,x,y,start,finish)

/*      Draw just a section of the image.
        X and Y select where the image starts.
        Start specifies which row of the image
        to start drawing with.  Finish specifies
        at which row to stop.
*/

struct RastPort *rp;
struct Image *image;
short x,y,start,finish;

{
    struct Image newimage;
    char *newimagedata;
    char *oldimagedata = (char *) image->ImageData;
    short datasize;
    short bytewidth = ((image->Width + 15) >> 4) << 1;
    short indent;
    short plane;
    short index = 0;
    short shortrange;
    short longrange;
    shortrange = (finish - start) * bytewidth;
    longrange = image->Height * bytewidth;
    datasize = image->Depth * shortrange;
    if (datasize) {
        newimagedata = (short *) AllocMem(datasize,MEMF_CHIP);
        if (newimagedata) {
            for (plane = 0; plane< image->Depth; plane++) {
                indent = (start * bytewidth) + (plane * longrange);
                memcpy(&newimagedata[index],&oldimagedata[indent],shortrange);
                index += shortrange;
            }
            memcpy((char *)&newimage,(char *)image,sizeof(struct Image));
            newimage.Height = finish - start;
            newimage.ImageData = newimagedata;
            DrawImage(rp,&newimage,x,y);
            FreeMem(newimagedata,datasize);
        }
    }
}

void drawspacecadet(window,volume)

/*      Given a window and a volume, draw a space
        cadet.
*/

struct Window *window;
struct Volume *volume;

{
    struct RastPort *rp = window->RPort;
    int line, len;
    len = strlen(volume->name);
    line = volume->ratio;
    line = line * 36;
    line = line >> 16;
    line = 37 - line;
    if (line <= 0) line = 1;
    drawslice(rp,&emptyspacecadetimage,volume->leftedge,volume->topedge,0,line);
    drawslice(rp,&fullspacecadetimage,volume->leftedge,volume->topedge+line,line,37);
    SetDrMd(rp,JAM2);
    SetAPen(rp,1);
    SetBPen(rp,0);
    Move(rp,volume->leftedge + 18 - (len << 2),volume->topedge + 50);
    Text(rp,volume->name,len);
}

main()

/*      The main routine opens the Space Cadet window and
        waits for Intuition events.   Each time an ACTIVEWINDOW,
        NEWSIZE, or DISKINSERTED message comes in, getvolumes is
        called to find out what disks are in and how full they
        are, then space cadets are drawn in the window for each
        volume.
*/

{
    struct IntuiMessage *message;
    struct Window *window;
    struct Volume *volume, *firstvolume;
    int totalwidth;
    int height;
    IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",0);
    GfxBase = (struct GfxBase *) OpenLibrary("graphics.library",0);
    window = (struct Window *) OpenWindow(&NewWindowStructure);
    if (window) {
        for (;;) {
            firstvolume = getvolumes();
            totalwidth = 20;
            height = 20;
            for (volume = firstvolume;volume;volume = volume->next) {
                if ((totalwidth + volume->width) > (window->Width - 30)) {
                    totalwidth = 20;
                    height += 70;
                }
                volume->leftedge = totalwidth + (volume->width >> 1);
                totalwidth += volume->width;
                volume->topedge = height;
            }
            SetRast(window->RPort,0);
            RefreshWindowFrame(window);
            for (volume = firstvolume;volume;volume = volume->next) {
                drawspacecadet(window,volume);
            }
            freevolumes(firstvolume);
            WaitPort(window->UserPort);
            message = (struct IntuiMessage *) GetMsg(window->UserPort);
            if (message->Class == CLOSEWINDOW) break;
            ReplyMsg((struct Message *)message);
        }
        CloseWindow(window);
    }
    CloseLibrary(GfxBase);
    CloseLibrary(IntuitionBase);
}
