#include "xsb.h"
#include "startup.h"

extern void popup(void);
extern void loadprefs(void);

/* hotkey */
char hotkey[40]={"alt shift del"};
char popkey[40]={"alt shift help"};
char xsbname[40]={"xsbstandard.library"};
long tick; /* 5 sec tick count */
long prio;

extern long blankmouse,mousetimeout,screentimeout,randomblanker;

#define CreatePort alsosoeinmist
#include <clib/alib_protos.h>

struct Library *IconBase,*CxBase,*XSBBase,*GfxBase;
struct IntuitionBase *IntuitionBase;
struct GadToolsBase *GadToolsBase;
struct MsgPort *mp;
CxObj *filter1,*filter2,*comms,*broker,*cxsig1,*cxsig2;
struct TextAttr top80={"topaz.font",8,0,0};

char version[]={"$VER: XSBCX V1.0 (" __DATE__ " " __TIME__ ")"};

struct InputXpression fix1={IX_VERSION,IECLASS_RAWKEY,0,0,0,0,0};
struct InputXpression fix2={IX_VERSION,IECLASS_RAWMOUSE,0,0,0,0,0};

struct timerequest treq;
struct MsgPort *timerport;
int timeropen;

void cxcleanup(char *error)
{
 if(broker) DeleteCxObjAll(broker);
 if(IconBase) CloseLibrary(IconBase);
 if(CxBase) CloseLibrary(CxBase);
 if(IntuitionBase) CloseLibrary(IntuitionBase);
 if(GfxBase) CloseLibrary(GfxBase);
 if(GadToolsBase) CloseLibrary(GadToolsBase);
 if(mp) DeleteMsgPort(mp);
 if(timeropen) {
	AbortIO(&treq);
	WaitIO(&treq);
	CloseDevice(&treq);
 }
 if(timerport) DeleteMsgPort(timerport);
 if(error) VPrintf("XSBCX: %s\n",&error);
 exit((error)?20:0);
}

#define BUFF(sg) ((struct StringInfo*)sg->SpecialInfo)->Buffer

long mouseoff;
extern struct Custom __far custom;
void offmouse(void)
{
	custom.dmacon=1<<5;
	mouseoff++;
}

void onmouse(void)
{
	custom.dmacon=(1<<15)|(1<<5);
	mouseoff=0;
}

static struct XSBInfo xsbi;
static struct XSBPref xsp[10];
void doblank(char *name)
{
	BPTR f;
	char prefname[30],preffile[40],*p;
	struct XSBPref *prp=0;

	if(!(XSBBase=OldOpenLibrary(name))) {
		doreq("XSBCX","Unable to open blanker library\n%s","Cancel",xsbname);
		return;
	}
	strcpy(p=prefname,&name[3]);
	while(*p!='.') p++; *p=0;
	sprintf(preffile,"ENV:XSB/%s.XSBP",prefname);
	if(f=Open(preffile,MODE_OLDFILE)) {
		Read(f,prp=xsp,400);
		Close(f);
	}
	offmouse();
	SetSignal(0,SIGBREAKF_CTRL_D);
	xsbi.tr=&treq;
	xsbi.prefs=prp;
	XSBBlankScreen(SIGBREAKF_CTRL_D,&xsbi);
	CloseLibrary(XSBBase);
	onmouse();
}

void brokeron(void)
{
	     ActivateCxObj(broker,-1);
}

void brokeroff(void)
{
	     ActivateCxObj(broker,0);
}

void qtimer(void)
{
 treq.tr_node.io_Command=TR_ADDREQUEST;
 treq.tr_time.tv_secs=5;
 treq.tr_time.tv_micro=0;
 BeginIO(&treq);
}

void atimer(void)
{
 AbortIO(&treq);
 WaitIO(&treq);
 SetSignal(0,1<<(timerport->mp_SigBit));
}

