/**********************************************************************
   Event-Recorder V1.0   zeichnet alle Events auf und l„žt sie bei +
   Bedarf wieder abspielen
   Tip: Speicher kann mittels SHIFT-Taste freigegeben werden.
        Wiedergabegeschwindigkeit kann mit ALT ge„ndet werden. 
        Der Menuepunkt ist mit Zusatztaste anzuklicken
**********************************************************************/

extern  long    gemdos();
extern  long    bios();

#define Fsetdta(a)      gemdos(0x1a,a)
#define Fcreate(a,b)    gemdos(0x3c,a,b)
#define Fopen(a,b)      gemdos(0x3d,a,b)
#define Fclose(a)       gemdos(0x3e,a)
#define Fread(a,b,c)    gemdos(0x3f,a,b,c)
#define Fwrite(a,b,c)   gemdos(0x40,a,b,c)
#define Malloc(a)       gemdos(0x48,a)
#define Mfree(a)        gemdos(0x49,a)
#define Fsfirst(a,b)    (int)gemdos(0x4e,a,b)
#define BING            bios(3,2,7)
#define EOS             '\0'
#define FALSE           0
#define TRUE            1

struct DTA
{
   char dummy[21];
   char attribut;
   int  time;
   int  date;
   long size;
   char dat_name[14];
}  dta_buff;

#define ARROW           0
#define HOURGLASS       2
#define WF_WORKXYWH     4
#define K_RSHIFT        0x0001
#define K_LSHIFT        0x0002
#define K_CTRL          0x0004
#define K_ALT           0x0008
#define AC_OPEN         40
#define AC_CLOSE        41
#define MU_KEYBD        0x0001
#define MU_BUTTON       0x0002
#define MU_M1           0x0004
#define MU_M2           0x0008
#define MU_MESAG        0x0010
#define MU_TIMER        0x0020

struct Aufnahme
{
    int  eventart;
    long eventparameter;
    int  filler;
};
long    eintraege;
struct  Aufnahme        *puffer;

#define DEFAULT_SPEED   100
int     speed;
#define GEFUELLT_SPEICHER       0
#define LEER_SPEICHER           1
#define KEIN_SPEICHER           2
int     leer;

char    f_path[82],
        f_name[82],
        search[6],
        f_anwahl[82];

#define BOOTDATEI       "C:\AUTOEXEC.EVN"
#define WAIT_DEFAULT    5000
int     contrl[12],
        intin[128],
        intout[128],
        ptsin[128],
        ptsout[128];
        
int     handle,
        phys_handle;
        
int     gl_hchar,
        gl_wchar,
        gl_hbox,
        gl_wbox;
        
int     xdesk,
        ydesk,
        wdesk,
        hdesk;
        
int     x_aufl,
        y_aufl,
        bitplanes;
        
extern  int     gl_apid;
int     menu_id;
        
int     dummy;


/* Initialisierungen fr GEM-Programme */

_start()
{
form_alert(1,"[1][Dies ist Start][ok]");
}

open_vwork()
{
   register     int i;
   appl_init(); 
   if (gl_apid == -1) return FALSE;
   for (i=1; i<10; intin[i++]=1);
   intin[10]=2;
   phys_handle = graf_handle (&gl_wchar, &gl_hchar, &gl_wbox, &gl_hbox);
   
   intin[0] = handle = phys_handle;
   v_opnvwk(intin, &handle, intout);
   x_aufl = intout[0];  /* hier steht die Aufl”sung drin */
   y_aufl = intout[1];
   bitplanes = (intout[13] == 2) ? 1 : ((intout[13] == 4) ? 2 : 4);
   
   vqt_attributes(handle, intout);
   gl_wchar = intout[6];        /* Werte graf_handle waren falsch */
   gl_hchar = intout[7];
   gl_wbox  = intout[8];
   gl_hbox  = intout[9];
   wind_get(0, WF_WORKXYWH, &xdesk, &ydesk, &wdesk, &hdesk);
   return TRUE;
}

close_vwork()
{
   v_clsvwk(handle);
   appl_exit();
}

