/*
	    MausAus

    die Maus wird aus dem Weg geräumt


	     von

	 Jürgen Mülbert
	 Rathausstr.42
    6803 Edingen
	 Tel 06203/81467

    mit AZTEC V3.6

*/

/*  Viele, viele includes   */

#include <fcntl.h>
#include <exec/types.h>
#include <exec/lists.h>
#include <exec/nodes.h>
#include <exec/tasks.h>
#include <exec/ports.h>
#include <exec/memory.h>
#include <exec/io.h>
#include <exec/devices.h>

#include <devices/input.h>
#include <devices/inputevent.h>
#include <devices/timer.h>

#include <libraries/dos.h>
#include <libraries/dosextens.h>

#include <workbench/workbench.h>
#include <workbench/startup.h>

#include <hardware/custom.h>
#include <hardware/dmabits.h>
#include <hardware/intbits.h>

#include <graphics/rastport.h>
#include <graphics/gfx.h>
#include <graphics/gfxmacros.h>

#include <intuition/intuitionbase.h>
#include <intuition/intuition.h>

/*  Nur ein define !	*/

#define   AUSZEIT 10


/*  Die externen. Ich hoffe die LATTICE-Besitzer
    freuen sich darüber.
    Ich hätte einfach '#include <functions.h>
    mit einlesen können
*/

extern struct IntuitionBase *OpenLibrary();
extern struct MsgPort	    *CreatePort();
extern struct Message	    *GetMsg();
extern struct IOStdReq	    *CreateStdIO();
extern struct Process	    *FindTask();
extern struct DiskObject    *GetDiskObject();
extern struct Window	    *OpenWindow();
extern APTR		     AllocMem();
extern STRPTR		     FindToolType();
extern long		     OpenDevice(), SetSignal(), Wait();
extern int		     atoi(), strlen();
extern void		     CloseLibrary(), CloseDevice();
extern void		     FreeMem(), DoIO();
extern void		     DeletePort(), DeleteStdIO();
extern void		     ReplyMsg();
extern void		     CloseWindow();
extern void		     FreeDiskObject();

/*  Die zwei sind im Assemblerteil  */

extern void		     Handler();
extern void		     InitHandler();

/*  Beim Amiga gibts immer globales */

struct NewWindow nw =
    { 0,0,300,11,0,1,CLOSEWINDOW,
      WINDOWDEPTH|WINDOWCLOSE|WINDOWDRAG,
      NULL,NULL,
      (STRPTR)"MausAus von Jürgen Mülbert",
      NULL,NULL,0,0,0,0,
      WBENCHSCREEN
     };

ULONG  *IconBase = 0;		  /* Die IconBase wird für die WB */
				  /* gebraucht. */
int    zeit	 = 0;
ULONG  windsig	 = 0;

ULONG  ev_signal;		  /* Die zwei werden im Assembler- */
struct Process *meintask;	  /* teil benötigt */

struct Window  *win;


struct MemEntry       me[10];	  /* Etwas Platz für Daten der inter-
				     rupt Routine   */
struct MsgPort	     *inp_msg, *tim_msg;
struct IOStdReq      *inp_req;
struct timerequest   *tim_req;
struct Interrupt     i_handl;
struct IntuitionBase *IntuitionBase;

/*
 *  In der Funktion ifback() wird festgestellt
 *  ob das Programm vom CLI aus gestartet wurde.
 *  Trifft das zu wird überprüft ob es als
 *  Hintergrund Process läuft (mit RUN gestartet)
 *  und das Ergebnis (TRUE wenn BACKGROUND) zu-
 *  rückgegeben
 */

BOOL ifback()
{
    register BOOL flag = 0;
    register struct CommandLineInterface *cli;

    if (meintask->pr_CLI)
     {
      cli = (struct CommandLineInterface *)
	    ((long)meintask->pr_CLI << 2);

      flag = cli->cli_Background;
     }

    /* Das DOS hat eine etwas andere Aufassung von
       TRUE und FALSE. Deswegen die Umwandlung */

    if (flag == DOSTRUE) return(TRUE);
    else		 return(FALSE);
}

/*
 *  Die Routine _wb_parse() wird beim AZTEC im Startup-Teil
 *  aufgerufen. Allerdings überprüft die ob der USER wünscht
 *  das ein Fenster geöffnet wird. Für dieses Programm soll
 *  kein Fenster geöffnet werden.
 */

void _wb_parse(pp,wbm)
register struct Process *pp;
struct WBStartup *wbm;
{
    void cleanup();
    register struct DiskObject *dop;
    register struct FileHandle *fhp;
    register STRPTR cp;
    register long wind;


    if ( (IconBase = (ULONG *)OpenLibrary("icon.library",0L)) == 0)
	return;

    if ( (dop = GetDiskObject(wbm->sm_ArgList->wa_Name)) == 0)
	goto fertig;

    if (cp = FindToolType(dop->do_ToolTypes,"ZEIT"))
      zeit = atoi(cp);

    FreeDiskObject(dop);
fertig:
    CloseLibrary(IconBase);

