#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)
				{
				    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(data,&many->expansion[0]);
								SetAttrs(data->gdg[i],GAU_VolType,data->voltype,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:
									if(RetinaBase)
									    cur=Retina_AvailMem(MEMF_LARGEST);
									else
									    cur=GAU_err_notavail;
									break;
								case    typ_retina:
									if(RetinaBase)
									    cur=Retina_AvailMem(0L);
									else
									    cur=GAU_err_notavail;
									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);
							    goto no_Reply;
							}
							break;
						case    IDCMP_CLOSEWINDOW:
							running=FALSE;
							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) goto no_Reply;
							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);
									}
								    }
								    break;
							    case    'F':
							    case    'f':
								    {
									ULONG   my_mem;
									Forbid();
									my_mem= AllocVec(2000000000L,MEMF_PUBLIC);
									if(my_mem)FreeVec(my_mem);
									Permit();
								    }
								    break;
							    case    'Q':
							    case    'q':
								    running=FALSE;
								    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);
									goto no_Reply;
								    }
								    break;
							}
							break;
						case    IDCMP_MOUSEBUTTONS:
							if((m->Code&129)==1)
							{
							    setBase(data);
							}
							break;
						default :
							break;
					    }
					    ReplyMsg( m );
no_Reply:
					}
				    }
				    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)
							{
							    FreeVec(set);
							    many=data->list;
							    do
							    {
								next=many->next;
								FreeVec(many);
							    }
							    while(many=next);
							    set                 = test_msg->set;
							    data->list          = test_msg->list;
							    data->num_of_gaug   = getNum(data->list);
							}
							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;
									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);
}

