/*	demo_german.c
	Dies ist ein Beispiel-Blanker für Madhouse, mit deutschen Kommentaren.

   Hinweisen zum kompilieren des Programms:
	- Vielleicht mag Dein Compiler nicht die <pragma/...>-Includes.
     Dann kannst Du diese Includes evtl. weglassen, oder "pragma" muß ge-
     ändert werden.
	- Dieses Programm kann mit dem MaxonC++ Version 3 problemlos übersetzt
     werden. Für andere Compiler kann eine Anpassung nötig werden.
*/


#include <dos/dos.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>
#include <pragma/graphics_lib.h>
#include <pragma/intuition_lib.h>
#include <pragma/exec_lib.h>
#include <pragma/dos_lib.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

#define ABNC 0x40
#define ABC  0x80


/* Prototypen: */
void write_stopblank();
void read_prefs();
void write_error( char *str );


/* Variablen */
char text[40];
short color, scroll;
time_t start;
short duration_sec=0;
struct Library *IntuitionBase = NULL;
struct Library *GfxBase = NULL;
struct Screen *scr = NULL;
struct Window *win = NULL;
struct Message *msg = NULL;
USHORT DemoPalette[] = {
	0x0000, 0x0FFF
};
struct TextAttr topaz8 = {
	"topaz.font",
	8,
	0,
	0
};

/***************************************************************************
***                          open_all()
***                 Öffnet alle benötigten Dinge.
***************************************************************************/

BOOL open_all()
{
	IntuitionBase = OpenLibrary("intuition.library",37);
	if( !IntuitionBase ) return FALSE;
	GfxBase = OpenLibrary("graphics.library",37);
	if( !GfxBase ) return FALSE;

	/* Einen einfachen LowRes-Screen öffnen. */
	scr = OpenScreenTags(NULL,
		  SA_Depth,         1,
		  SA_Width,         320,
        SA_Height,        256,
		  SA_Font,          &topaz8,
		  TAG_DONE);
	if(!scr) return FALSE;
	
	/* Der Mauszeiger verschwindet, wenn man ihm die Farben des Hintergrunds
	   gibt: */
	SetRGB4( &scr->ViewPort,17,0,0,0);
	SetRGB4( &scr->ViewPort,18,0,0,0);
	SetRGB4( &scr->ViewPort,19,0,0,0);
	
	win = OpenWindowTags(NULL,
			 WA_AutoAdjust,    TRUE,
			 WA_NoCareRefresh, TRUE,
			 WA_CustomScreen,  scr,
			 WA_Flags,         WFLG_RMBTRAP,
			 WA_Borderless,    TRUE,
			 WA_Activate,      TRUE,
			 WA_IDCMP,			 IDCMP_MOUSEBUTTONS+IDCMP_RAWKEY,
			 TAG_DONE );
	if( !win ) return FALSE;
	
	LoadRGB4( &scr->ViewPort, DemoPalette, 2 );
	
	return TRUE;
}

/***************************************************************************
***                          close_all()
***             Schließt alles, was wir geöffnet hatten.
***************************************************************************/

void close_all()
{
	/* Diese Anweisung legt den Screen nach hinten. Dies verhindert einen
	   nervigen Effekt, wenn der Screen auf einem 68000-Amiga geschlossen
	   wird. */
	if( scr )
		ScreenToBack( scr );
	
	/* Wenn etwas schlief lief, müssen wir das Madhouse mitteilen. Aber
	   weil man write_error() nur einmal aufrufen darf, benötigen wir
	   diese nette if-Konstruktion: */
	
	if( !IntuitionBase ) write_error( "No intuition.lib V37!" );
	else {
		if( !GfxBase ) write_error( "No graphics.lib V37!" );
		else {
			if( !scr ) write_error( "Out of memory: Couldn't open screen.");
			else {
				if( !win ) write_error( "Out of memory: Couldn't open window.");
			}
		}
	}
	
	/* Jetzt schließen wir alles, was wir öffnen konnten. */
	if( win ) CloseWindow( win );
	if( scr ) CloseScreen( scr );
	if( GfxBase ) CloseLibrary( GfxBase );
	if( IntuitionBase ) CloseLibrary( IntuitionBase );
}

