#include "sdolist.h"

#include "MLog.h"
#include "MLogManip.h"

#include "MTime.h"


ClassImp(PendingSDO);
ClassImp(PendingSDOList);

using namespace std;

#undef DEBUG

#ifdef DEBUG
#include <fstream>
static ofstream fout;
#endif

PendingSDOList::PendingSDOList()
{
#ifdef DEBUG
    fout.open("sdolist.txt", ios::app);
    fout.rdbuf()->pubsetbuf(0,0);
    fout << hex;
#endif

    fFirst = new PendingSDO;
    fLast  = fFirst;
}

PendingSDOList::~PendingSDOList()
{
    DelAll();
    delete fFirst;

#ifdef DEBUG
    fout.close();
#endif
}

void PendingSDOList::DelAll()
{
    if (fMux.Lock()==13)
        gLog << err << MTime(-1) << " -  PendingSDOList::DelAll - mutex is already locked by this thread" << endl;

#ifdef DEBUG
    fout << MTime(-1) << " - DelAll" << endl;
#endif

    PendingSDO *prev = fFirst;
    PendingSDO *sdo;

    do
    {
        sdo = prev->Next;
        delete prev;

    } while((prev=sdo));

    fFirst = new PendingSDO;
    fLast  = fFirst;

    if (fMux.UnLock()==13)
        gLog << err << MTime(-1) << " -  PendingSDOList::DelAll - tried to unlock mutex locked by other thread." << endl;
}

void PendingSDOList::Add(BYTE_t node, WORD_t idx, BYTE_t subidx)
{
    PendingSDO *sdo = fFirst;

    if (fMux.Lock()==13)
        gLog << err << MTime(-1) << " -  PendingSDOList::Add - mutex is already locked by this thread" << endl;

#ifdef DEBUG
    fout << MTime(-1) << " - Add " << idx << "/" << subidx << " @ " << node << endl;
#endif

    while ((sdo=sdo->Next))
        if (sdo->Node==node && sdo->Idx==idx && sdo->Subidx==subidx)
        {
            gLog << warn << MTime(-1) << " - SDO Node #" << dec << (int)node << ", 0x";
            gLog << hex << idx << "/" << (int)subidx;
            gLog << " still pending." << endl;
            break;
        }

    fLast->Next = new PendingSDO(node, idx, subidx);
    fLast = fLast->Next;
    if (fMux.UnLock()==13)
        gLog << err << MTime(-1) << " - PendingSDOList::Add - tried to unlock mutex locked by other thread." << endl;
}

void PendingSDOList::Del(BYTE_t node, WORD_t idx, BYTE_t subidx)
{
    PendingSDO *prev = fFirst;
    PendingSDO *sdo;

    if (fMux.Lock()==13)
        gLog << err << MTime(-1) << " -  PendingSDOList::Del - mutex is already locked by this thread" << endl;

#ifdef DEBUG
    fout << MTime(-1) << " - Del " << idx << "/" << subidx << " @ " << node << endl;
#endif

    while ((sdo=prev->Next))
    {
        if (sdo->Node!=node || sdo->Idx!=idx || sdo->Subidx!=subidx)
        {
            prev = sdo;
            continue;
        }

        prev->Next = sdo->Next;

        delete sdo;

        if (!prev->Next)
            fLast = prev;

        break;
    }
    if (fMux.UnLock()==13)
        gLog << err <<  MTime(-1) << " - PendingSDOList::Del - tried to unlock mutex locked by other thread." << endl;
}

int PendingSDOList::IsPending() const
{
    return fFirst->Next ? 1 : 0;
}

int PendingSDOList::IsPending(BYTE_t node)
{
    int rc = FALSE;
    PendingSDO *sdo = fFirst;

    if (fMux.Lock()==13)
        gLog << err << MTime(-1) << " - PendingSDOList::IsPending(byte) - mutex is already locked by this thread" << endl;
    while ((sdo=sdo->Next))
        if (sdo->Node==node)
        {
            rc = TRUE;
            break;
        }
    if (fMux.UnLock()==13)
        gLog << err << MTime(-1) << " - PendingSDOList::IsPending(byte) - tried to unlock mutex locked by other thread." << endl;

    return rc;
}

int PendingSDOList::IsPending(BYTE_t node, WORD_t idx, BYTE_t subidx)
{
    int rc = FALSE;
    PendingSDO *sdo = fFirst;

    if (fMux.Lock()==13)
        gLog << err <<  MTime(-1) << " - PendingSDOList::IsPending - mutex is already locked by this thread" << endl;
    while ((sdo=sdo->Next))
        if (sdo->Node==node && sdo->Idx==idx && sdo->Subidx==subidx)
        {
            rc = TRUE;
            break;
        }
    if (fMux.UnLock()==13)
        gLog << err <<  MTime(-1) << " - PendingSDOList::IsPending - tried to unlock mutex locked by other thread." << endl;

    return rc;
}
