/*
(c) Copyright 1988-1994 Microsoft Corporation.

Microsoft Bars&Pipes Professional Source Code License

This License governs use of the accompanying Software.  
Microsoft hopes you find this Software useful.

You are licensed to do anything you want with the Software. 

In return, we simply require that you agree:

1.      Not to remove any copyright notices from the Software.

2.      That the Software comes "as is", with no warranties.  
        None whatsoever. This means no implied warranty of merchantability or 
        fitness for a particular purpose or any warranty of non-infringement.  
        Also, you must pass this disclaimer on whenever you distribute the Software.

3.      That we will not be liable for any of those types of damages known as indirect, 
        special, consequential, or incidental related to the Software or this License, 
        to the maximum extent the law permits. Also, you must pass this limitation of 
        liability on whenever you distribute the Software.

4.      That if you sue anyone over patents that you think may apply to the Software 
        for that person’s use of the Software, your license to the Software ends automatically.

5.      That the patent rights Microsoft is licensing only apply to the Software, 
        not to any derivatives you make.

6.      That your rights under the License end automatically if you breach this in any way.
*/

#include "/CompilerSpecific.h"
#include <intuition/intuition.h>
#include <exec/memory.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/exec.h>
#include <graphics/gfxmacros.h>
#include <string.h>
#include "tools.h"
#include "all.h"

extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;

struct Cow {
    struct Cow *next;
    char *item;
    short itemsize;
};

static struct Cow *cowlist = 0;

char *tools_alloc(size,flags)

long size, flags;

{
    register struct Cow *cow = (struct Cow *) 
        AllocMem(sizeof(struct Cow),MEMF_PUBLIC|MEMF_CLEAR);
    register char *item = (char *) AllocMem(size+1,flags);
    if (item && cow) {
        Forbid();
        cow->item = item;
        cow->itemsize = size;
        cow->next = cowlist;
        cowlist = cow;
        Permit();
    }
    else {
        if (cow) FreeMem((APTR)cow,sizeof(*cow));
        if (item) FreeMem(item,size+1);
        item = 0;
    }
    return(item);
}

void tools_free(item)

register char *item;

{
    register struct Cow *cow = cowlist;
    Forbid();
    for (;cow;cow = cow->next) {
        if (item == cow->item) {
            FreeMem(item,cow->itemsize+1);
            cowlist = (struct Cow *) 
                List_Remove((struct ListItem *)cowlist,(struct ListItem *)cow);
            FreeMem((APTR)cow,sizeof(*cow));
            break;
        }
    }
    Permit();
}

struct ListInfo *DupeListInfo(listinfo)

register struct ListInfo *listinfo;

{
    register struct ListInfo *copy;
    copy = (struct ListInfo *) tools_alloc(sizeof(*listinfo),MEMF_PUBLIC);
    if (copy) memcpy(copy,listinfo,sizeof(*listinfo));
    return(copy);
}

void DeleteListInfo(listinfo)

struct ListInfo *listinfo;

{
    tools_free((char *)listinfo);
}

void DeleteAll()

{
    register struct Cow *cow = cowlist;
    register struct Cow *next;
    for (;cow;) {
        next = cow->next;
        FreeMem(cow->item,cow->itemsize+1);
        FreeMem((APTR)cow,sizeof(*cow));
        cow = next;
    }
    cowlist = 0;
}    
    
long Itoa(i,s,r)

/*      This converts the integer i to ascii, radix r, putting it in s.
*       Returns the length, else 0 if error.
*/

register long i;
register char s[];
register long r;

{
    register long pol,rem,index,len;
    char buff[40];
    if (( r < 2 ) || ( r > 16 )) return(0);
    if (!i) {
        s[0] = '0';
        s[1] = 0;
        return(1);
    }
    pol = (i < 0);
    if (pol) i = 0 - i;
    for(index = 0;((index < 30) && i); index++) {
        rem = i % r;
        i = i / r;
        if (rem < 10) buff[index] = rem + '0';
        else buff[index] = rem + 'A' - 10;
    }
    if (pol && (r == 10)) buff[index++] = '-';
    for (len = index;index;index--) s[len - index] = buff[index-1];
    s[len] = 0;
    return(len);
}

long Atoi(s,r)

/*      Converts string s to integer, radix r.
*/

register char s[];
register long r;

{
    register long pol,result,index;
    if (s[0] == '-') pol = 1;
    else pol = 0;
    if (r < 2) return(0);
    for(index=result=0;(index < 17) && s[index];index++) {
        result = result * r;
        if ((s[index] >= '0') && (s[index] <= '9')) result += s[index] - '0';
        else if ((s[index]>='a') && (s[index]<='z')) result += s[index]-'a'+10;
        else if ((s[index]>='A') && (s[index]<='Z')) result += s[index]-'A'+10;
        else result = result / r;
    }
    if (pol) result = 0 - result;
    return(result);
}