main()
{
   if ( open_vwork() == TRUE )
   {
      if(( menu_id = menu_register( gl_apid,"  Recorder\277 ")) == -1 )
      {
         puts("Acc-Recorder kann nicht installiert werden!");;
         appl_exit();
      }
      else
      {
         /* puts("Acc-Recorder installiert!");; */
         endlos();
      }
      close_vwork();
   }
   else puts("Acc-Recorder: Fehler bei Programminitialisierung!");
        return 0;
}

/* Wieviel Speicher wird verbraucht? */

long config()
{
   register int  antwort;
   char s[220];
   register long max = (long)Malloc(-1L) / sizeof(struct Aufnahme),
                 anzahl = 0;

   do
   {
      anzahl += 1024; /* bei jedem Durchlauf 1 KB dazu */
      if ( anzahl > max ) anzahl = max; /* mehr ist nicht da */
      sprintf (s,
         "[2][%s|%s|%s|%s|%7ld kByte][%ld|mehr|Abbruch]",
         "Event-Recorder\277 V1.0 \21\31\30\31",
         "     by D. Schaun", 
         "Gewnschte \"Bandl„nge\"?",
         "Aktueller Speicherbedarf:",
         ( (sizeof(struct Aufnahme) * anzahl) + 512 ) >> 10,
         anzahl );
      antwort = form_alert( 1, s );
   }
   while( antwort == 2 );        /* solange mehr gewnscht */
   if( antwort == 3 ) return 0;  /* Abbruch */
   return anzahl;
}

recorder(state)
int state;
{
   char s[220];
   register int antwort;

   evnt_timer( 0, 0 );          /* 0 Millisekunden warten */
   if( state & K_RSHIFT ||      /* SHIFT rechts oder */
       state & K_LSHIFT )       /* SHIFT lins */
   {
      if( leer != KEIN_SPEICHER )       /* Speicher vorhanden? */
      {
         if( 1 == form_alert( 1,
            "[2][Speicher wieder|zurckgeben?][Her damit|Behalt' ihn]" ) )
         {
            Mfree( puffer );
            leer = KEIN_SPEICHER;
         }
      }
      else form_alert( 1, "[1][Ich habe|keinen|Speicher!][Na dann]" );
      return;
   }
   if( state & K_CTRL )         /* CTRL-Taste => IO */
   {
      if( leer == GEFUELLT_SPEICHER )   /* Laden/Speicher m”glich? */
         antwort = form_alert( 1,
         "[2][Datentransfer|Welche Operation?][Abbruch|Laden|Speicher]");
      else                      /* Speicher leer? nur Laden m”glich */
         antwort = form_alert( 1,
         "[2][Datentransfer][Abbruch|Laden]" );
      if( antwort == 1 ) return;        /* Abbruch */
      if( do_file( f_path, f_name, search, f_anwahl ) )
      {
         register int datei;
         if( antwort == 2 )             /* Laden */
         {
            Fsetdta( &dta_buff );
            Fsfirst( f_anwahl, 0 );     /* Filel„nge ermittels */
            if( leer != KEIN_SPEICHER )
            {
               Mfree( puffer );
               leer = KEIN_SPEICHER;
            }
            /* Gesamte Datei laden */
            puffer = (struct Aufnahme *)Malloc( dta_buff.size );
            if( !puffer )
            {
               form_alert( 1,
               "[1][Datei pažt|nicht in|den Speicher!][Abbruch]" );
               return;
            }
            leer = LEER_SPEICHER;  /* Speicher ist nun vorhanden */
            datei = Fopen( f_anwahl, 0 );
            if( datei < 0 )
            {
               sprintf( s,
                  "[1][Die Datei|%s|%s|Fehlercode %d][Abbruch]",
                  f_anwahl,
                  "kann nicht gelesen werden!",
                  datei );
               form_alert(1, s );
               return;
            }
            graf_mouse( HOURGLASS, &dummy );
            Fread( datei, (long)sizeof(speed), &speed );
            if( speed > 10000 || speed < 1 ) speed = 100;
            Fread( datei, dta_buff.size, puffer );      /* alles einlesen */
            eintraege = dta_buff.size / sizeof(struct Aufnahme);
            leer = GEFUELLT_SPEICHER;
         }
         else           /* Speichern */
         {
            datei = Fcreate( f_anwahl, 0 );
            if( datei < 0 )
            {
               sprintf( s,
                  "[1][Die Datei|%s|%s|Fehlercode %d][Abbruch]",
                  f_anwahl,
                  "kann nicht erzeugt werden!",
                  datei );
               form_alert(1, s );
               return;
            }
            graf_mouse( HOURGLASS, &dummy );
            Fwrite( datei, (long)sizeof(speed), &speed );
            Fwrite( datei, sizeof(struct Aufnahme) * eintraege, puffer );
         }
         Fclose( datei );
         graf_mouse( ARROW, &dummy );
      } /* Abbruch-Knopf ausgew„hlt */
      return;
   }
   if( state & K_ALT )          /* ALT-Taste => Speed */
   {
      do /* Nicht fr gr”žere Žnderungen gedacht */
      {
         sprintf( s, "[2][%s|%s| |%s %4d][Schneller|Langsamer|OK]",
            "Abspielgeschwindigkeit",
            "einstellen! (1 - 10000)",
            "Aktuell:", speed );
         antwort = form_alert( 1, s );
         if( antwort == 1 )
         {
            speed <<= 1;     /* Verdoppeln */
            if( speed > 10000 ) speed = 1;
         }
         if( antwort == 2 )
         {
            speed >>=1;      /* Halbieren */
            if( speed < 1 )     speed = 10000;
         }
      } while( antwort != 3 );
      return;
   }
   if( leer == KEIN_SPEICHER )
   {
      eintraege = config();     /* Wieviele Eintr„ge? */
      if( !eintraege ) return;
      puffer = (struct Aufnahme *)Malloc( sizeof(struct Aufnahme) * eintraege );
      if( !puffer )             /* haben wir den Speicher bekommen? */
      {
         form_alert( 1,
            "[1][Dafr reicht|der Speicher nicht!][Abbruch]" );
         return;
      }
      leer = LEER_SPEICHER;
   }
   if( leer != KEIN_SPEICHER )
   {
      if( leer == LEER_SPEICHER )
      {
         sprintf( s, "[2][%s| |%s|%s|%s][Noch nicht|Aufnahme]",
            "Die erste Aufnahme?",
            "Nach Anklicken von",
            " \"Aufnahme\" geht",
            "   es SOFORT los!" );
         antwort = form_alert( 1, s );
      }
      else
         antwort = form_alert( 2,
            "[2][Was wird gewnscht?][Nichts|Aufnahme|Abspielen]" );
      if( antwort == 1 ) return;
      play_record( antwort == 3 );
   }
}

