#include <intuition/classusr.h>
#include <intuition/gadgetclass.h>
#include <intuition/cghooks.h>
#include <intuition/icclass.h>
#include <intuition/classes.h>
#include <utility/tagitem.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <dos/notify.h>
#include <intuition/intuition.h>
#include <libraries/SysInfo.h>
#include <utility/tagitem.h>
#include <clib/macros.h>
#include <libraries/commodities.h>
#include <libraries/ScreenNotify.h>
#include "gaugeclass.h"
#include "tinymeter.h"

extern struct Library *RetinaBase;

extern ULONG idle;

#define test_test       0
#define test_getwin     1

#define do_clock        1
#define do_mem          2
#define do_vol          3

struct TestMessage
{
    struct  Message ts_Message;

    ULONG   MethodID;

    struct  tm_sys_set  *set;
    struct  tm_gau_set  *list;

    ULONG   posx,
            posy,
            sizx;
};

init_time_request(struct timerequest *my_time_request_clock, ULONG my_time_mask_clock)
{
    ULONG interval;
    my_time_request_clock -> tr_node.io_Command     = TR_GETSYSTIME;
    DoIO(my_time_request_clock);
    interval=my_time_request_clock -> tr_time.tv_secs;
    my_time_request_clock -> tr_node.io_Command     = TR_ADDREQUEST;
    my_time_request_clock -> tr_time.tv_secs        = interval+1;
    my_time_request_clock -> tr_time.tv_micro       = 0;
    SetSignal(0,my_time_mask_clock);
    SendIO(my_time_request_clock);
}

ULONG snapSub(struct tm_sys_set *set, struct tm_data *data)
{
    struct Gadget       *g;
    int                 i;

    g=data->win->FirstGadget;
    data->win=(struct Window *)snapBackground(set,data);
    RemoveGList(data->win,data->win->FirstGadget,-1);
    AddGList(data->win,g,0,-1,NULL);
    drawBackground(set,data);
    for(i=0;i<data->num_of_gaug;i++)
    {
        if(data->gdg[i]!=0)
        {
            SetAttrs(data->gdg[i],GA_Width, data->gauge_x_size, NULL);
            RefreshGList(data->gdg[i],data->win,NULL,1);
        }
    }
    return(1L << data->win->UserPort->mp_SigBit);
}

setBase(struct tm_data *data)
{
    struct tm_gau_set   *many;
    int                 i;
    ULONG               cur;
    for(i=0,many=data->list;i<data->num_of_gaug;i++,many=many->next)
    {
        if(data->gdg[i]!=0)
        {
            GetAttr(GAU_Current,data->gdg[i],&cur);
            SetAttrs(data->gdg[i],GAU_Current,cur,GAU_Base,cur,TAG_DONE);
            RefreshGList(data->gdg[i],data->win,NULL,1);
        }
    }
}

struct tm_sys_set *handler(struct tm_sys_set *set, struct tm_data *data, struct MsgPort *broker_mp, CxObj *broker, ULONG cxsigflag, Class *gclass)
{
    BOOL                        running = TRUE;

    ULONG                       interval,
                                mem_val=0,
                                vol_val=0,
                                sigs,
                                window_mask,
                                my_time_mask_clock,
                                my_test_port_mask,
                                my_noti_port_mask=0L,
                                my_handler;

    struct MsgPort             *my_time_port_clock,
                               *my_test_port,
                               *my_noti_port;

    struct timerequest         *my_time_request_clock;

    struct NotifyRequest       *notifyrequest;
    LONG                        not_sig;

    struct IntuiMessage        *m;
    struct Gadget              *g;
    int                         i;
    ULONG                       cur;
    ULONG                       bas;
    struct TestMessage         *test_msg;
    struct tm_gau_set          *many,*next;
    UBYTE                      *my_file;
    BOOL                        first_run=TRUE;
    UWORD                       do_what;

    if(data->scrnot)
    {
        my_noti_port        = (struct MsgPort *)CreateMsgPort();
        my_handler          = ((!data->on_public)|(!strcmp(&set->pub_name[0],"Workbench"))) ? (ULONG)AddWorkbenchClient(my_noti_port,0) : (ULONG)AddCloseScreenClient(data->scr,my_noti_port,0);
        my_noti_port_mask   = 1L << my_noti_port->mp_SigBit;
    }

    window_mask  = 1L << data->win->UserPort->mp_SigBit;

