// Copyright © 1998 by Jon Shemitz, all rights reserved.
// Permission is hereby granted to freely use, modify, and
// distribute this source code PROVIDED that all six lines of
// this copyright and contact notice are included without any
// changes. Questions? Comments? Offers of work?
// mailto:jon@midnightbeach.com - http://www.midnightbeach.com

#ifndef SynchedThreadsH
#define SynchedThreadsH

#include <stdexcept>


// Simple threads

typedef void (__closure *TThreadFunction)(void* Data);

class TSimpleThread : public TThread
    TSimpleThread( TThreadFunction _Action,
                   void* _Data = NULL, bool RunNow = True );
    void AbortThread();

    TThreadFunction ThreadFunction;
    void*           Data;

    virtual void __fastcall Execute() { ThreadFunction(Data); };

TSimpleThread* RunInThread( TThreadFunction Handler,
                            void* Data = NULL )
{ return new TSimpleThread(Handler, Data); };

// Wait threads (basic synchronization)

void MsgWaitForSingleObject(HANDLE Handle);

TProcessInformation SpawnProcess(char* Command);

class TWaitThread : public TSimpleThread
  typedef TSimpleThread inherited;
    TWaitThread( TThreadFunction _Action, void* _Data = NULL );
    void WaitFor()    throw (EAbort*) { Run(false); }
    void MsgWaitFor() throw (EAbort*) { Run(true);  }
    void AbortThread();

    bool* AbortFlag;
    void Run(bool MsgWait = true)
         throw (EAbort*);

void WaitForThread(TThreadFunction Handler, void* Data = NULL)
     throw (EAbort*)
{ (new TWaitThread(Handler, Data))->WaitFor(); };

void MsgWaitForThread( TWaitThread*& Thread,
                       TThreadFunction Handler, void* Data = NULL)
     throw (EAbort*);

// Stop/start threads

class EAbortedThread : public std::runtime_error
{ public: EAbortedThread(); };

class EThreadInUse : public std::logic_error
{ public: EThreadInUse(); };

class TStopStartThread : public TSimpleThread
    bool Waiting;

    virtual __fastcall ~TStopStartThread()
    { CloseHandle(Event); };

    void Run( TThreadFunction _Action, void* _Data = NULL,
              bool MsgWait = true)
         throw (EAbort*, EAbortedThread, EThreadInUse);
    void AbortThread();

    HANDLE Event;
    bool   Aborted;

    virtual void __fastcall Execute();