/***************************************************************************
***                              main()
***            Hier steht nun endlich der richtige Blanker:
***************************************************************************/

void main()
{
	BOOL quit = FALSE;
	BOOL user_quit = FALSE;
	short ypos = 20;
	short direction = 1;
	short oldy;
	
	/* Zuerst lesen wir die Blanker-Einstellungen (aus dem BlankerPrefs-
	   Fenster) sowie den Duration-Wert, der angibt, wielange der Blanker
	   blanken darf. */
	read_prefs();
	
	/* Jetzt wird die Stopp-Uhr gestartet (zum Überprüfen des Eigen-Abbruchs) */
	start = time(NULL);
	
	/* Screen und Fenster werden geöffnet. */
	if(open_all()) {
		
		/* Je nach Einstellung bekommt der Text eine andere Farbe: */
		switch( color ) {
			case 0:
				SetRGB4( &scr->ViewPort, 1, 15,0,0 );
				break;
			case 1:
				SetRGB4( &scr->ViewPort, 1, 15,15,0 );
				break;
			case 2:
				SetRGB4( &scr->ViewPort, 1, 0,0,15 );
		}
		
		/* Text-Parameter: der Text wird geschrieben. */
		SetAPen( win->RPort, 1 );
		Move( win->RPort, 5, ypos );
		Text( win->RPort, text, ( strlen(text) > 38 ? 38 : strlen(text)) );
		
		/* Hauptschleife. */
		while( !quit ) {
			
			/* Wenn Scroll gewählt wurde, muß der Text bewegt werden: */
			if( scroll ) {
				oldy = ypos;
				ypos += direction;
				if( (ypos > 220)  ||  (ypos < 20) ) direction *= -1;
				
				ClipBlit(win->RPort, 5, oldy-10, win->RPort, 5, ypos-10, 310, 20, ABNC | ABC );
				/* Minterme ABNC | ABC -> Rechteck ohne Veränderungen kopieren. */
			}
			
			/* Mausknöpfe oder ein Tastendruck? */
			if( msg = GetMsg(win->UserPort) ) {
				quit = TRUE;
				user_quit = TRUE;
				ReplyMsg( msg );
			}
			
			/* Wenn 'Change Blanker' im Hauptfenster aktiviert wurde
			   (duration_sec ist ungleich null) UND wir schon etwas länger
			   blanken als erlaubt (difftime(time(NULL),start) > time_counter)
			   dann müssen wir schlußmachen. */
			if( duration_sec && difftime(time(NULL),start) > duration_sec )
				quit = TRUE;
			
			WaitTOF();
		}
		
	}
	
	/* Alles Angeforderte schließen (und vielleicht einen Fehler schreiben): */
	close_all();
	
	/* Wenn unser Blanker durch den Anwender beendet wurde, müssen wir das Mad-
	   house mitteilen (sonst würde es [bei aktivertem Change Blanker] den
	   nächsten Blanker starten. */
	
	if( user_quit )
		write_stopblank();
	
	/* Und fertig! */
}


/***************************************************************************
***                                                                      ***
***              Funktionen zur Verständigung mit Madhouse               ***
***                                                                      ***
***************************************************************************/

/* Einige globale Variablen: */

char bu[1500];        /* Der Speicherbereich bu[] enthält die gesamte prefs-
                         Datei. */
short bu_seek = 0;    /* bu_seek ist der Offset von bu[]. Er gibt an, wo sich
                         die "Lesemarke" in bu befindet, ab der der nächste
                         Parameter gelsen wird. */

/* Erstmal einige nützliche Funktionen: */

/***************************************************************************
***                          read_next_digit()
***              Liest die nächste Nummer aus der prefs-Datei.
***              (Der nächste Parameter muß eine Nummer sein.)
***************************************************************************/

long read_next_digit()
{
	short number_cnt = 0;
	char number[50];
	
	while( bu[bu_seek] != (char) 0x0D ) {
		number[number_cnt] = bu[bu_seek];
		bu_seek++;
		number_cnt++;
	}
	number[number_cnt] = (char) 0x00;

	/*  Das (0x0D)(0x0A) muß übersprungen werden.
	 *  (Madhouse schreibt diese Sequenzen zwischen die Zeilen.)   */
	bu_seek+=2;
	
	return strtol( number, 0, 10 );
}