    /*	Wenn das Programm von der WB gestartet wurde
	wird die Intuition geöffnet und ein Fenster
	das nur so hoch wie die Titelleiste ist. Dieses
	Fenster hat den Ausschaltknopt für das Programm
	zu beenden
    */

    if ( (IntuitionBase = OpenLibrary("intuition.library",0L)) == NULL)
     exit(20);

    if ( (win = (struct Window *)OpenWindow(&nw)) == NULL)
      cleanup(1);

    windsig = 1L <<win->UserPort->mp_SigBit;


}

/*
 *  Alles zurück zum AMIGA
 */

void cleanup(fehler)
int fehler;
{
    switch(fehler)
     {
      case  0 :
	AbortIO(tim_req);
	CloseDevice(tim_req);
      case  6 :
	FreeMem(tim_req,(long)sizeof(struct timerequest));
      case  5 :
	DeletePort(tim_msg);
      case  4 :
	inp_req->io_Command = IND_REMHANDLER;
	DoIO(inp_req);
	CloseDevice(inp_req);
      case 3 :
	DeleteStdIO(inp_req);
      case 2 :
	if (win) CloseWindow(win);
	DeletePort(inp_msg);
      case 1 :
	FreeSignal(ev_signal);
	if (IntuitionBase) CloseLibrary(IntuitionBase);
     }

    exit(fehler);
}

/*
 * Alle Resourcen allokieren
 */

void openall()
{
    InitHandler();

    if ( (inp_msg = CreatePort(0L,0L)) == NULL)
     cleanup(1);

    if ( (inp_req = CreateStdIO(inp_msg)) == NULL)
     cleanup(2);

    i_handl.is_Data = (APTR)&me[0];
    i_handl.is_Code = Handler;
    i_handl.is_Node.ln_Pri = 51;

    if (OpenDevice("input.device",0L,inp_req,0L))
     cleanup(3);

    if ( (tim_msg = CreatePort(0L,0L)) == NULL)
     cleanup(4);

    if ( (tim_req = (struct timerequest *)
	  AllocMem((long)sizeof(struct timerequest),MEMF_PUBLIC|MEMF_CLEAR))
	== NULL)
      cleanup(5);

    tim_req->tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
    tim_req->tr_node.io_Message.mn_ReplyPort	= tim_msg;

    if (OpenDevice(TIMERNAME,UNIT_VBLANK,tim_req,0L))
      cleanup(6);

    inp_req->io_Command = IND_ADDHANDLER;
    inp_req->io_Data	= (APTR)&i_handl;

    DoIO(inp_req);
}

/*
 *  Hier wird der Timer jede Sekunde neu gestartet
 */

void QueueTimer(timer)
register struct timerequest *timer;
{
    timer->tr_node.io_Command  = TR_ADDREQUEST;
    timer->tr_time.tv_secs     = 1;
    timer->tr_time.tv_micro    = 0;
    SendIO(timer);
}

/*
 *  Ein kurze Hinweis für die Benutzung
 */

void usage()
{
    static char U[] =
	"MausAus\nUSAGE : MausAus [Zeit] default 10 Sekunden\n";

    Write(_devtab[1].fd,U,(long)strlen(U));
    exit(1);
}

/*
 * Hier gehts los
 */

main(argc,argv)
int  argc;
TEXT *argv[];
{
    register ULONG sigs,
		   timesig,
		   sig;
    register BOOL  Maus = TRUE;
    register UWORD interval = 0;

    if (argc > 1)
     {
      if (*argv[1] == '?') usage();
      else     zeit = atoi(argv[1]);
     }

    if (zeit == 0) zeit = AUSZEIT;

    openall();

    /* Kein wichtiger Task  */
    SetTaskPri(meintask,-1L);

    /*	Bei RUN werden alle geöffneten
	ein und ausgabe Kanäle geschlossen */

    if (ifback() == TRUE)
     {
      _devtab[0].mode &= ~O_STDIO;
      _devtab[1].mode &= ~O_STDIO;
      close(0);
      close(1);
      close(2);
      sigs = 0; /* Und CONTROL_C wird gesperrt */
     }
    else sigs = SIGBREAKF_CTRL_C;

    QueueTimer(tim_req);

    timesig = 1L <<tim_msg->mp_SigBit;
    sigs    |= ev_signal | timesig | windsig;

    FOREVER
     {
      sig = Wait(sigs);

      if (sig & SIGBREAKF_CTRL_C) break;
      if (sig & windsig)
       {
	ReplyMsg(GetMsg(win->UserPort));
	goto fertig;
       }
      else if (sig & timesig)
       {
	GetMsg(tim_msg);
	if (Maus == TRUE && ++interval > zeit)
	 {
	  OFF_SPRITE;
	  Maus = FALSE;
	 }
	if (Maus == TRUE) QueueTimer(tim_req);
       }
      else if (sig & ev_signal)
       {
	if (Maus == FALSE)
	 {
	  Maus = TRUE;
	  ON_SPRITE;
	  interval = 0;
	  QueueTimer(tim_req);
	 }
       }
     }
fertig:
    /* Falls die Maus noch versteckt ist wird sie
       wieder enttarnt.
    */
    if (Maus == FALSE) ON_SPRITE;
    cleanup(0);
}