void main(int argc,char **argv)
{
 char **tt;
 CxMsg *msg;
 struct NewBroker nb;
 long sigmask=0;
 long id;
 int dopopup=0;

 if(argc==2 && *argv[1]=='?') {
   PutStr("\nUsage: XSBCX [CX_PRIORITY=pri] [CX_POPUP=YES|NO]\n\n");
   exit(0);
 }

 if(!(IconBase=OpenLibrary("icon.library",37)))
   cxcleanup("can't open icon.library");
 if(!(CxBase=OpenLibrary("commodities.library",37)))
   cxcleanup("can't open commodities.library");
 IntuitionBase=OpenLibrary("intuition.library",37);
 GadToolsBase=OpenLibrary("gadtools.library",37);
 GfxBase=OldOpenLibrary("graphics.library");

 loadprefs();
 if(argc!=1) {
   if(!(tt=ArgArrayInit(argc,argv))) cxcleanup("arg error");
   prio=ArgInt(tt,"CX_PRIORITY",0);
   dopopup=!stricmp("yes",ArgString(tt,"CX_POPUP","no"));
   ArgArrayDone();
 }
 if(!(mp=CreateMsgPort()))
   cxcleanup("out of memory");

 filter1=CxFilter(hotkey);
 AttachCxObj(filter1,CxSignal(FindTask(0),SIGBREAKB_CTRL_E));
 AttachCxObj(filter1,CxTranslate(0));

 filter2=CxFilter(popkey);
 AttachCxObj(filter2,CxSignal(FindTask(0),SIGBREAKB_CTRL_F));
 AttachCxObj(filter2,CxTranslate(0));

 cxsig1=CxFilter("alt shift del");
 AttachCxObj(cxsig1,CxSignal(FindTask(0),SIGBREAKB_CTRL_D));
 cxsig2=CxFilter("alt shift del");
 AttachCxObj(cxsig2,CxSignal(FindTask(0),SIGBREAKB_CTRL_D));
 SetFilterIX(cxsig1,&fix1);
 SetFilterIX(cxsig2,&fix2);

 nb.nb_Version=NB_VERSION;
 nb.nb_Name="XSBCX";
 nb.nb_Title="eXternal Screen Blanker Commodity";
 nb.nb_Descr="Driver for XSB libraries";
 nb.nb_Unique=NBU_UNIQUE|NBU_NOTIFY;
 nb.nb_Pri=prio;
 nb.nb_Flags=COF_SHOW_HIDE;
 nb.nb_Port=mp;
 nb.nb_ReservedChannel=0;

 if(!(broker=CxBroker(&nb,0)))
   cxcleanup(0);
 
 AttachCxObj(broker,filter1);
 AttachCxObj(broker,filter2);
 AttachCxObj(broker,cxsig1);
 AttachCxObj(broker,cxsig2);

 timerport=CreateMsgPort();
 treq.tr_node.io_Message.mn_ReplyPort=timerport;
 OpenDevice("timer.device",UNIT_VBLANK,&treq,0);
 timeropen=1;
 qtimer();

 brokeron();

 for(;;) {
   if(!dopopup) sigmask=Wait((1<<timerport->mp_SigBit)|(1<<mp->mp_SigBit)|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F|SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D);
   if(sigmask&SIGBREAKF_CTRL_C) {
     cxcleanup(0);
   }
   if(sigmask&SIGBREAKF_CTRL_D) {
	tick=0;
	if(mouseoff) onmouse();
   }
   if(sigmask&SIGBREAKF_CTRL_E) {
	atimer();
	Delay(10);
	Wait(SIGBREAKF_CTRL_D);
	doblank(xsbname);
	qtimer();
   }
   if(sigmask&SIGBREAKF_CTRL_F || dopopup) {
     brokeroff(); atimer(); popup(); qtimer(); brokeron(); dopopup=0;
	SetFilter(filter1,hotkey);
	SetFilter(filter2,popkey);
   }
   if(sigmask&(1<<timerport->mp_SigBit)) {
/*	DisplayBeep(0);*/
	WaitIO(&treq);
	tick++;
	if(blankmouse && tick>mousetimeout && !mouseoff) offmouse();
	if(tick>screentimeout) { doblank(xsbname); tick=0; }
	qtimer();
   }

   if(sigmask&(1<<mp->mp_SigBit)) {
     if(msg=GetMsg(mp)) {
       id=CxMsgID(msg);
       ReplyMsg(msg);
       switch(id) {
         case CXCMD_DISABLE: brokeroff(); break;
         case CXCMD_ENABLE: brokeron(); break;
         case CXCMD_UNIQUE: /* fallthrough */
         case CXCMD_APPEAR: 
	     brokeroff(); atimer(); popup(); qtimer(); brokeron();
		SetFilter(filter1,hotkey);
		SetFilter(filter2,popkey);
	     break;
         case CXCMD_KILL: cxcleanup(0); break;
       }
     }
   }
 }
}
