#include <intuition/intuitionbase.h>
#include <libraries/dos.h>
#include <graphics/gfxmacros.h>
#include <graphics/sprite.h>
#include <devices/printer.h>
#include <exec/memory.h>
#include <exec/types.h>
#include <functions.h>

#define ACTIVE_SCREEN ((struct Screen *)(IntuitionBase?IntuitionBase->ActiveScreen:NULL))
#define ACTIVE_WINDOW ((struct Window *)(IntuitionBase?IntuitionBase->ActiveWindow:NULL))
#define CircFill(RP,col,x,y,r) EllFill(RP,col,x,y,r,r)
#define FreeFile(buffer,size) FreeMem(buffer,size)
#define TYPE (eintrag->fib_DirEntryType)
#define NAME (eintrag->fib_FileName)
#define SIZE (eintrag->fib_Size)
#define REQ   0
#define DMREQ 1
#define DIRS  2
#define FILES 4
#define FLEN 31

struct IntuitionBase *IntuitionBase=NULL;
struct GfxBase       *GfxBase=NULL;


/*
\\	Libraries öffnen/schließen
*/

SHORT OpenLib()
{/* Libraries öffnen */
    if(!(IntuitionBase=(struct IntuitionBase *)
       OpenLibrary("intuition.library",0)))   return(1);
    if(!(GfxBase=(struct GfxBase *)
       OpenLibrary("graphics.library",0)))    return(2);
    return(0);
}

VOID CloseLib()
{/* Libraries schließen */
    if(GfxBase)       CloseLibrary(GfxBase);
    if(IntuitionBase) CloseLibrary(IntuitionBase);
}

/*
\\        Intuition-Tools 
*/

struct Screen *GetScreen(top,depth,modes,title)
    SHORT top,depth;
    USHORT modes;
    STRPTR title;
{/* Screen öffnen */
    struct NewScreen nscr;

    nscr.LeftEdge     = 0;
    nscr.TopEdge      = top;
    nscr.Width        = 320*((modes&HIRES)?2:1);
    nscr.Height       = 256*((modes&LACE) ?2:1);
    nscr.Depth        = depth;
    nscr.DetailPen    = 0;
    nscr.BlockPen     = 1;
    nscr.ViewModes    = modes;
    nscr.Type         = WBENCHSCREEN;
    nscr.Font         = NULL;
    nscr.DefaultTitle = title;
    nscr.Gadgets      = NULL;
    nscr.CustomBitMap = NULL;
    return(OpenScreen(&nscr));
}

struct Window *GetWindow(scr,left,top,width,height,idcmp,flags,title,gad)
    struct Screen *scr;
    SHORT left,top,width,height;
    ULONG idcmp,flags;
    STRPTR title;
    struct Gadget *gad;
{/* Window öffnen */
    struct NewWindow nwin;

    scr=scr?scr:ACTIVE_SCREEN;
    nwin.LeftEdge   = left;
    nwin.TopEdge    = top;
    nwin.Width      = width;
    nwin.Height     = height;
    nwin.DetailPen  = -1;
    nwin.BlockPen   = -1;
    nwin.IDCMPFlags = idcmp;
    nwin.Flags      = flags;
    nwin.FirstGadget= gad;
    nwin.CheckMark  = NULL;
    nwin.Title      = title;
    nwin.Screen     = scr;
    nwin.BitMap     = NULL;
    nwin.MinWidth   = 20;
    nwin.MinHeight  = 20;
    nwin.MaxWidth   = (scr->Width)-left;
    nwin.MaxHeight  = (scr->Height)-top;
    nwin.Type       = WBENCHSCREEN;
    return(OpenWindow(&nwin));
}

SHORT GetGadget(gad,WorG,left,top,width,height,f,act,type,gr,sr,text,info,id)
    struct Gadget *gad;
    APTR WorG; /* struct Window oder struct Gadget */
    struct IntuiText *text;
    APTR gr,sr,info;
    SHORT left,top,width,height,id;
    USHORT f,act,type;
{/* Gadget-Struktur initialisieren und in Gadget-Liste einfügen */
    SHORT nr;

    gad->NextGadget   = (type&REQGADGET)?(struct Gadget *)WorG:NULL;
    gad->LeftEdge     = left;
    gad->TopEdge      = top;
    gad->Width        = width;
    gad->Height       = height;
    gad->Flags        = f;
    gad->Activation   = act;
    gad->GadgetType   = type;
    gad->GadgetRender = gr;
    gad->SelectRender = sr;
    gad->GadgetText   = text;
    gad->MutualExclude= NULL;
    gad->SpecialInfo  = info;
    gad->GadgetID     = id;
    gad->UserData     = NULL;
    if(type&REQGADGET)    return(0);
    nr=AddGadget(WorG,gad,-1);
    RefreshGadgets(gad,WorG,NULL);
    return(nr);
}

