/*
 * WBClock.c
 * Eröffnet auf dem 'standard Public Screen' ein Window mit Datum und Uhrzeit
 * Version : 1.2
 * Autor   : Markus Zahn
 * Datum   : 4.1.1994
 * Compiler: SAS/C 6.50
 */

#define TITLE "WBClock"
#define VERSION "1.2"

#define MAX_CHAR 64

/* Standard Includes */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Amiga Includes */
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/icon.h>
#include <proto/intuition.h>
#include <proto/locale.h>

#include <exec/memory.h>
#include <devices/timer.h>
#include <workbench/startup.h>
#include <workbench/icon.h>

char *__procname = "WBClock"; /* Name des Hintergrundprozesses */

#define RP win->RPort

char version[] = "\0$VER: "TITLE" "VERSION; /* Für die Abfrage durch 'version' */

extern struct WBStartup *WBenchMsg; /* Für ToolTypes */

struct Window *win = NULL;
struct Screen *scr = NULL;
struct MsgPort *timerport;
struct IntuiMessage *imsg;
struct timerequest *timereq;
struct Locale *locale;

char wtitle[MAX_CHAR];
int timeropen = FALSE;

struct ToolTypes
{
  long Tt_Top;
  long Tt_Left;
  char Tt_Screen[MAX_CHAR];
  char Tt_Format[MAX_CHAR];
  char Tt_Locale[MAX_CHAR];
} tooltypes = { -1, -1, '\0', '\0', '\0' };

void addrequest( int secs );
void cleanup( void );
int createwindow( void );
int gettime( void );
void gettooltypes( void );
int initall( void );
int inittimer( void );
int openlibs( void );
void printtime( void );
void __saveds __asm pchar( register __a0 struct Hook *hook,
  register __a2 APTR object,
  register __a1 APTR message );

void addrequest( int secs )
{
  /* Timer Request initallialisieren... */
  timereq->tr_node.io_Message.mn_ReplyPort = timerport;
  timereq->tr_node.io_Command = TR_ADDREQUEST;
  timereq->tr_node.io_Flags = 0;
  timereq->tr_node.io_Error = 0;
  timereq->tr_time.tv_secs = secs;
  timereq->tr_time.tv_micro = 0;

  /* ... und an das Timer Device übergeben */
  BeginIO( (struct IORequest *)timereq );
}

void cleanup( void )
{
  if( locale )
    CloseLocale( locale );
  if( win )
    CloseWindow( win );
  if( timeropen )
  {
    /* Timer Request abbrechen und auf Ende warten */
    AbortIO( (struct IORequest *)timereq );
    WaitIO( (struct IORequest *)timereq );

    /* Device schließen */
    CloseDevice( (struct IORequest *)timereq );
  }
  if( timerport )
    DeleteMsgPort( timerport );
  if( timereq )
    DeleteIORequest( timereq );
  if( IntuitionBase )
    CloseLibrary( (struct Library *)IntuitionBase );
  if( GfxBase )
    CloseLibrary( (struct Library *)GfxBase );
}

int createwindow( void )
{
  long width, left = -1, top = -1;

  if( tooltypes.Tt_Top >= 0 )
    top = tooltypes.Tt_Top;
  if( tooltypes.Tt_Left >= 0 )
    left = tooltypes.Tt_Left;

  /* Default Public Screen blockieren falls vorhanden... */
  if( !( scr = LockPubScreen( (UBYTE *)tooltypes.Tt_Screen ) ) )
    scr = LockPubScreen( NULL ); /* ... wenn nicht, dann versuche DefaultPubScreen */

  if( scr )
  {
    /* Windowgröße bestimmen */
    width = TextLength( &scr->RastPort, (STRPTR)wtitle, strlen( wtitle ) ) + 40;
    if( left < 0 )
      left = scr->Width - width - 23; /* Heuristik!? */
    if( top < 0 )
      top = 0;
    win = OpenWindowTags( NULL, WA_Top, top, WA_Left, left,
        WA_Height, scr->BarHeight + 1,
        WA_Width, width,
        WA_Flags, WFLG_NOCAREREFRESH | WFLG_SIMPLE_REFRESH,
        WA_IDCMP, IDCMP_CLOSEWINDOW,
        WA_RMBTrap, (ULONG)TRUE,
        WA_DragBar, (ULONG)TRUE,
        WA_CloseGadget, (ULONG)TRUE,
        WA_ScreenTitle, TITLE" "VERSION,
        WA_PubScreen, scr,
        TAG_DONE );

    /* Public Screen wieder freigeben */
    UnlockPubScreen( NULL, scr );
  }
  return( win != NULL );
}

