//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// UserRTX.NET satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;
using System.Threading;

#if !WASM
namespace user_rtx { using u = user_rtx;
#else
namespace user_rtx.wasm { using u = user_rtx.wasm;
#endif

static partial class beeper {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static readonly object
   SyncRoot             = new object(),
   InitializationLocker = new object(),
   PlayStartLocker      = new object(),
   ThreadActivityLocker = new object(),
   PlaybackLocker       = new object(),
   PlayStopSignalLocker = new object(),
   PlayStopControlLocker= new object();

[u.strict_result]
static Thread PlaybackThread =>
   IsInitialized ? _playbackThread.NN() : throw new InvalidOperationException();

[u.strict_result]
static AutoResetEvent PlayStartedEvent =>
   IsInitialized ? _playStartedEvent.NN() : throw new InvalidOperationException();

//==================================================================================================

public static (int Frequency,int Duration)[]? PrepareBeeps( u.BeepNote[] beeps )
{
   var values = new (int,int)[ beeps.Length ];
   lock ( SyncRoot )
      for ( int i=0; i<beeps.Length; i++ ) {
         double
            frequencyScale = beeps[ i ].Frequency,
            durationScale  = beeps[ i ].Duration;
         int
            frequency, duration;
         try {
            frequency = frequencyScale != 0 ?
               VerifyFrequency( (int)(BaseFrequency * frequencyScale) ) : 0;
            duration = VerifyDuration( (int)(BaseDuration * durationScale) );
         } catch {
            return null;
         }
         values[ i ] = ( frequency, duration );
      }
   return values;
}

//==================================================================================================

[u.win32]
static void PlayBeeps( (int Frequency,int Duration)[] beeps )
{
   for ( int i=0; i<beeps.Length && !_playStopFlag; i++ ) {
      if ( Monitor.TryEnter( PlayStopSignalLocker ) )
         Monitor.Exit( PlayStopSignalLocker );
      else
      {
         if (Monitor.TryEnter( PlayStopControlLocker ))
            Monitor.Exit( PlayStopControlLocker );
         else
            _playStopOwnerThread = _playStopInitiatorThread;
         break;
      }
      int
         frequency= beeps[ i ].Frequency,
         duration = beeps[ i ].Duration;
      if ( frequency == 0 ) {
         Thread.Sleep( duration );
         continue;
      }
      if ( !w32_core.Beep( (UInt32)frequency, (UInt32)duration ) )
         break;
   }
}

//--------------------------------------------------------------------------------------------------

static void PlaybackThreadRoutine()
{
   lock ( ThreadActivityLocker ) {
      Monitor.Pulse( ThreadActivityLocker );
      for (;;) {
         Monitor.Wait( ThreadActivityLocker );
         lock ( PlaybackLocker ) {
            _playStopFlag = false;
            _isPlaybackActive = true;
            PlayStartedEvent.Set();
            PlayBeeps( _playbackBeeps.NN() );
            _playStopInitiatorThread = null;
            PlaybackThread.Priority = _idlePriority;
         }
      }
   }
}

//==================================================================================================

static volatile int
   _baseFrequency = BaseFrequencyDef,
   _baseDuration  = BaseDurationDef;
static double
   _simpleBeepRelativeFrequency = SimpleBeepRelativeFrequencyDef,
   _simpleBeepRelativeDurationDef = SimpleBeepRelativeDurationDef;
static volatile ThreadPriority
   _playbackPriority = PlaybackPriorityDef,
   _idlePriority = IdlePriorityDef;

static volatile bool
   _isMute,
   _isInitialized,
   _isPlaybackActive,
   _playStopFlag;
static volatile Thread?
   _playbackThread,
   _playStopInitiatorThread,
   _playStopOwnerThread,
   _playInitiatorLastThread;

static AutoResetEvent?
   _playStartedEvent;
static (int Frequency,int Duration)[]?
   _playbackBeeps;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // beeper

} // user_rtx (.wasm)