void RefreshGadget(window,id)

register struct Window *window;
register long id;

{
    register struct Gadget *gadget;
    register struct RastPort *rp = window->RPort;
    gadget = GetGadget(window,id);
    if (gadget) {
        SetDrMd(rp,JAM2);
        SetAPen(rp,0);
        SetOPen(rp,0);
        RectFill(rp,gadget->LeftEdge,gadget->TopEdge,
            gadget->LeftEdge + gadget->Width-1,gadget->TopEdge + gadget->Height-1);
        RefreshGList(gadget,window,0,1);
    }
}

struct Gadget *GetGadget(window,id)

struct Window *window;
register unsigned short id;

{
    register struct Gadget *gadget = window->FirstGadget;
    for(;gadget;gadget = gadget->NextGadget) {
        if (!(gadget->GadgetType & SYSGADGET)) {
            if (gadget->GadgetID == id) break;
        }
    }
    return(gadget);
}

struct StringInfo *GetStringInfo(window,id)

struct Window *window;
register unsigned short id;

{
    register struct Gadget *gadget = GetGadget(window,id);
    register struct StringInfo *stringinfo = 0;
    if (gadget && ((gadget->GadgetType & 0xF) == STRGADGET))
        stringinfo = (struct StringInfo *) gadget->SpecialInfo;
    return(stringinfo);
}

void SetStringInfo(window,id,string)

struct Window *window;
register unsigned short id;
register char *string;

{
    register struct StringInfo *stringinfo;
    register unsigned short i, len, slen;
    struct Gadget *gadget;
    stringinfo = GetStringInfo(window,id);
    slen = 1;
    if (stringinfo) {
        gadget = GetGadget(window,id);
        gadget->Flags &= ~GADGDISABLED; 
        len = stringinfo->MaxChars;
        for (i=0;i<len;i++) {
            if (slen) {
                stringinfo->Buffer[i] = string[i];
                if (string[i] == 0) {
                    slen = 0;
//                  stringinfo->NumChars = i;
                }
            }
//          else stringinfo->Buffer[i] = 0;
        }
        stringinfo->BufferPos = 0;
        stringinfo->DispPos = 0;
        RefreshGadget(window,id);
    }
}

long GetStringInfoNumber(window,id,base)

struct Window *window;
unsigned short id,base;

{
    register struct StringInfo *stringinfo;
    register long result;
    stringinfo = GetStringInfo(window,id);
    if (stringinfo) result = Atoi(stringinfo->Buffer,base);
    else result = 0;
    return(result);
}

void SetStringInfoNumber(window,id,number,base)
    
struct Window *window;
register unsigned short id;
register long number;
long base;

{
    char copystring[40];
    register struct StringInfo *stringinfo;
    stringinfo = GetStringInfo(window,id);
    if (stringinfo) {
        Itoa(number,copystring,base);
        SetStringInfo(window,id,copystring);
        stringinfo->LongInt = number;
/*      RefreshGadget(window,id);*/
    }
}

struct PropInfo *GetPropInfo(window,id)

struct Window *window;
register unsigned short id;

{
    register struct Gadget *gadget = GetGadget(window,id);
    register struct PropInfo *propinfo = 0;
    if (gadget && ((gadget->GadgetType & 0xF) == PROPGADGET))
        propinfo = (struct PropInfo *) gadget->SpecialInfo;
    return(propinfo);
}

void SetPropInfo(window,id,hpos,vpos)

struct Window *window;
unsigned short id,hpos,vpos;

{
    register struct PropInfo *propinfo = GetPropInfo(window,id);
    register struct Gadget *gadget;
    if (propinfo) {
        gadget = GetGadget(window,id);
        gadget->Flags &= ~GADGDISABLED; 
        propinfo->HorizPot = hpos;
        propinfo->VertPot = vpos;
        RefreshGadget(window,id);
    }
}


struct IntuiMessage *GetSelectIntuiMessage(window,type)

register struct Window *window;
register unsigned long type;

{
    register struct IntuiMessage *message;
    message = (struct IntuiMessage *) GetMsg(window->UserPort);
    if (message) {
        if (!(message->Class & type)) {
            ReplyMsg((struct Message *)message);
            message = 0;
        }
    }
    while (!message) {
        Wait(-1);
/*      WaitPort(window->UserPort);*/
        message = (struct IntuiMessage *) GetMsg(window->UserPort);
        if (message) {
            if (!(message->Class & type)) {
                ReplyMsg((struct Message *)message);
                message = 0;
            }
        }
    }
    return(message);
}