VOID GetMenu(men,win,left,width,flags,titel)
    struct Menu   *men;
    struct Window *win;
    SHORT left,width;
    USHORT flags;
    BYTE *titel;
{/* Menu-Struktur initialisieren und in die Menu-Liste einfügen */
    men->NextMenu  = win->MenuStrip;
    men->LeftEdge  = left;
    men->TopEdge   = 0;
    men->Width     = width;
    men->Height    = 10;
    men->Flags     = flags;
    men->MenuName  = titel;
    men->FirstItem = NULL;
    win->MenuStrip = men;
}

VOID GetItem(menu,item,left,top,width,height,flags,mutex,Ifill,Sfill,com)
    struct Menu *menu;
    struct MenuItem *item;
    SHORT left,top,width,height;
    USHORT flags;
    LONG mutex;
    APTR Ifill,Sfill;
    BYTE com;
{/* MenuItem-Struktur initialisieren und in die Item-Liste einfügen */
    item->NextItem     = menu->FirstItem;
    item->LeftEdge     = left;
    item->TopEdge      = top;
    item->Width        = width;
    item->Height       = height;    
    item->Flags        = flags;
    item->MutualExclude= mutex;
    item->ItemFill     = Ifill;
    item->SelectFill   = Sfill;
    item->Command      = com;
    item->SubItem      = NULL;
    menu->FirstItem    = item;
}

VOID GetSItem(item,sitem,left,top,width,height,flags,mutex,Ifill,Sfill,com)
    struct MenuItem *item;
    struct MenuItem *sitem;
    SHORT left,top,width,height;
    USHORT flags;
    LONG mutex;
    APTR Ifill,Sfill;
    BYTE com;
{/* SubItem initialisieren und in die SubItem-Liste einfügen */
    sitem->NextItem     = item->SubItem;
    sitem->LeftEdge     = left;
    sitem->TopEdge      = top;
    sitem->Width        = width;
    sitem->Height       = height;    
    sitem->Flags        = flags;
    sitem->MutualExclude= mutex;
    sitem->ItemFill     = Ifill;
    sitem->SelectFill   = Sfill;
    sitem->Command      = com;
    sitem->SubItem      = NULL;
    item->SubItem       = sitem;
}

SHORT GetRequest(req,win,l,t,w,h,rl,rt,gad,rand,text,flags,bf,dm)
    struct Requester *req;
    struct Window *win;
    SHORT l,t,w,h,rl,rt,dm;
    struct Gadget *gad;
    struct Border *rand;
    struct IntuiText *text;
    USHORT flags;
    UBYTE bf;
{/* frei definierbares Requester installieren */

    InitRequester(req);
    req->LeftEdge =l;
    req->TopEdge  =t;
    req->Width    =w;
    req->Height   =h;
    req->RelLeft  =rl;
    req->RelTop   =rt;
    req->ReqGadget=gad;
    req->ReqBorder=rand;
    req->ReqText  =text;
    req->Flags    =flags;
    req->BackFill =bf;
    if(dm==DMREQ) return(SetDMRequest(win,req));
    return(Request(req,win));
}

ULONG GetMessage(win,code,id,qual)
    struct Window *win;
    USHORT *code,*id,*qual;
{/* MsgPort auslesen; liefert CLASS,CODE,QUALIFIER der Msg und GadgetID */
    struct IntuiMessage *msg;
    ULONG class=0;

    if(msg=(struct IntuiMessage *)GetMsg(win->UserPort)){
        class=msg->Class;
        if(code) *code=msg->Code;
        if(id)   *id  =(((struct Gadget *)msg->IAddress)->GadgetID);
        if(qual) *qual=msg->Qualifier;
        ReplyMsg(msg);
    }
    else{
        if(code) *code=0;
        if(id)   *id  =0;
        if(qual) *qual=0;
    }
    return(class);
}


/*
\\          Grafik-Tools
*/


VOID Line(RP, col, x1, y1, x2, y2)
    struct RastPort *RP;
    SHORT col, x1, y1, x2, y2;
{/* Linie zeichnen */
    SetDrMd(RP, JAM1);
    SetAPen(RP, col);
    Move(RP,x1,y1);
    Draw(RP,x2,y2);
}