int gettime( void )
{
  static struct DateStamp datestamp;
  struct Hook putc_hook = { {NULL, NULL}, (ULONG(*)())pchar, NULL, 0 };

  DateStamp( &datestamp );
  if( tooltypes.Tt_Format[0] != '\0' )
    FormatDate( locale, tooltypes.Tt_Format, &datestamp, &putc_hook );
  else
    FormatDate( locale, locale->loc_ShortDateTimeFormat, &datestamp, &putc_hook );
  return( 60 - datestamp.ds_Tick / TICKS_PER_SECOND );
  /* Sekunden bis zu nächsten Minute */
}

void gettooltypes( void )
{
  struct DiskObject *dobj;
  UBYTE *str;

  if( WBenchMsg != NULL ) /* Start von der Workbench? */
  {
    /* ToolTypes Array auslesen */
    if( dobj = GetDiskObject( (UBYTE *)WBenchMsg->sm_ArgList->wa_Name ) )
    {
      if( str = FindToolType( (UBYTE **)dobj->do_ToolTypes,
          (UBYTE *)"WBCLOCK_TOP" ) )
        tooltypes.Tt_Top = atol( (char *)str );
      if( str = FindToolType( (UBYTE **)dobj->do_ToolTypes,
          (UBYTE *)"WBCLOCK_LEFT" ) )
        tooltypes.Tt_Left = atol( (char *)str );
      if( str = FindToolType( (UBYTE **)dobj->do_ToolTypes,
          (UBYTE *)"WBCLOCK_FORMAT" ) )
        strncpy( tooltypes.Tt_Format, ( char *)str, MAX_CHAR - 1 );
      if( str = FindToolType( (UBYTE **)dobj->do_ToolTypes,
          (UBYTE *)"WBCLOCK_SCREEN" ) )
        strncpy( tooltypes.Tt_Screen, (char *)str, MAX_CHAR - 1 );
      if( str = FindToolType( (UBYTE **)dobj->do_ToolTypes,
          (UBYTE *)"WBCLOCK_LOCALE" ) )
        strncpy( tooltypes.Tt_Locale, (char *)str, MAX_CHAR - 1 );
      FreeDiskObject( dobj );
    }
  }
}

int initall( void )
{
  int ok = FALSE;
  struct EasyStruct req = { sizeof( struct EasyStruct ),
    0,
    (UBYTE *)"Locale error:",
    (UBYTE *)"Unable to open preset file\n\"%s\"",
    (UBYTE *)"OK" };

  if( inittimer() )
  {
    gettooltypes();
    if( ( locale = OpenLocale( tooltypes.Tt_Locale ) ) == NULL )
    {
      if( tooltypes.Tt_Locale[0] != '\0' )
        EasyRequest( win, &req, NULL, tooltypes.Tt_Locale );
      locale = OpenLocale( NULL );
    }
    if( locale )
    {
      gettime(); /* Windowgröße wird nach TextLength(wtitle) bestimmt */
      if( createwindow() )
      {
        ok = TRUE;
        addrequest( gettime() );
        printtime();
      }
    }
  }
  return( ok );
}

int inittimer( void )
{
  /* Message Port öffnen */
  timerport = CreateMsgPort();

  /* Timer Request allozieren */
  timereq = CreateIORequest( timerport, sizeof(struct timerequest) );

  if( timereq && timerport )
  {
    /* Timer Device öffnen */
    if( OpenDevice( (STRPTR)TIMERNAME, UNIT_VBLANK,
        (struct IORequest *)timereq, 0 ) == 0 )
      timeropen = TRUE;
  }
  return( timeropen );
}

void printtime( void )
{
  SetWindowTitles( win, (UBYTE*)wtitle, (UBYTE*)~0 );
  WindowToFront( win );
}

void __saveds __asm pchar( register __a0 struct Hook *hook,
  register __a2 APTR object,
  register __a1 APTR message )
{
  if( (long)hook->h_Data < MAX_CHAR - 1 )
    wtitle[(long)hook->h_Data] = (char)message;
  hook->h_Data = (APTR)( (long)( hook->h_Data ) + 1 );
  if( (char)message == '\0' )
    hook->h_Data = (APTR)0;
}

void main( int argc, char *argv[] )
{
  int done = FALSE;
  ULONG signals;

  if( argc == 0 )
    WBenchMsg = (struct WBStartup *)argv;

  if( initall() )
  {
    do
    {
      signals = Wait( ( 1 << win->UserPort->mp_SigBit ) | ( 1 << timerport->mp_SigBit ) );
      if( signals & ( 1 << win->UserPort->mp_SigBit ) )
        while( imsg = (struct IntuiMessage *)GetMsg( win->UserPort ) )
        {
          if( imsg->Class == CLOSEWINDOW )
            done = TRUE;
          ReplyMsg( (struct Message *)imsg );
        }
      if( ( signals & ( 1 << timerport->mp_SigBit ) ) && !done )
      {
        while( GetMsg( timerport ) ); /* Timer Port 'leerlesen' */
        addrequest( gettime() );
        printtime();
      }
    } while( !done );
  }
  cleanup();
}