struct IntuiMessage *GetIntuiMessage(window)

struct Window *window;

{
    return(GetSelectIntuiMessage(window,-1));
}

void ClearIntuiMessages(window)

register struct Window *window;

{
    register struct IntuiMessage *message;
    while (message = (struct IntuiMessage *) GetMsg(window->UserPort))
        ReplyMsg((struct Message *)message);
}

struct Menu *GetMenu(menulist,menunum)

register struct Menu *menulist;
register long menunum;

{
    while (menunum && menulist) {
        menulist = menulist->NextMenu;
        menunum--;
    }
    return(menulist);
}

struct MenuItem *GetMenuItem(menu,menunum,itemnum,subitemnum)

register struct Menu *menu;
register long menunum,itemnum,subitemnum;

{
    register struct MenuItem *menuitem = 0;
    register struct MenuItem *subitem = 0;
    menu = GetMenu(menu,menunum);
    if (menu) {
        menuitem = menu->FirstItem;
        while (itemnum && menuitem) {
            menuitem = menuitem->NextItem;
            itemnum--;
        }
        if (menuitem && (subitemnum >= 0)) {
            subitem = menuitem->SubItem;
            while (subitemnum && subitem) {
                subitem = subitem->NextItem;
                subitemnum--;
            }
        }
    }
    if (subitem) return(subitem);
    else if (menuitem) return(menuitem);
    else return((struct MenuItem *)0);
}

void CheckMenuItem(menu,menunum,itemnum,subitemnum,on)

struct Menu *menu;
long menunum,itemnum,subitemnum,on;

{
    register struct MenuItem *item =
        GetMenuItem(menu,menunum,itemnum,subitemnum);
    if (item) {
        if (on) item->Flags |= CHECKED;
        else item->Flags &= ~CHECKED;
    }
}

void EnableMenuItem(menu,menunum,itemnum,subitemnum,on)

register struct Menu *menu;
long menunum,itemnum,subitemnum,on;

{
    register struct MenuItem *item = 
        GetMenuItem(menu,menunum,itemnum,subitemnum);
    if (item) {
        if (on) item->Flags |= ITEMENABLED;
        else item->Flags &= ~ITEMENABLED;
    }
}

void EnableMenu(menu,menunum,on)

register struct Menu *menu;
long menunum,on;

{
    menu = GetMenu(menu,menunum);
    if (menu) {
        if (on) menu->Flags |= MENUENABLED;
        else menu->Flags &= ~MENUENABLED;
    }
}
        
void EnableGadget(window,id,on)

struct Window *window;
short id, on;

{
    register struct Gadget *gadget = GetGadget(window,id);
    if (gadget) {
        if (on) gadget->Flags &= ~GADGDISABLED;
        else gadget->Flags |= GADGDISABLED;
        RefreshGadget(window,id);
    }
}

void SelectGadget(window,id,on)

struct Window *window;
short id, on;

{
    register struct Gadget *gadget = GetGadget(window,id);
    if (gadget) {
        if (on) gadget->Flags |= SELECTED;
        else gadget->Flags &= ~SELECTED;
        RefreshGadget(window,id);
    }
}

struct Gadget *tools_dupegadget(source)

register struct Gadget *source;

{
    register struct PropInfo *propinfo;
    register struct StringInfo *stringinfo;
    register struct Gadget *gadget = 0;
    register char *string;
    register char *temp;
    temp = (char *) AllocMem(2000,MEMF_PUBLIC);
    if (temp) {
        FreeMem(temp,2000);
        gadget = (struct Gadget *) tools_alloc(sizeof(*gadget),MEMF_PUBLIC);
        memcpy(gadget,source,sizeof(*gadget));
        if ((source->GadgetType & 0xF) == STRGADGET) {
            stringinfo = (struct StringInfo *) 
                tools_alloc(sizeof(struct StringInfo),MEMF_PUBLIC);
            memcpy(stringinfo,source->SpecialInfo,sizeof(*stringinfo));
            string = (char *) tools_alloc(stringinfo->MaxChars,MEMF_PUBLIC);
            memcpy(string,stringinfo->Buffer,stringinfo->MaxChars);
            gadget->SpecialInfo = (APTR) stringinfo;
            stringinfo->Buffer = string;
        }
        else if ((source->GadgetType & 0xF) == PROPGADGET) {
            propinfo = (struct PropInfo *) 
                tools_alloc(sizeof(struct PropInfo),MEMF_PUBLIC | MEMF_CLEAR);
            if (source->SpecialInfo)
                memcpy(propinfo,source->SpecialInfo,sizeof(*propinfo));
            gadget->SpecialInfo = (APTR) propinfo;
        }
        gadget->NextGadget = 0;
    }
    return(gadget);
}