VOID ILine(RP, x1, y1, x2, y2)
    struct RastPort *RP;
    SHORT x1, y1, x2, y2;
{/* Linie im JAM1|COMPLEMENT-Modus zeichnen */
    SetDrMd(RP, JAM1|COMPLEMENT);
    Move(RP,x1,y1);
    Draw(RP,x2,y2);
}

VOID Block(RP, col, x1, y1, x2, y2)
    struct RastPort *RP;
    SHORT col,x1,y1,x2,y2;
{/* Block zeichnen */
    if(!((x1>x2) || (y1>y2))){
        SetDrMd(RP, JAM1);
        SetAPen(RP, col);
        RectFill(RP, x1, y1, x2, y2);
    }
}

VOID IBlock(RP, x1, y1, x2, y2)
    struct RastPort *RP;
    SHORT x1,y1,x2,y2;
{/* Block im JAM1|COMPLEMENT-Modus zeichnen */
    if(!((x1>x2) || (y1>y2))){
        SetDrMd(RP, JAM1|COMPLEMENT);
        RectFill(RP, x1, y1, x2, y2);
    }
}

VOID IRast(RP)
    struct RastPort *RP;
{/* RastPort im JAM1|COMPLEMENT-Modus darstellen */
    IBlock(RP,0,0,RP->BitMap->BytesPerRow*8,RP->BitMap->Rows);
}

VOID GetPos(RP, x, y)
    struct RastPort *RP;
    SHORT *x, *y;
{/* Position des Grafikcursors im RastPort ermitteln */
    *x=RP->cp_x;
    *y=RP->cp_y;
}

SHORT GetCol(VP,nr, r,g,b)
    struct ViewPort *VP;
    SHORT nr, *r,*g,*b;
{/* Farbregister auslesen */
    SHORT col;

    col= GetRGB4(VP->ColorMap,nr);
    *r = (col>>8)&15;
    *g = (col>>4)&15;
    *b = col&15;
    return(col);
}

VOID Print(RP, text, col, xpos, ypos)
    struct RastPort *RP;
    STRPTR text;
    SHORT col, xpos, ypos; 
{/* Ausgabe eines Textes */
    SetDrMd(RP, JAM1);
    SetAPen(RP, col);
    Move(RP, xpos, ypos+RP->TxBaseline);
    Text(RP, text, strlen(text));
}

SHORT EllFill(RP, col, x, y, rh, rv)
    struct RastPort *RP;
    SHORT col, x, y, rh, rv;
{/* ausgefüllte Ellipse in beliebiger Farbe zeichnen */
    struct TmpRas *Raster;
    struct AreaInfo *AInfo;
    PLANEPTR Bitplane;
    WORD Buffer[10];
    BOOL error=1;
    SHORT height=3*rh,width=3*rv;

    if((Bitplane=AllocRaster(width,height))&&
       (Raster=(struct TmpRas *)AllocMem(sizeof(struct TmpRas),MEMF_CLEAR))&&
       (AInfo=(struct AreaInfo *)AllocMem(sizeof(struct AreaInfo),MEMF_CLEAR))){
           SetAPen(RP,col);
           InitTmpRas(Raster,Bitplane,RASSIZE(width,height));
           RP->TmpRas=Raster; 
           InitArea(AInfo,Buffer,2);
           RP->AreaInfo=AInfo;
           error=AreaEllipse(RP,x,y,rh,rv);
           AreaEnd(RP);
    }
    if(AInfo)    FreeMem(AInfo,sizeof(struct AreaInfo));
    if(Raster)   FreeMem(Raster,sizeof(struct TmpRas));
    if(Bitplane) FreeRaster(Bitplane,width,height);
    return(error);
}

BOOL HrdCpy(scr,left,top,width,height,size)
    struct Screen *scr;
    UWORD left,top,width,height;
    USHORT size;
{/* Screen-RastPort ausdrucken */
    union PrIO{
        struct IOStdReq ios;
        struct IODRPReq iodrp;
        struct IOPrtCmdReq iopc;
    }*request,*CreateExtIO();
    struct MsgPort *MPort;
    BOOL OK=1;

    scr=scr?scr:ACTIVE_SCREEN;
    if(!(MPort=CreatePort("TOOL_Port",0))) return(1);
    if(request=(union PrIO *)CreateExtIO(MPort,sizeof(union PrIO))){
        if(!(OpenDevice("printer.device",0,request,0))){
            request->iodrp.io_Command=PRD_DUMPRPORT;
            request->iodrp.io_RastPort=&scr->RastPort;
            request->iodrp.io_ColorMap=scr->ViewPort.ColorMap;
            request->iodrp.io_Modes=scr->ViewPort.Modes;
            request->iodrp.io_SrcX=left;
            request->iodrp.io_SrcY=top;
            request->iodrp.io_SrcWidth=width;
            request->iodrp.io_SrcHeight=height;
            request->iodrp.io_DestCols=(LONG)(size*width);
            request->iodrp.io_DestRows=(LONG)(size*height);
            request->iodrp.io_Special=SPECIAL_MILCOLS|
                                      SPECIAL_MILROWS|
                                      SPECIAL_ASPECT;
            DoIO(request);
            CloseDevice(request);
        }
        else OK=0;
        DeleteExtIO(request,sizeof(union PrIO));
    }
    else OK=0;
    DeletePort(MPort);
    return(OK);
}


