using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Exercise1
{
   // Klasa przechowujące wyświetlane informacje
   public class CountDownClockEventArgs : EventArgs
   {
      public readonly string message;
      public CountDownClockEventArgs( string message )
      {
         this.message = message;
      }
   }

   // Podmiot (wydawca). Klasa, do której inne klasy
   // zgłaszają subskrypcje. Udostępnia delegata TimeExpired
   // wyzwalanego po upływie określonego czasu
   public class CountDownClock
   {
      private DateTime startingTime;
      private DateTime targetTime;
      private string message;

      // Podaje komunikat przeznaczony do wyświetlenia i ile czasu
      // (godziny, minuty, sekundy) należy czekać
      public CountDownClock( string message, int hours, int mins, int seconds )
      {
         this.message = message;
         startingTime = DateTime.Now;
         TimeSpan duration = new TimeSpan( hours, mins, seconds );
         targetTime = startingTime + duration;
      }

      // Delegat
      public delegate void TimesUpEventHandler
      (
         object countDownClock,
         CountDownClockEventArgs alarmInformation
      );

      // Egzemplarz delegata
      public TimesUpEventHandler TimeExpired;

      // 10 razy na sekundę sprawdza, czy czas już upłynął.
      // Jeśli tak, a są obiekty nasłuchujące, należy przekazać komunikat
      public void Run()
      {
         for ( ; ; )
         {
            // Uśpienie na 1/10 sekundy
            Thread.Sleep( 100 ); // Milisekundy
             
            // Pobiera bieżący czas
            System.DateTime rightNow = System.DateTime.Now;

            if ( rightNow >= this.targetTime )
            {
               if ( TimeExpired != null )
               {
                  // Tworzy obiekt CountDownClockEventArgs przechowujący komunikat
                  CountDownClockEventArgs e = 
                     new CountDownClockEventArgs( this.message );
                  // Zgłoszenie zdarzenia
                  TimeExpired( this, e );
                  // Zatrzymuje zegar
                  break;
               } // Koniec „jeśli są zarejestrowane delegaty”
            }    // Koniec „jeśli czas upłynął”
         }       // Koniec nieskończonej pętli
      }          // Koniec Run
   }             // Koniec klasy

   // Obserwator
   public class CountDownTimerDisplay
   {
      CountDownClock.TimesUpEventHandler myHandler;

      public CountDownTimerDisplay(CountDownClock cdc)
      {
         myHandler = new CountDownClock.TimesUpEventHandler( TimeExpired );

         // Rejestruje metodę obsługi zdarzenia i uruchamia zegar
         cdc.TimeExpired += myHandler;
      }

      // Informuje użytkownika, że czas upłynął
	   public void TimeExpired( object theClock, CountDownClockEventArgs e )
      {
         Console.WriteLine( e.message );
      }
   }

   // Obserwator
   public class CountDownTimerLog
   {
      CountDownClock.TimesUpEventHandler myHandler;

      public CountDownTimerLog( CountDownClock cdc )
      {
         myHandler = new CountDownClock.TimesUpEventHandler( TimeExpired );

         // Rejestruje metodę obsługi zdarzenia i uruchamia zegar
         cdc.TimeExpired += myHandler;
      }
 
      // Informuje użytkownika, że czas upłynął
      public void TimeExpired( object theClock, CountDownClockEventArgs e )
      {
         Console.WriteLine( "logowanie " + e.message );
      }
   }

   public class Test
   {
      public static void Main()
      {
         Console.Write( "Podaj komunikat: " );
         string message = Console.ReadLine();

         // Uwaga: oczywiście należy utworzyć bardziej złożony interfejs
         // pozwalający ustawić użytkownikowi odpowiednią ilość czasu. Tu
         // program po prostu prosi użytkownika o podanie liczby sekund
         Console.Write( "Ile sekund?: " );
         int seconds = Convert.ToInt32( Console.ReadLine() );

         CountDownClock cdc = new CountDownClock( message, 0, 0, seconds );
         CountDownTimerDisplay display = new CountDownTimerDisplay( cdc );
         CountDownTimerLog logger = new CountDownTimerLog (cdc);
         cdc.Run();

      }
   }
}