static struct Gadget *tools_DupeGadgetList(source)

register struct Gadget *source;

{
    register struct Gadget *top = 0;
    register struct Gadget *gadget;
    for(;source;source = source->NextGadget) {
        gadget = tools_dupegadget(source);
        if (gadget) {
            top = (struct Gadget *) List_Insert((struct ListItem *)top,(struct ListItem *)gadget,-1);
        }
    }
    return(top);
}

struct NewWindow *DupeNewWindow(nw)

register struct NewWindow *nw;

{
    register struct NewWindow *new = (struct NewWindow *)
        tools_alloc(sizeof(*nw),MEMF_PUBLIC);
    if (new) {
        memcpy(new,nw,sizeof(*nw));
        new->FirstGadget = tools_DupeGadgetList(nw->FirstGadget);
    }
    return(new);
}

static void tools_DeleteGadgetList(list)

register struct Gadget *list;

{
    register struct StringInfo *stringinfo;
    register struct Gadget *next;
    for(;list;list = next) {
        next = list->NextGadget;
        if ((list->GadgetType & 0xF) == STRGADGET) {
            stringinfo = (struct StringInfo *) list->SpecialInfo;
            tools_free((char *)stringinfo->Buffer);
            tools_free((char *)stringinfo);
        }
        else if ((list->GadgetType & 0xF) == PROPGADGET) {
            tools_free((char *)list->SpecialInfo);
        }
        tools_free((char *)list);
    }
}

void DeleteNewWindow(nw)

register struct NewWindow *nw;

{
    tools_DeleteGadgetList(nw->FirstGadget);
    tools_free((char *)nw);
}
    
static struct MenuItem *tools_dupemenuitem(source)

register struct MenuItem *source;

{
    register struct MenuItem *item, *top, *last;
    register char *temp = AllocMem(1000,MEMF_PUBLIC);
    last = NULL;
    if (temp) {
        FreeMem(temp,1000);
        for (top = 0;source;source = source->NextItem) {
            item = (struct MenuItem *) tools_alloc(sizeof(*source),MEMF_PUBLIC);
            memcpy(item,source,sizeof(*source));
            item->NextItem = 0;
            if (item->SubItem) {
                item->SubItem = tools_dupemenuitem(item->SubItem);
            }
            if (top) last->NextItem = item;
            else top = item;
            last = item;
        }
    }
    return(top);
}

struct Menu *DupeMenu(source)

register struct Menu *source;

{
    register struct Menu *menu, *top, *last;
    register char *temp = AllocMem(1000,MEMF_PUBLIC);
    last = NULL;
    if (temp) {
        FreeMem(temp,1000);
        for (top = 0;source;source = source->NextMenu) {
            menu = (struct Menu *) tools_alloc(sizeof(*source),MEMF_PUBLIC);
            memcpy(menu,source,sizeof(*source));
            menu->NextMenu = 0;
            if (menu->FirstItem) {
                menu->FirstItem = tools_dupemenuitem(menu->FirstItem);
            }
            if (top) last->NextMenu = menu;
            else top = menu;
            last = menu;
        }
    }
    return(top);
}

static void tools_deletemenuitem(list)

register struct MenuItem *list;

{
    register struct MenuItem *next;
    for (;list;list = next) {
        next = list->NextItem;
        if (list->SubItem) tools_deletemenuitem(list->SubItem);
        tools_free((char *)list);
    }
}

void DeleteMenu(list)

register struct Menu *list;

{
    register struct Menu *next;
    for (;list;list = next) {
        next = list->NextMenu;
        if (list->FirstItem) tools_deletemenuitem(list->FirstItem);
        tools_free((char *)list);
    }
}
    
void SendCloseWindow(window)

register struct Window *window;

{
    struct IntuiMessage message;
    register struct MsgPort *replyport;
    if (window) {
        replyport = (struct MsgPort *) CreatePort(0,0);
        if (replyport) {
            message.ExecMessage.mn_ReplyPort = replyport;
            message.ExecMessage.mn_Node.ln_Type = NT_MESSAGE;
            message.Class = CLOSEWINDOW;
            PutMsg(window->UserPort,(struct Message *)&message);
            WaitPort(replyport);
            GetMsg(replyport);
            DeletePort(replyport);
        }
    }
}