/*
\\          DOS-Tools
*/


LONG Exists(name)
    STRPTR name;
{/* Existenz eines Eintrags feststellen */
    LONG bytes=0;
    struct FileInfoBlock *eintrag;
    struct FileLock *lock;

    if(lock=(struct FileLock *)Lock(&name[0],ACCESS_READ)){
        if(eintrag=(struct FileInfoBlock *)
            AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR)){
            if(Examine(lock,eintrag)) bytes=(TYPE>0) ? -1 : SIZE;
            FreeMem(eintrag,sizeof(struct FileInfoBlock));
        }
        UnLock(lock);
    }
    return(bytes);
}

UBYTE *GetFile(file,fsize)
    STRPTR file;
    LONG *fsize;
{/* File in Speicher laden */
    struct FileHandle *FH;
    UBYTE *buffer;
    LONG size;

    if((size=Exists(file))<=0) return(0);
    if(!(buffer=(UBYTE *)AllocMem(size,MEMF_CLEAR))) return(0);
    else if(!(FH=(struct FileHandle *)Open(file,MODE_OLDFILE))){
        FreeMem(buffer,size);
        return(0);
    }
    else if(Read(FH,buffer,size)!=size){
        FreeMem(buffer,size);
        Close(FH);
        return(0);
    }
    else{
        Close(FH);
        *fsize=size;
        return(buffer);
    }
}

BOOL PutFile(file,buffer,size)
    STRPTR file;
    UBYTE *buffer;
    LONG size;
{/* Buffer speichern */
    struct FileHandle *FH;
    BOOL rw=0;

    if(!(FH=(struct FileHandle *)Open(file,MODE_NEWFILE))) return(1);
    if(Write(FH,buffer,size)!=size)    rw=1;
    Close(FH);
    return(rw);
}

LONG GetLW()
{/* Nummer des aktuellen Laufwerks ermitteln */
    struct FileInfoBlock *eintrag;
    struct InfoData *infos;
    struct FileLock *lock;
    LONG disk=-1;

    if(infos=(struct InfoData *)AllocMem(sizeof(struct InfoData),MEMF_CLEAR)){
        if(lock=(struct FileLock *)Lock(NULL,ACCESS_READ)){
            if(eintrag=(struct FileInfoBlock *)
                AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR)){
                if(Examine(lock,eintrag)){
                    Info(lock,infos);
                    disk=infos->id_UnitNumber+1;
                }
                FreeMem(eintrag,sizeof(struct FileInfoBlock));
            }
            UnLock(lock);
        }
        FreeMem(infos,sizeof(struct InfoData));
    }
    return(disk);
}

SHORT ReadDir(dirname,anz,flags,namen,size)
    STRPTR dirname;
    USHORT anz;
    SHORT flags;
    UBYTE namen[][FLEN];
    LONG size[];
{/* Verzeichnis lesen */
    SHORT i=-1;
    struct FileInfoBlock *eintrag;
    struct FileLock *lock;

    if(lock=(struct FileLock *)Lock(&dirname[0],ACCESS_READ)){
        if(eintrag=(struct FileInfoBlock *)
            AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR)){
            if(Examine(lock,eintrag)){
                if(TYPE>0){
                    for(i=anz;i>0;i--) namen[i-1][0]='\0';
                    ExNext(lock,eintrag);
                    while((IoErr()!=ERROR_NO_MORE_ENTRIES)&&(i<anz)){
                        if(TYPE>0){
                            if(flags&DIRS){
                                strcpy(&namen[i][0],&NAME[0]);
                                if(size) size[i]=-1;
                                i++;
                            }
                        }
                        else if(flags&FILES){
                            strcpy(&namen[i][0],&NAME[0]);
                            if(size) size[i]=SIZE;
                            i++;
                        }
                        ExNext(lock,eintrag);
                    }
                }
            }
            FreeMem(eintrag,sizeof(struct FileInfoBlock));
        }
        UnLock(lock);
    }
    return(i);
}
