#include <intuition/screens.h>
#include <intuition/intuitionbase.h>
#include <intuition/intuition.h>
#include <graphics/modeid.h>
#include <dos/dostags.h>
#include <exec/libraries.h>
#include <libraries/asl.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>

extern struct IntuitionBase *IntuitionBase;

struct Library *TimerBase;

#define SCREENTITLE "David Göhlers visuelles Frequenz-Meßgerät © 1995"
#define MINHERTZ 10
#define MAXHERTZ 90
#define MINDELAY 4000
#define MAXDELAY 100000
#define PROCNAME "MessHzToggleColor"

const char version[] = "$VER: MessHz 1.0 © David Göhler (24.05.95)";

int hertz       = 600;      // Hertz mal 10
ULONG longdelay = 14166;    // wartezeit in µs - (500 + TimeDelay-Overhead)
ULONG MySignal;
struct ViewPort *vp = 0;

/*
 * GetAmiTime returns a LONG value. It's the system time in
 * milliseconds. If the value returned is -1, something went wrong.
 */

LONG GetAmiTime(void)
{
   struct timeval time = {0,0};      /* tv_secs & tv_micro */
   struct timerequest timereq = {0};
   LONG retcode = -1;

   if (!OpenDevice(TIMERNAME,UNIT_ECLOCK,(struct IORequest *)&timereq,0L))
   {  TimerBase = (struct Library *)timereq.tr_node.io_Device;

      GetSysTime(&time);

      retcode = (time.tv_secs)*1000000 + (time.tv_micro);
      CloseDevice((struct timerequest *)&timereq);
   }

   return retcode;
}

void HertzAus(struct Screen *s, struct Window *w)
{
   char textaus[30];

   Move(w->RPort, 20,s->BarHeight+20);
   sprintf(textaus,"%02ld,%1ld Hertz",hertz/10,hertz%10);
   Text(w->RPort,textaus, strlen(textaus));

   Move(w->RPort, 20,s->BarHeight+40);
   sprintf(textaus,"%02ld LongDelay",longdelay);
   Text(w->RPort,textaus, strlen(textaus));
}

#define LOOPCOUNT 40

int CheckTimeDelay()
{
  int i = LOOPCOUNT;
  ULONG million = 1000000;
  ULONG shortdelay = 500;
  ULONG bla;
  LONG messtime;

  messtime = GetAmiTime();
  while ((i--) && (!CheckSignal(MySignal)))
  {  bla = (10 * million / (shortdelay +  shortdelay + shortdelay));
     SetRGB4(vp,0,0,0,0);
     TimeDelay(UNIT_MICROHZ,0,shortdelay);
     SetRGB4(vp,0,10,10,10);
     TimeDelay(UNIT_MICROHZ,0,shortdelay);
  }
  return (GetAmiTime() - messtime - (LOOPCOUNT*shortdelay*2)) / LOOPCOUNT;
}

__geta4 void ToggleColor0(void)
{
  ULONG million = 1000000;
  ULONG shortdelay = 500; // 1/2000 Sekunde Schaltung
  ULONG messdelay;

  MySignal  = 1 << AllocSignal(-1L);
  messdelay = CheckTimeDelay();
  longdelay = (million-((hertz/10)*(messdelay+shortdelay))) / (hertz/10);

  while (!CheckSignal(MySignal))
  {  hertz = (10*million / (messdelay + shortdelay + longdelay));
     SetRGB4(vp,0,0,0,0);
     TimeDelay(UNIT_MICROHZ,0,shortdelay);
     SetRGB4(vp,0,10,10,10);
     TimeDelay(UNIT_MICROHZ,0,longdelay);
  }
}

struct TagItem ti[] = {
    {  ASLSM_InitialDisplayID, INVALID_ID },
    {  TAG_DONE, 0 }
};

int main(int argc, char *argv[])
{
   struct Screen *s = 0L;
   ULONG DisplayID = INVALID_ID;
   BOOL loopy;

   s = IntuitionBase->FirstScreen;
   while ((DisplayID = GetScreenMode(s,ti,0)) != INVALID_ID)
   {
      ti[0].ti_Data = DisplayID;
      loopy = TRUE;
      if ( s = OpenScreenTags(0L,SA_DisplayID, DisplayID, TAG_DONE))
      {
         struct Window *w = 0L;

         vp = &(s->ViewPort);
         if (w = OpenWindowTags(0L,
                WA_IDCMP,        IDCMP_RAWKEY,
                WA_CustomScreen, s,
                WA_ScreenTitle,  SCREENTITLE,
                WA_Flags,        WFLG_BORDERLESS | WFLG_BACKDROP |
                                 WFLG_ACTIVATE | WFLG_RMBTRAP,
                TAG_DONE)
            )
         {  struct IntuiMessage * imsg;
            struct Process *p;

            HertzAus(s,w);
            p = CreateNewProcTags(NP_Entry,    ToggleColor0,
                   NP_Priority, 50, // muß hoch sein
                   NP_Name, PROCNAME,
                   TAG_DONE
                  );
            HertzAus(s,w);
            while (loopy)
            {  Wait(1L << w->UserPort->mp_SigBit);
               while (imsg = GetMsg(w->UserPort))
               {  int key = -1;
                  static BOOL shift = FALSE;
                  static BOOL alt   = FALSE;

                  if (imsg->Class == IDCMP_RAWKEY)
                  {  key = imsg->Code; }
                  ReplyMsg(imsg);
                  if (key != -1)
                  {
                     switch (key) {
                       case 0x60:
                       case 0x61: shift = TRUE; break;
                       case 0xE0:
                       case 0xE1: shift = FALSE; break;
                       case 0x64:
                       case 0x65: alt = TRUE; break;
                       case 0xE4:
                       case 0xE5: alt = FALSE; break;
                       case 0x45: // ESC
                                  loopy = FALSE;
                                  while (imsg = GetMsg(w->UserPort))
                                  {  ReplyMsg(imsg); }
                                  break;
                       case 0x1B: // + Taste
                                  if (longdelay > MINDELAY)
                                  {  longdelay -= (!(alt+shift))+10*shift +100*alt;
                                  }
                                  break;
                       case 0x3A: // - Taste
                                  if (longdelay < MAXDELAY)
                                  {  longdelay += (!(alt+shift))+10*shift +100*alt;
                                  }
                                  break;
                       default:   break;
                     }
                     HertzAus(s,w);
                  }
               }
            }
            while (FindTask(PROCNAME))
            {  Signal(p,MySignal);
               Delay(10);
            }
            CloseWindow(w);
         }
         CloseScreen(s);
      }
      s = IntuitionBase->FirstScreen;
   }
   return (s == 0);
}