/* Flag mit 0=Aufnahme, 1=Abspielen */
play_record( play )
register int play;
{
   /* in Bl”cken zu 16 KB aufspalten,
      ab 32 KB bekommt GEM Probleme */
   long ges = eintraege * sizeof(struct Aufnahme);
   register long vollstaendige = ges >> 14,
                 ptr = (long)puffer;
   int  rest = ges & 0x3FFF,
        anz  = 16384 / sizeof(struct Aufnahme); /* Elemente in 16 KB */

   BING;
   /* Ruhe, Aufnahme l„uft! */
   while( vollstaendige-- )      /* komplette 16-KB-Bl”cke */
   {
      if( play ) appl_tplay( ptr, anz, speed );
      else       appl_trecord( ptr, anz );
      ptr += 16384;
   }
   /* den letzten Schnippel auch noch */
   if( rest )
      if( play ) appl_tplay( ptr, rest / sizeof(struct Aufnahme), speed );
      else       appl_trecord( ptr, rest / sizeof(struct Aufnahme) );
   BING;
   if( !play )          /* Aufnahme beendet */
   {
      form_alert( 1, "[3][Danke, das war's][Stop]" );
      leer = GEFUELLT_SPEICHER;
   }
}

bootload( boot_datei )          /* Bootdatei laden, falls vorhanden */
register char *boot_datei;      /* keine Fehlermeldungen!! */
{
   register int datei;

   Fsetdta( &dta_buff );
   if( Fsfirst( boot_datei, 0 ) || dta_buff.size <= 2 ) return;
   puffer = (struct Aufnahme *)Malloc( dta_buff.size );
   if( !puffer ) return;
   leer = LEER_SPEICHER;
   datei = Fopen( boot_datei, 0 );
   if( datei < 0 ) return;
   Fread( datei, (long)sizeof(speed), &speed );
   if( speed > 10000 || speed < 1 ) speed = 100;
   Fread( datei, dta_buff.size, puffer );
   Fclose( datei );
   eintraege = dta_buff.size / sizeof(struct Aufnahme);
   leer = GEFUELLT_SPEICHER;
   evnt_timer( WAIT_DEFAULT, 0 );       /* Warten auf Desktop Aufbau */
   play_record( 1 );
}