/***************************************************************************
***                          read_next_string()
***             Liest die nächste Zeichenkette aus der prefs-Datei.
***             (Der nächste Parameter muß eine Zeichenkette sein.)
**************************************************************************/

void read_next_string( char *string, short maxlen )
{
	short text_cnt = 0;
	
	/* Ein Madhouse-Text beginnt aus technischen Gründen (Aha) mit "$".
	   Weil wir das "$" nicht benötigen, überspringen wir einfach das
	   nächste Zeichen. */
	bu_seek++;
	
	while( (bu[bu_seek] != (char) 0x0D)  &&  (text_cnt < maxlen)  ) {
		string[text_cnt] = bu[bu_seek];
		bu_seek++;
		text_cnt++;
	}
	
	string[text_cnt] = (char) 0x00;
	/* Jetzt haben wir den Text in string[]. */
	
	/*
	 *  Die (0x0D)(0x0A)-Sequenz überspringen.
	 */
	
	bu_seek+=2;
}



/***************************************************************************
***                             read_prefs()
***                       Liest die Einstellungen.
***************************************************************************/

void read_prefs()
{
	short text_cnt = 0;
	short number_cnt = 0;
	BPTR f = NULL;
	
	f = Open( "RAM:Madhouse_Storage/prefs", MODE_OLDFILE );
	if (f) {
		Read( f, bu, sizeof( bu ) );
		
		/* Nun hat bu[] zum Beispiel so einen Inhalt:
		   "$Hello, this is a text(0x0D)(0x0A)2(0x0D)(0x0A)0(0x0D)(0x0A)
		   5(0x0D)(0x0A)RAM:Madhouse_Storage(0x0D)(0x0A)".
		   Die beiden Zeichen (0x0D) und (0x0A) sind zwischen jeder Zeile.
		   Hello,... ist unser erste Parameter. 2 ist der Zweite (die
		   Farbe des Textes), 0 der Dritte (Scrollen ja/nein), 5 ist
		   der Duration-Wert in Minuten und RAM:... ist der Pfad unseres
		   Verzeichnisses, falls wir eine Datei nachladen möchten.
		   Alle Madhouse-Strings beginnen mit "$".
		   Der erste Parameter wird in text[] verfrachtet, der Zweite kommt
		   in color, der Dritte in duration_sec und den Pfad brauchen wir
		   gar nicht. */
		
		/*
		 *   Erster Parameter (Text)
		 */
		 
		read_next_string( text, 40 );
		
		/*
		 *   Zweiter Parameter (Color)
		 */
		
		color = read_next_digit();
		
		/*
		 *  Dritter Parameter (Scroll)
		 */
		
		scroll = read_next_digit();
		
		/*
		 *  Duration-Parameter.
		 */
		
		duration_sec = read_next_digit() * 60; /*Minuten -> Sekunden*/
		
		Close( f );
	} else {     /* Der Blanker wurde nicht von Madhouse gestarten: Abbruch! */
		exit(0);
	}
}		

/***************************************************************************
***                           write_stopblank()
***   Muß benutzt werden, wenn der Blanker durch den Anwender abgebrochen
***               wurde, und nicht durch den Duration-Wert.
***************************************************************************/

void write_stopblank()
{
	/* Wir müssen nur eine neue, leere Datei anlegen, schon weiß Madhouse
	   bescheit. */
	
	BPTR f;
	f = Open( "RAM:Madhouse_Storage/stopblank", MODE_NEWFILE );
	if( f )
		Close( f );
}

/***************************************************************************
***                              write_error()
***     Macht Madhouse klar, daß ein Fehler auftrat (und wie der Fehler
***            heißt) - darf nur EINMAL aufgerufen werden!
***************************************************************************/

void write_error( char *str )
{
	BPTR f;
	char eol_marker = 0x0D;
	
	f = Open( "RAM:Madhouse_Storage/errors", MODE_READWRITE );
	if( f ) {
		Seek( f, 0, OFFSET_END );
		Write( f, str, strlen(str) );
		Write( f, &eol_marker, 1 );
		Close( f );
	} 
}