    if(my_test_port=(struct MsgPort *)CreatePort("TinyMeter",0))
    {
        my_test_port_mask = 1L << (my_test_port->mp_SigBit);
        if(my_time_port_clock=(struct MsgPort *)CreateMsgPort())
        {
            my_time_mask_clock    = 1L << (my_time_port_clock->mp_SigBit);
            if(my_time_request_clock = (struct timerequest *)CreateIORequest(my_time_port_clock,sizeof(struct timerequest)))
            {
                if(!OpenDevice("timer.device",UNIT_WAITUNTIL,my_time_request_clock,NULL))
                {
                    if(notifyrequest = (struct NotifyRequest *)AllocVec(sizeof(struct NotifyRequest), MEMF_CLEAR))
                    {
                        if ((not_sig = AllocSignal(-1L)) != -1)
                        {
                            notifyrequest->nr_Name = "ENV:sys/WBPattern.prefs";
                            notifyrequest->nr_Flags = NRF_SEND_SIGNAL;
                            notifyrequest->nr_stuff.nr_Signal.nr_Task = (struct Task *) FindTask(NULL);
                            notifyrequest->nr_stuff.nr_Signal.nr_SignalNum = not_sig;

                            if ((StartNotify(notifyrequest)) == DOSTRUE)
                            {
                                init_time_request(my_time_request_clock,my_time_mask_clock);

                                while(running)
                                {
                                    if (running) sigs = Wait( my_noti_port_mask | my_test_port_mask | window_mask | my_time_mask_clock | (1L << not_sig) | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | cxsigflag );

                                    if (sigs & my_time_mask_clock)
                                    {
                                        if(data->win)
                                        {
                                            do_what=do_clock;
                                            mem_val++;
                                            if(mem_val>=set->mem_refresh)
                                            {
                                                mem_val=0;
                                                do_what=do_mem;
                                            }
                                            vol_val++;
                                            if(vol_val>=set->vol_refresh)
                                            {
                                                vol_val=0;
                                                do_what=do_vol;
                                            }

                                            for(i=0,many=data->list;i<data->num_of_gaug;i++,many=many->next)
                                            {
                                                if(data->gdg[i]!=0)
                                                switch (do_what)
                                                {
                                                    case    do_vol:
                                                            if(many->type==typ_volume)
                                                            {
                                                                getVolsize(set,data,&many->expansion[0]);
                                                                SetAttrs(data->gdg[i],GAU_Max,data->volmax,GAU_Current,data->volcur,TAG_DONE);
                                                                BeginRefresh(data->win);
                                                                EndRefresh(data->win,TRUE);
                                                                RefreshGList(data->gdg[i], data->win,NULL,1);
                                                            }
                                                    case    do_mem:
                                                            switch (many->type)
                                                            {
                                                                case    typ_all:
                                                                        cur=AvailMem(0L);
                                                                        break;
                                                                case    typ_chip:
                                                                        cur=AvailMem(MEMF_CHIP);
                                                                        break;
                                                                case    typ_fast:
                                                                        cur=AvailMem(MEMF_FAST);
                                                                        break;
                                                                case    typ_idle:
                                                                        GetAttr(GAU_Current,data->gdg[i],&bas);
                                                                        switch (data->executive)
                                                                        {
                                                                            case    idle_none:
                                                                                    cur=0L;
                                                                                    break;
                                                                            case    idle_executive:
                                                                                    GetCpuUsage(data->si,&data->cpu);
                                                                                    cur=(data->cpu.used_cputime_lastsec_hz-data->cpu.used_cputime_lastsec)<<8;
                                                                                    break;
                                                                            case    idle_own:
                                                                                    cur=idle;
                                                                                    break;
                                                                        }
                                                                        if(bas<cur)SetAttrs(data->gdg[i],GAU_Base,cur,TAG_DONE);
                                                                        break;
                                                                case    typ_largest_total:
                                                                        cur=AvailMem(MEMF_LARGEST);
                                                                        break;
                                                                case    typ_largest_chip:
                                                                        cur=AvailMem(MEMF_LARGEST|MEMF_CHIP);
                                                                        break;
                                                                case    typ_largest_fast:
                                                                        cur=AvailMem(MEMF_LARGEST|MEMF_FAST);
                                                                        break;
                                                                case    typ_largest_retina:
                                                                        cur=Retina_AvailMem(MEMF_LARGEST);
                                                                        break;
                                                                case    typ_retina:
                                                                        if(RetinaBase)
                                                                            cur=Retina_AvailMem(0L);
                                                                        else
                                                                            cur=1024L;
                                                                        break;
                                                                default:
                                                                        goto none_4;
                                                                        break;
                                                            }
                                                            if(do_what!=do_vol)
                                                            {
                                                                SetAttrs(data->gdg[i],GAU_Current,cur,TAG_DONE);
                                                                BeginRefresh(data->win);
                                                                EndRefresh(data->win,TRUE);
                                                                RefreshGList(data->gdg[i],data->win,NULL,1);
                                                            }
                                                            none_4:
                                                    case    do_clock:
                                                            if(many->type==typ_clock_)
                                                            {
                                                                SetAttrs(data->gdg[i],GAU_Current,cur,TAG_DONE);
                                                                BeginRefresh(data->win);
                                                                EndRefresh(data->win,TRUE);
                                                                RefreshGList(data->gdg[i],data->win,NULL,1);
                                                            }
                                                            break;
                                                }
                                            }
                                            if(first_run){setBase(data);first_run=FALSE;}
                                        }
                                        if(set->win_backfront==win_front)
                                        {
                                            if(data->win->WLayer!=data->scr->LayerInfo.top_layer)
                                                WindowToFront(data->win);
                                        }
                                        init_time_request(my_time_request_clock,my_time_mask_clock);
                                    }

                                    if (sigs & window_mask )
                                    {
                                        while(m=(struct IntuiMessage *)GetMsg( data->win->UserPort ))
                                        {
                                            switch ( m->Class )
                                            {
                                                case    IDCMP_CHANGEWINDOW:
                                                        if(set->bg_type==bg_snap)
                                                        {
                                                            ReplyMsg( m ); while((m=(struct IntuiMessage *)GetMsg( data->win->UserPort )))ReplyMsg( m );
                                                            window_mask=snapSub(set,data);
                                                        }
                                                        else ReplyMsg( m );
                                                        break;
                                                case    IDCMP_CLOSEWINDOW:
                                                        running=FALSE;
                                                        ReplyMsg( m );
                                                        break;
                                                case    IDCMP_NEWSIZE:
                                                        {
                                                            new_window_size(set,data);
                                                            set->x_siz=data->win->Width;
                                                            data->gauge_x_size=(set->x_siz-(set->win_border_x<<1)-((set->colums-1)*set->win_space_x))/set->colums;
                                                            switch (set->bg_type)
                                                            {
                                                                case    bg_file:
                                                                        fileBackground(set,data);
                                                                        break;
                                                                case    bg_snap:
                                                                        ReplyMsg( m ); while((m=(struct IntuiMessage *)GetMsg( data->win->UserPort )))ReplyMsg( m );
                                                                        g=data->win->FirstGadget;
                                                                        data->win=(struct Window *)snapBackground(set,data);
                                                                        RemoveGList(data->win,data->win->FirstGadget,-1);
                                                                        AddGList(data->win,g,0,-1,NULL);
                                                                        window_mask  = 1L << data->win->UserPort->mp_SigBit;
                                                                        break;
                                                                default:
                                                                        break;
                                                            }
                                                            drawBackground(set,data);
                                                            for(i=0,many=data->list;i<data->num_of_gaug;i++,many=many->next)
                                                            {
                                                                if(data->gdg[i]!=0)
                                                                {
                                                                    SetAttrs(data->gdg[i],
                                                                             GA_Left,        set->win_border_x+((i)%set->colums)*data->gauge_x_size+((i)%set->colums)*set->win_space_x,
                                                                             GA_Width,       data->gauge_x_size,
                                                                             TAG_DONE);
                                                                    RefreshGList(data->gdg[i], data->win,NULL,1);
                                                                }                                                                
                                                            }
                                                        }
                                                        if(set->bg_type!=bg_snap)ReplyMsg( m );
                                                        break;
                                                case    IDCMP_VANILLAKEY:
                                                        switch(m->Code)
                                                        {
                                                            case    'S':
                                                            case    's':
                                                                    {
                                                                        set->x_pos=data->win->LeftEdge;
                                                                        set->y_pos=data->win->TopEdge;
                                                                        set->x_siz=data->win->Width;
                                                                        if(my_file=(UBYTE *)Open("ENV:TinyMeter",MODE_NEWFILE))
                                                                        {
                                                                            Write(my_file,set,(ULONG) sizeof(struct tm_sys_set));
                                                                            many=data->list;
                                                                            for(i=0;i<data->num_of_gaug;i++)
                                                                            {
                                                                                Write(my_file,many,(ULONG) sizeof(struct tm_gau_set));
                                                                                many=many->next;
                                                                            }
                                                                            Close(my_file);
                                                                        }
                                                                        if(my_file=(UBYTE *)Open("ENVARC:TinyMeter",MODE_NEWFILE))
                                                                        {
                                                                            Write(my_file,set,(ULONG) sizeof(struct tm_sys_set));
                                                                            many=data->list;
                                                                            for(i=0;i<data->num_of_gaug;i++)
                                                                            {
                                                                                Write(my_file,many,(ULONG) sizeof(struct tm_gau_set));
                                                                                many=many->next;
                                                                            }
                                                                            Close(my_file);
                                                                        }
                                                                    }
                                                                    ReplyMsg( m );
                                                                    break;
                                                            case    'F':
                                                            case    'f':
                                                                    {
                                                                        ULONG   my_mem;
                                                                        Forbid();
                                                                        my_mem= AllocVec(2000000000L,MEMF_PUBLIC);
                                                                        if(my_mem)FreeVec(my_mem);
                                                                        Permit();
                                                                    }
                                                                    ReplyMsg( m );
                                                                    break;
                                                            case    'Q':
                                                            case    'q':
                                                                    running=FALSE;
                                                                    ReplyMsg( m );
                                                                    break;
                                                            case    'b':
                                                            case    'B':
                                                                    if(set->bg_type==bg_snap)
                                                                    {
                                                                        ReplyMsg( m ); while((m=(struct IntuiMessage *)GetMsg( data->win->UserPort )))ReplyMsg( m );
                                                                        window_mask=snapSub(set,data);
                                                                    }
                                                                    else ReplyMsg( m );
                                                                    break;
                                                        }
                                                        break;
                                                case    IDCMP_MOUSEBUTTONS:
                                                        if((m->Code&129)==1)
                                                        {
                                                            setBase(data);
                                                        }
                                                        ReplyMsg( m );
                                                        break;
                                                default :
                                                        ReplyMsg( m );
                                                        break;
                                            }
                                        }
                                    }

                                    if (sigs & (1L << not_sig))
                                    {
                                        Delay(100L);
                                        switch (set->bg_type)
                                        {
                                            case    bg_snap:
                                                    window_mask=snapSub(set,data);
                                                    break;
                                            default:
                                                    break;
                                        }
                                    }

                                    if (sigs & cxsigflag)
                                    {
                                        CxMsg *msg;
                                        ULONG sigrcvd, msgid, msgtype;

                                        while(msg = (CxMsg *)GetMsg(broker_mp))
                                        {
                                            msgid = CxMsgID(msg);
                                            msgtype = CxMsgType(msg);
                                            if(msgtype==CXM_COMMAND)
                                            switch(msgid)
                                            {
                                                case    CXCMD_DISABLE:
                                                        {
                                                            BOOL pause=TRUE;
                                                            ActivateCxObj(broker, 0L);
                                                            while(pause)
                                                            {
                                                                Wait(cxsigflag);
                                                                while(msg = (CxMsg *)GetMsg(broker_mp))
                                                                {
                                                                    msgid = CxMsgID(msg);
                                                                    msgtype = CxMsgType(msg);
                                                                    ReplyMsg((struct Message *)msg);
                                                                    if(msgtype==CXM_COMMAND) if(msgid==CXCMD_ENABLE) pause=FALSE;
                                                                }
                                                            }
                                                            ActivateCxObj(broker, 1L);
                                                        }
                                                        break;
                                                case    CXCMD_ENABLE:
                                                        ActivateCxObj(broker, 1L);
                                                        break;
                                                case    CXCMD_KILL:
                                                        running=FALSE;
                                                        break;
                                            }
                                            ReplyMsg((struct Message *)msg);
                                        }
                                    }

                                    if ((sigs & my_test_port_mask))
                                    {
                                        while(test_msg=(struct TestMessage *)GetMsg(my_test_port))
                                        {
                                            switch (test_msg->MethodID)
                                            {
                                                case    test_test:
                                                        closeWindow(set,data);
                                                        removeGadgets(set,data);
                                                        first_run=TRUE;
                                                        if(test_msg->set && test_msg->list) /* To be sure that no trash arrives here */
                                                        {
                                                            /* Free old settings */
                                                            FreeVec(set);
                                                            many=data->list;
                                                            do
                                                            {
                                                                next=many->next;
                                                                FreeVec(many);
                                                            }
                                                            while(many=next);
                                                            /* get new settings */
                                                            set                 = test_msg->set;
                                                            data->list          = test_msg->list;
                                                            data->num_of_gaug   = getNum(data->list);
                                                        }
                                                        /* initialize new settings */
                                                        if(openWindow(set,data))
                                                        {
                                                            drawBackground(set,data);
                                                            allocGadgets(set,data,gclass);
                                                            window_mask  = 1L << data->win->UserPort->mp_SigBit;
                                                        }
                                                        else running=FALSE;
                                                        setBase(data);
                                                        break;
                                                case    test_getwin:
                                                        test_msg->posx=data->win->LeftEdge;
                                                        test_msg->posy=data->win->TopEdge;
                                                        test_msg->sizx=data->win->Width;
                                                        break;
                                            }
                                            ReplyMsg(test_msg);
                                        }
                                    }

                                    if(data->scrnot)
                                    {
                                        if (sigs & my_noti_port_mask)
                                        {
                                            struct ScreenNotifyMessage  *snm;
                                            while(snm = (struct ScreenNotifyMessage *) GetMsg(my_noti_port))
                                            {
                                                switch(snm->snm_Type)
                                                {
                                                    case    SCREENNOTIFY_TYPE_CLOSESCREEN:
                                                            ReplyMsg((struct Message *) snm);
                                                            running=FALSE;
                                                            break;
                                                    case    SCREENNOTIFY_TYPE_WORKBENCH:
                                                            switch ((ULONG)snm->snm_Value)
                                                            {
                                                                case    FALSE:
                                                                        closeWindow(set,data);
                                                                        removeGadgets(set,data);
                                                                        ReplyMsg((struct Message *) snm);
                                                                        Wait(my_noti_port_mask);
                                                                        while(snm = (struct ScreenNotifyMessage *) GetMsg(my_noti_port))
                                                                        {
                                                                            if(snm->snm_Type==SCREENNOTIFY_TYPE_WORKBENCH)
                                                                            {
                                                                                if((ULONG)snm->snm_Value==TRUE)
                                                                                {
                                                                                    ReplyMsg((struct Message *) snm);
                                                                                    Delay(50L);
                                                                                    if(openWindow(set,data))
                                                                                    {
                                                                                        drawBackground(set,data);
                                                                                        allocGadgets(set,data,gclass);
                                                                                        window_mask  = 1L << data->win->UserPort->mp_SigBit;
                                                                                    }
                                                                                    else running=FALSE;
                                                                                    setBase(data);
                                                                                }
                                                                                else running=FALSE;
                                                                            }
                                                                            else running=FALSE;
                                                                        }
                                                                        first_run=TRUE;
                                                                        window_mask = 0L;
                                                                        break;
                                                                default:
                                                                        ReplyMsg((struct Message *) snm);
                                                                        break;
                                                            }
                                                            break;
                                                    default:
                                                            ReplyMsg((struct Message *) snm);
                                                            break;
                                                }
                                            }
                                        }
                                        Delay(10L);
                                    }

                                    if (sigs & (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D)) running=FALSE;
                                }
                            }
                            else show("StartNotify failed!");
                            FreeSignal(not_sig);
                        }
                        else show("Could not allocate signal!");
                        FreeVec(notifyrequest);
                    }
                    else show("Not enough memory!");
                    if(!CheckIO(my_time_request_clock))
                        AbortIO(my_time_request_clock);
                    WaitIO(my_time_request_clock);
                    CloseDevice(my_time_request_clock);
                }
                else show("timer.device usage failed!");
                DeleteIORequest(my_time_request_clock);
            }
            else show("CreateIORequest failed!");
            DeleteMsgPort(my_time_port_clock);
        }
        else show("CreateMsgPort failed!");
        DeletePort(my_test_port);
    }
    else show("CreatePort failed.!");

    if(data->scrnot)
    {
        if((!data->on_public)|(!strcmp(&set->pub_name[0],"Workbench")))
            while(!RemWorkbenchClient(my_handler)) Delay(10);
        else
            while(!RemCloseScreenClient(my_handler)) Delay(10);
        DeleteMsgPort(my_noti_port);
    }

    return(set);
}