endlos()
{
   int event,
       keycode,
       state,           /* Status der Zusatztasten SHIFT und ALT */
       msgbuff[8];

   speed = DEFAULT_SPEED;
   leer = KEIN_SPEICHER;
   *f_path = EOS;
   *f_name = EOS;
   strcpy( search, ".EVN" );
   bootload( BOOTDATEI );       /* wenn vorhanden laden */
   while( TRUE )                /* forever */
   {
      event = evnt_multi( MU_MESAG | MU_BUTTON | MU_KEYBD,
                           1, 1, 1,
                           0, 0, 0, 0, 0,
                           0, 0, 0, 0, 0,
                     msgbuff, 0, 0, &dummy, &dummy, &dummy, &state,
                           &keycode, &dummy ); 

      /* unser ACC ausgew„hlt ? */
      if( event & MU_MESAG      &&
          msgbuff[0] == AC_OPEN &&
          msgbuff[4] == menu_id )  recorder( state );
   }
}

/* Name:        do_file    (04.12.87)
   Parameter:   f_path, f_name, search, f_anwahl (Strings)
                f_path    Vorschlag des Paths
                f_name    Dateiname im "Auswahl:"-Feld
   Rckgabewerte: Taste (0=ABBRUCH, 1=OK) mit return
                f_path    Aktueller Path zum Directory
                f_name    Dateiname ohne Extension
                f_anwahl  kompletter Pfad incl. Name und Extension
   Funtion:     L„žt Benutzer einen Dateinamen ausw„hlen
*/
#define EOS '\0'
extern  long    gemdos();
#define Dgetdrv()       (int)gemdos(0x19)
#define Dgetpath(a,b)   gemdos(0x47,a,b)
#define Dsetdrv(a)      gemdos(0x0e,a)
#define Dsetpath(a)     gemdos(0x3b,a)

do_file( f_path, f_name, search, f_anwahl )
register char *f_path, *f_name;
char *search, *f_anwahl;
{
   char help_path[64],
        help_name[64];
   int  key;
   register int i;

   if(( i = index( f_path, '*' )) >= 0 )   f_path[i] = EOS;
   strcpy( help_path, f_path );
   strcpy( help_name, f_name );
   if( !f_path[0] )   get_path( f_path );
   strcat( f_path, "*" );
   strcat( f_path, search );
   fsel_input( f_path, f_name, &key );
   if( !f_name[0] || f_name[0] == '.' )   key = 0;
   if( key )
   {
      register int j;
      i = rindex( f_path, '\\' );
      if( i >= 0 )   f_path[++i] = EOS;
      do        /* Pfadname von Blitter-TOS-Bug befreien */
      {
         i = index( f_path, '.' );
         if( i >= 0 && f_path[i+1] == '\\' )
         {
            strcpy( &f_path[i], &f_path[i+1] );
            j = 1;
         }
         else
            j = 0;
      } while( j );
      strcpy( f_anwahl, f_path );
      /* Macke des Blitter-TOS ("XXXXXXXX.") */
      if( strlen( f_name ) == 9 && f_name[8] == '.' )   f_name[8] = EOS;
      strcat( f_anwahl, f_name );
      if( (i = index( f_name, '.' )) >= 0 )   f_name[i] = EOS;
   }
   else
   {
      strcpy( f_path, help_path );
      strcpy( f_name, help_name );
      f_anwahl[0] = EOS;
   }
   return( key );
}

get_path( path )
register char *path;
{
   register int fehler;

   path[0] = Dgetdrv() + 'A';
   path[1] = ':';
   fehler = Dgetpath( &path[2], 0 );
   strcat( path, "\\" );
   return fehler;
}

index( s, c )
register char s[];
register char c;
{
   register int i = 0;
   while( s[i] && s[i] != c )  i++;
   if( s[i] )  return i;
   return -1;
}

rindex( s, c )
register char s[];
register char c;
{
   register int i = strlen(s);
   while( i >= 0 && s[i] != c )  i--;
   return i;
}
