#include "msgqueue.h"

using namespace std;

// --------------------------------------------------------------------------
//
// This creates the Message queue thread,
//
MsgQueue::MsgQueue() : MyThreadX("MsqQueue"), fNextMsg(0), fNextPtr(0)
{
    RunThread();
}

// --------------------------------------------------------------------------
//
// The destructor terminates the thread.
//
MsgQueue::~MsgQueue()
{
    CancelThread();

    fMuxMsg.Lock();

    if (fNextPtr)
    {
        delete [] fNextPtr;
        fNextPtr = 0;
    }

    fMuxMsg.UnLock();
}

// --------------------------------------------------------------------------
//
// This is the function which must be overloaded.
// Here you process the messages. mp is a pointer which you can
// specify when posting the message.
//
// If a new messages is posted while the old one is not yet
// finished the fBreak flag is set. Please test this flag with
// Break() and try to finish (or stop) the current action as soon
// as possible. This makes sure, that before a new action is started
// the old action can be finished correctly by the user.
//
Int_t MsgQueue::Proc(int msg, void *mp)
{
    return 0;
}

int MsgQueue::Break() const
{
    return fNextMsg>0 || IsThreadCanceled();
}

// --------------------------------------------------------------------------
//
// This is the thread which handles the processing.
// As soon as a message is posted the fBreak flag is set (see PostMsg)
// And as soon as the current action is finished the new action is executed
// in this thread. This makes sure, that the calling program is not stalled.
//
Int_t MsgQueue::Thread()
{
    while (1)
    {
        Int_t msg = 0;
        char *ptr = 0;

        fMuxMsg.Lock();

        if (fNextMsg)
        {
            msg = fNextMsg;
            ptr = fNextPtr;

            fNextMsg = 0;
            fNextPtr = 0;
        }

        fMuxMsg.UnLock();

        if (ptr)
        {
            Proc(msg, ptr);
            delete [] ptr;
        }

        usleep(1);
        TThread::CancelPoint();
    }
    return 0;
}


// --------------------------------------------------------------------------
//
// Use this function to post a message.
// mp can be a pointer to a data structure. size should be the size of it.
// size bytes of this structure are copied and a pointer to the copy
// is forwarded to the Proc function.
//
void *MsgQueue::PostMsg(int msg, void *mp, int size)
{
    fMuxMsg.Lock();

    fNextMsg = msg;

    if (fNextPtr)
        delete [] fNextPtr;
    fNextPtr = new char[size];

    memcpy(fNextPtr, mp, size);

    fMuxMsg.UnLock();

    return 0;
}
