//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / SSCOP protocol
//
//File: sscopstate10.cpp
//
//Version: $Revision: 1.33 $
//
//State: $State: Exp $
//
//Date: $Date: 1999/03/11 18:53:55 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications and Multimedia
//
//Author:
//      Juhana Räsänen
//
//Description:
//      See corresponding header file
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//
//Licence:
//
//
//History: 
//

#include <assert.h>
#include "sscopstate10.h"
#include "sscoppdu.h"
#include "sscopprotocol.h"
#include "sscopinternals.h"
#include "iface/aaif/aadownprimitives.h"
#include "pf/frame.h"
#include "pf/timer.h"
#include "pf/debug.h"
#include "pf/error.h"

#undef debugUser
#define debugUser(x)

#ifdef __SSCOP_TESTING__
#endif
#define USEPOLL 1

sscopDataTransferReady *sscopDataTransferReady :: _only = 0;

sscopDataTransferReady *sscopDataTransferReady :: instance(void)
{
    if (_only == 0)
    {
        _only = new sscopDataTransferReady;
        assert(_only != 0);
    }
    return _only;
}


sscopDataTransferReady :: sscopDataTransferReady(void)
    : sscopState()
{
    return;
}


sscopDataTransferReady :: ~sscopDataTransferReady(void)
{
    _only = 0;
    return;
}


//
// Functions: AA primitive input methods
//
// Description:
//     These methods define actions in SSCOP state 2 for incoming
//     AA-signals from the above layer (UNI SSCF or NNI SSCF for
//     the time being)
//

void sscopDataTransferReady :: aaRELEASEreqAct(aaRELEASEreq *messenger_,
                                               pfProtocol *protocol_) const
{
    debugUser("sscopDataTransferReady::aaRELEASEreqAct");
    sscopProtocol *sscop = dynamic_cast<sscopProtocol *>(protocol_);
    THROW_IF_DYNAMIC_CAST_FAILED(sscop);
    sscop->resetDataTransferTimers();
    sscop->_VT_CC = 1;
    sscop->sendENDpdu(messenger_->getSSCOP_UU(), SSCOP_RELEASE_USER);
    sscop->prepareRetrieval();
    sscop->_timerCC.start();
    sscop->changeToOutgoingDisconnectionPendingState();
    return;
}

void sscopDataTransferReady :: aaDATAreqAct(aaDATAreq *messenger_,
                                            pfProtocol *protocol_) const
{
    debugUser("sscopDataTransferReady::aaDATAreqAct");
    sscopProtocol *sscop = dynamic_cast<sscopProtocol *>(protocol_);
    THROW_IF_DYNAMIC_CAST_FAILED(sscop);
    sscop->_transmissionQueue.push_back(messenger_->getMessageUnit());
    sscop->createSDpduQueuedUp();
    return;
}

void sscopDataTransferReady :: aaRESYNCreqAct(aaRESYNCreq *messenger_,
                                              pfProtocol *protocol_) const
{
    debugUser("sscopDataTransferReady::aaRESYNCreqAct");
    sscopProtocol *sscop = dynamic_cast<sscopProtocol *>(protocol_);
    THROW_IF_DYNAMIC_CAST_FAILED(sscop);
    sscop->resetDataTransferTimers();
    sscop->_VT_CC = 1;
    sscop->_VT_SQ++;
    sscop->initializeVR_MR();
    sscop->sendRSpdu(messenger_->getSSCOP_UU());
    sscop->releaseBuffers();
    sscop->_timerCC.start();
    sscop->changeToOutgoingResynchronizationPendingState();
    return;
}


//
// Functions: SSCOP PDU input methods
//
// Description:
//     Actions in SSCOP state 10 for received PDUs
//

void sscopDataTransferReady :: sscopBGNpduAct(sscopBGN_PDU *messenger_,
                                              sscopProtocol *protocol_) const
{
    debugUser("sscopDataTransferReady::sscopBGNpduAct");
    if (protocol_->detectRetransmission(messenger_->getN_SQ()) != 0)
    {
        debugUser("sscopDataTransferReady::sscopBGNpduAct::retransmission");
        protocol_->_timerNO_RESPONSE.start();
        protocol_->sendBGAKpdu(protocol_->_lastBGAKsscop_uu);
    }
    else
    {
        debugUser("sscopDataTransferReady::sscopBGNpduAct::new bgn");
        protocol_->resetDataTransferTimers();
        protocol_->_VT_MS = messenger_->getN_MR();
        pfFrame sscop_uu;
        protocol_->sendAaRELEASEind(sscop_uu, SSCOP_RELEASE_USER);
        protocol_->sendAaESTABLISHind(messenger_->getSSCOP_UU());
        protocol_->prepareRetrieval();
        protocol_->changeToIncomingConnectionPendingState();
    }
    return;
}

void sscopDataTransferReady :: sscopBGREJpduAct(
    sscopBGREJ_PDU *,
    sscopProtocol *protocol_) const
{
    debugUser("sscopDataTransferReady::sscopBGREJpduAct");
    protocol_->resetDataTransferTimers();
    protocol_->sendErrorReleaseEND(SSCOP_ERROR_D, 0, 1);
    protocol_->prepareRetrieval();
    protocol_->changeToIdleState();
    return;
}

void sscopDataTransferReady :: sscopENDpduAct(
    sscopEND_PDU *messenger_,
    sscopProtocol *protocol_) const
{
    debugUser("sscopDataTransferReady::sscopENDpduAct");
    protocol_->resetDataTransferTimers();
    protocol_->sendENDAKpdu();
    protocol_->sendAaRELEASEind(messenger_->getSSCOP_UU(),
                                messenger_->getSource());
    protocol_->prepareRetrieval();
    protocol_->changeToIdleState();
    return;
}

void sscopDataTransferReady :: sscopENDAKpduAct(
    sscopENDAK_PDU *,
    sscopProtocol *protocol_) const
{
    debugUser("sscopDataTransferReady::sscopENDAKpduAct");
    protocol_->resetDataTransferTimers();
    protocol_->sendErrorReleaseEND(SSCOP_ERROR_F, 0, 1);
    protocol_->prepareRetrieval();
    protocol_->changeToIdleState();
    return;
}

void sscopDataTransferReady :: sscopRSpduAct(
    sscopRS_PDU *messenger_,
    sscopProtocol *protocol_) const
{
    debugUser("sscopDataTransferReady::sscopRSpduAct");
    if (protocol_->detectRetransmission(messenger_->getN_SQ()) != 0)
    {
        debugUser("sscopDataTransferReady::sscopRSpduAct::retransmission");
        protocol_->_timerNO_RESPONSE.start();
        protocol_->sendRSAKpdu();
    }
    else
    {
        debugUser("sscopDataTransferReady::sscopRSpduAct::new rs");
        protocol_->resetDataTransferTimers();
        protocol_->_VT_MS = messenger_->getN_MR();
        protocol_->sendAaRESYNCind(messenger_->getSSCOP_UU());
        protocol_->prepareRetrieval();
        protocol_->changeToIncomingResynchronizationPendingState();
    }
    return;
}

void sscopDataTransferReady :: sscopERpduAct(
    sscopER_PDU *messenger_,
    sscopProtocol *protocol_) const
{
    debugUser("sscopDataTransferReady::sscopERpduAct");
    if (protocol_->detectRetransmission(messenger_->getN_SQ()) != 0)
    {
        debugUser("sscopDataTransferReady::sscopERpduAct::retransmission");
        protocol_->_timerNO_RESPONSE.start();
        protocol_->sendERAKpdu();
    }
    else
    {
        debugUser("sscopDataTransferReady::sscopERpduAct::new er");
        protocol_->resetDataTransferTimers();
        protocol_->_VT_MS = messenger_->getN_MR();
        protocol_->prepareRecovery();
        protocol_->deliverData();
        protocol_->sendAaRECOVERind();
        protocol_->changeToIncomingRecoveryPendingState();
    }
    return;
}

void sscopDataTransferReady :: sscopSDpduAct(
    sscopSD_PDU *messenger_,
    sscopProtocol *protocol_) const
{
    debugUser("sscopDataTransferReady::sscopSDpduAct");
    moduloInteger seq(SSCOP_SEQUENCE_MODULUS);
    seq = messenger_->getN_S();
    if (moduloInteger::compareWithBase(seq,
                                       protocol_->_VR_MR,
                                       protocol_->_VR_R) < 0)
    {
        debugUser("sscopDataTransferReady::sscopSDpduAct::1");
        if (seq == protocol_->_VR_R)
        {
            debugUser("sscopDataTransferReady::sscopSDpduAct::2");
            if (seq == protocol_->_VR_H)
            {
                debugUser("sscopDataTransferReady::sscopSDpduAct::3");
                protocol_->sendAaDATAind(messenger_->getInformation(),
                                         seq.getValue());
                protocol_->_VR_R = seq + 1;
                protocol_->_VR_H = seq + 1;
                protocol_->_VR_MR++;
            }
            else
            {
                debugUser("sscopDataTransferReady::sscopSDpduAct::4");
                protocol_->sendAaDATAind(messenger_->getInformation(),
                                         seq.getValue());
                protocol_->_VR_R++;
                protocol_->_VR_MR++;
                sscopProtocol::pduMapIterator iter;
                while ((iter = protocol_->
                        _receiverBuffer.find(protocol_->_VR_R.getValue())) !=
                       protocol_->_receiverBuffer.end())
                {
                    debugUser("sscopDataTransferReady::sscopSDpduAct::5");
                    sscopSD_PDU *msg = (*iter).second;
                    protocol_->sendAaDATAind(msg->getInformation(),
                                             seq.getValue());
                    protocol_->_VR_R++;
                    protocol_->_VR_MR++;
                    protocol_->_receiverBuffer.erase(iter);
                    delete msg;
                }
            }
        }
        else if (protocol_->receiverBufferIsFull() == 0)
        {
            debugUser("sscopDataTransferReady::sscopSDpduAct::6");
            if (seq == protocol_->_VR_H)
            {
                debugUser("sscopDataTransferReady::sscopSDpduAct::7");
                debugUser("Normal action");
                protocol_->insertIntoReceiverBuffer(messenger_);
                protocol_->_VR_H++;
            }
            else if (moduloInteger::compareWithBase(protocol_->_VR_H,
                                                    seq,
                                                    protocol_->_VR_R) < 0)
            {
                debugUser("sscopDataTransferReady::sscopSDpduAct::8");
                debugUser("Questionable1");
                protocol_->insertIntoReceiverBuffer(messenger_);
                protocol_->sendUSTATpdu(protocol_->_VR_H.getValue(),
                                        seq.getValue());
                protocol_->_VR_H = seq + 1;
            }
            else if (protocol_->_receiverBuffer.find(seq.getValue()) !=
                protocol_->_receiverBuffer.end())
            {
                debugUser("sscopDataTransferReady::sscopSDpduAct::9");
                debugUser("Questionable2");
                sscopSDLprocedureD(protocol_, SSCOP_ERROR_Q);
            }
            else
            {
                debugUser("sscopDataTransferReady::sscopSDpduAct::10");
                debugUser("Questionable3");
                protocol_->insertIntoReceiverBuffer(messenger_);
            }
        }
    }
    else if (moduloInteger::compareWithBase(protocol_->_VR_H,
                                            protocol_->_VR_MR,
                                            protocol_->_VR_R) < 0)
    {
        debugUser("sscopDataTransferReady::sscopSDpduAct::11");
        protocol_->sendUSTATpdu(protocol_->_VR_H.getValue(),
                                protocol_->_VR_MR.getValue());
        protocol_->_VR_H = protocol_->_VR_MR;
    }
    return;
}

void sscopDataTransferReady :: sscopPOLLpduAct(
    sscopPOLL_PDU *messenger_,
    sscopProtocol *protocol_) const
{
    debugUser("sscopDataTransferReady::sscopPOLLpduAct");
    moduloInteger n_s(SSCOP_SEQUENCE_MODULUS);
    n_s = messenger_->getN_S();
    if (moduloInteger::compareWithBase(protocol_->_VR_H,
                                       n_s,
                                       protocol_->_VR_R) < 0)
    {
        debugUser("sscopDataTransferReady::sscopPOLLpduAct::1");
        sscopSDLprocedureD(protocol_, SSCOP_ERROR_Q);
        return;
    }

    if (moduloInteger::compareWithBase(protocol_->_VR_MR,
                                       n_s,
                                       protocol_->_VR_R) < 0)
    {
        debugUser("sscopDataTransferReady::sscopPOLLpduAct::2");
        protocol_->_VR_H = protocol_->_VR_MR;
    }
    else
    {
        debugUser("sscopDataTransferReady::sscopPOLLpduAct::3");
        protocol_->_VR_H = n_s;
    }
    debugUser("sscopDataTransferReady::sscopPOLLpduAct::4");
    pfUlong listLength = 0;
    moduloInteger i(SSCOP_SEQUENCE_MODULUS);
    i = protocol_->_VR_R;
    pfFrame list;
    while (1)
    {
        debugUser("sscopDataTransferReady::sscopPOLLpduAct::5");
        if (i == protocol_->_VR_H)
        {
            debugUser("sscopDataTransferReady::sscopPOLLpduAct::6");
            protocol_->sendSTATpdu(list, messenger_->getN_PS());
            return;
        }
        while (1)
        {
            debugUser("sscopDataTransferReady::sscopPOLLpduAct::7");
            if (moduloInteger::compareWithBase(i,
                                               protocol_->_VR_H,
                                               protocol_->_VR_R) >= 0)
            {
                debugUser("sscopDataTransferReady::sscopPOLLpduAct::8");
                list.putLast(0);
                list.putLast24bit(i.getValue());
                protocol_->sendSTATpdu(list, messenger_->getN_PS());
                return;
            }
            if (protocol_->_receiverBuffer.find(i.getValue()) ==
                protocol_->_receiverBuffer.end())
            {
                debugUser("sscopDataTransferReady::sscopPOLLpduAct::9");
                break;
            }
            i++;
        }

        debugUser("sscopDataTransferReady::sscopPOLLpduAct::10");
        list.putLast(0);
        list.putLast24bit(i.getValue());
        listLength++;
        if (listLength >= protocol_->_maxSTAT)
        {
            debugUser("sscopDataTransferReady::sscopPOLLpduAct::11");
            protocol_->sendSTATpdu(list, messenger_->getN_PS());
            list.clear();
            list.putLast(0);
            list.putLast24bit(i.getValue());
            listLength = 1;
        }
        do
        {
            debugUser("sscopDataTransferReady::sscopPOLLpduAct::12");
            i++;
        } while ((moduloInteger::compareWithBase(i,
                                                 protocol_->_VR_H,
                                                 protocol_->_VR_R) < 0) &&
                 (protocol_->_receiverBuffer.find(i.getValue()) ==
                  protocol_->_receiverBuffer.end()));

        list.putLast(0);
        list.putLast24bit(i.getValue());
        listLength++;
    }
    return;
}

void sscopDataTransferReady :: sscopSTATpduAct(
    sscopSTAT_PDU *messenger_,
    sscopProtocol *protocol_) const
{
    debugUser("sscopDataTransferReady::sscopSTATpduAct");
    moduloInteger n_ps(SSCOP_SEQUENCE_MODULUS);
    moduloInteger n_r(SSCOP_SEQUENCE_MODULUS);
    n_ps = messenger_->getN_PS();
    n_r = messenger_->getN_R();

    if (!((moduloInteger::compareWithBase(protocol_->_VT_PA,
                                          n_ps,
                                          protocol_->_VT_PA) <= 0) &&
          (moduloInteger::compareWithBase(n_ps,
                                          protocol_->_VT_PS,
                                          protocol_->_VT_PA) <= 0)))
    {
        debugUser("sscopDataTransferReady::sscopSTATpduAct::1");
        sscopSDLprocedureD(protocol_, SSCOP_ERROR_R);
        return;
    }

    if (!((moduloInteger::compareWithBase(protocol_->_VT_A,
                                          n_r,
                                          protocol_->_VT_A) <= 0) &&
          (moduloInteger::compareWithBase(n_r,
                                          protocol_->_VT_S,
                                          protocol_->_VT_A) <= 0)))
    {
        debugUser("sscopDataTransferReady::sscopSTATpduAct::2");
        sscopSDLprocedureD(protocol_, SSCOP_ERROR_S);
        return;
    }

    sscopSD_PDU *msg = 0;
    while (protocol_->_VT_A != n_r)
    {
        debugUser("sscopDataTransferReady::sscopSTATpduAct::3");
        sscopProtocol::pduMapIterator iter =
            protocol_->_transmissionBuffer.find(protocol_->_VT_A.getValue());
        msg = (*iter).second;
        protocol_->_transmissionBuffer.erase(iter);
        delete msg;
        protocol_->_VT_A++;
    }
        
    protocol_->_VT_PA = n_ps;
    protocol_->_VT_MS = messenger_->getN_MR();
    pfUlong i = messenger_->getNItems();
    pfUlong count = 0;

    if (i <= 1)
    {
        debugUser("sscopDataTransferReady::sscopSTATpduAct::4");
        sscopSDLprocedureL(protocol_);
        return;
    }

    moduloInteger seq1(SSCOP_SEQUENCE_MODULUS);
    moduloInteger seq2(SSCOP_SEQUENCE_MODULUS);
    seq1 = messenger_->getNextListElement();
    i--;

    if (moduloInteger::compareWithBase(seq1,
                                       protocol_->_VT_S,
                                       protocol_->_VT_A) >= 0)
    {
        debugUser("sscopDataTransferReady::sscopSTATpduAct::5");
        sscopSDLprocedureD(protocol_, SSCOP_ERROR_S);
        return;
    }

    do
    {
        debugUser("sscopDataTransferReady::sscopSTATpduAct::6");
        seq2 = messenger_->getNextListElement();
        i--;
        if (!((moduloInteger::compareWithBase(seq1,
                                              seq2,
                                              protocol_->_VT_A) < 0) &&
              (moduloInteger::compareWithBase(seq2,
                                              protocol_->_VT_S,
                                              protocol_->_VT_A) <= 0)))
        {
            sscopSDLprocedureD(protocol_, SSCOP_ERROR_S);
            return;
        }
        do
        {
            debugUser("sscopDataTransferReady::sscopSTATpduAct::7");
            sscopProtocol::pduMapIterator iter =
                protocol_->_transmissionBuffer.find(seq1.getValue());
            if (iter == protocol_->_transmissionBuffer.end())
            {
                debugUser("sscopDataTransferReady::sscopSTATpduAct::8");
                sscopSDLprocedureD(protocol_, SSCOP_ERROR_S);
                return;
            }
            msg = (*iter).second;
            moduloInteger storedN_PS(SSCOP_SEQUENCE_MODULUS);
            storedN_PS = msg->getN_PS();

            if ((moduloInteger::compareWithBase(storedN_PS,
                                                n_ps,
                                                protocol_->_VT_PA) < 0) &&
                (moduloInteger::compareWithBase(n_ps,
                                                protocol_->_VT_PS,
                                                protocol_->_VT_PA) <= 0) &&
                (protocol_->_retransmissionQueue.find(seq1.getValue()) ==
                 protocol_->_retransmissionQueue.end()))
            {
                debugUser("sscopDataTransferReady::sscopSTATpduAct::9");
                protocol_->insertIntoRetransmissionQueue(msg);
                count++;
                protocol_->createSDpduQueuedUp();
            }
            seq1++;
        } while (seq1 != seq2);

        if (i > 0)
        {
            debugUser("sscopDataTransferReady::sscopSTATpduAct::10");
            seq2 = messenger_->getNextListElement();
            i--;
            if (!((moduloInteger::compareWithBase(seq1,
                                                  seq2,
                                                  protocol_->_VT_A) < 0) &&
                  (moduloInteger::compareWithBase(seq2,
                                                  protocol_->_VT_S,
                                                  protocol_->_VT_A) <= 0)))
            {
                debugUser("sscopDataTransferReady::sscopSTATpduAct::11");
                sscopSDLprocedureD(protocol_, SSCOP_ERROR_S);
                return;
            }
            do
            {
                debugUser("sscopDataTransferReady::sscopSTATpduAct::12");
                if (protocol_->_clearBuffers != 0)
                {
                    debugUser("sscopDataTransferReady::sscopSTATpduAct::13");
                    sscopProtocol::pduMapIterator iter =
                        protocol_->_transmissionBuffer.find(seq1.getValue());
                    msg = (*iter).second;
                    protocol_->_transmissionBuffer.erase(iter);
                    delete msg;
                }
                seq1++;
            } while (seq1 != seq2);
        }
    } while (i > 0);
    protocol_->sendMaaERRORind(SSCOP_ERROR_V, count);
    sscopSDLprocedureL(protocol_);
    return;
}

void sscopDataTransferReady :: sscopUSTATpduAct(
    sscopUSTAT_PDU *messenger_,
    sscopProtocol *protocol_) const
{
    debugUser("sscopDataTransferReady::sscopUSTATpduAct");
    moduloInteger n_r(SSCOP_SEQUENCE_MODULUS);
    n_r = messenger_->getN_R();
    if (!((moduloInteger::compareWithBase(protocol_->_VT_A,
                                          n_r,
                                          protocol_->_VT_A) <= 0) &&
          (moduloInteger::compareWithBase(n_r,
                                          protocol_->_VT_S,
                                          protocol_->_VT_A) < 0)))
    {
        debugUser("sscopDataTransferReady::sscopUSTATpduAct::1");
        sscopSDLprocedureD(protocol_, SSCOP_ERROR_T);
        return;
    }

    sscopSD_PDU *msg = 0;
    while (protocol_->_VT_A != n_r)
    {
        debugUser("sscopDataTransferReady::sscopUSTATpduAct::2");
        sscopProtocol::pduMapIterator iter =
            protocol_->_transmissionBuffer.find(protocol_->_VT_A.getValue());
        msg = (*iter).second;
        protocol_->_transmissionBuffer.erase(iter);
        delete msg;
        protocol_->_VT_A++;
    }

    debugUser("sscopDataTransferReady::sscopUSTATpduAct::3");
    protocol_->_VT_MS = messenger_->getN_MR();
    moduloInteger seq1(SSCOP_SEQUENCE_MODULUS);
    moduloInteger seq2(SSCOP_SEQUENCE_MODULUS);
    seq1 = messenger_->getListElement1();
    seq2 = messenger_->getListElement2();

    if (!((moduloInteger::compareWithBase(protocol_->_VT_A,
                                          seq1,
                                          protocol_->_VT_A) <= 0) &&
        (moduloInteger::compareWithBase(seq1,
                                        seq2,
                                        protocol_->_VT_A) < 0) &&
        (moduloInteger::compareWithBase(seq2,
                                        protocol_->_VT_S,
                                        protocol_->_VT_A) < 0)))
    {
        debugUser("sscopDataTransferReady::sscopUSTATpduAct::4");
        sscopSDLprocedureD(protocol_, SSCOP_ERROR_T);
        return;
    }

    pfUlong Count = 0;

    do
    {
        debugUser("sscopDataTransferReady::sscopUSTATpduAct::5");
        sscopProtocol::pduMapIterator iter =
            protocol_->_transmissionBuffer.find(seq1.getValue());
        if (iter == protocol_->_transmissionBuffer.end())
        {
            sscopSDLprocedureD(protocol_, SSCOP_ERROR_T);
            return;
        }
        protocol_->insertIntoRetransmissionQueue((*iter).second);
        protocol_->createSDpduQueuedUp();
        seq1++;
        Count++;
    } while (seq1 != seq2);
    protocol_->sendMaaERRORind(SSCOP_ERROR_V, Count);
    return;
}


//
// Functions: Timeout input methods
//
// Description:
//     Actions in SSCOP state 2 for timer timeouts
//

void sscopDataTransferReady :: sscopPOLLtimeoutAct(
    sscopProtocol *protocol_) const
{
    // sscopState::sscopPOLLtimeoutAct();
    protocol_->_VT_PS++;
#if USEPOLL
    debugUser("sscopPOLLtimeoutAct");
    protocol_->sendPOLLpdu();
#else
    debugUser("sscopPOLLtimeoutAct _NOT_ sending POLL");
#endif
    protocol_->_VT_PD = 0;
    protocol_->setPOLLtimer();
    return;
}

void sscopDataTransferReady :: sscopKEEPALIVEtimeoutAct(
    sscopProtocol *protocol_) const
{
    protocol_->_VT_PS++;
#if USEPOLL
    debugUser("sscopKEEPALIVEtimeoutAct");
    protocol_->sendPOLLpdu();
#else
    debugUser("sscopKEEPALIVEtimeoutAct _NOT_ sending POLL");
#endif
    protocol_->_VT_PD = 0;
    protocol_->setPOLLtimer();
    return;
}

void sscopDataTransferReady :: sscopNORESPONSEtimeoutAct(
    sscopProtocol *protocol_) const
{
    protocol_->resetDataTransferTimers();
    protocol_->sendErrorReleaseEND(SSCOP_ERROR_P, 0, 1, 1);
    protocol_->prepareRetrieval();
    protocol_->changeToIdleState();
    return;
}

void sscopDataTransferReady :: sscopIDLEtimeoutAct(
    sscopProtocol *protocol_) const
{
    protocol_->_timerNO_RESPONSE.start();
    protocol_->_VT_PS++;
#if USEPOLL
    debugUser("sscopIDLEimeoutAct");
    protocol_->sendPOLLpdu();
#else
    debugUser("sscopIDLEimeoutAct _NOT_ sending POLL");
#endif
    protocol_->_VT_PD = 0;
    protocol_->setPOLLtimer();
    return;
}


//
// Function: sscopState :: sscopSDpduQueuedUpAct
//
// Description:
//     Action for internal SSCOP event "SD PDU Queued Up", that sends a
//     PDU in transmission or retransmission queue to the peer protocol
//

void sscopDataTransferReady :: sscopSDpduQueuedUpAct(
    sscopProtocol *protocol_) const
{
    if ((protocol_->lowerLayerIsBusy() == 0) &&
        ((protocol_->_retransmissionQueue.empty() == 0) ||
         (moduloInteger::compareWithBase(protocol_->_VT_S,
                                         protocol_->_VT_MS,
                                         protocol_->_VT_A) < 0) ||
         (protocol_->_timerIDLE.isActive() != 0)))
    {
        if (protocol_->_retransmissionQueue.empty() == 0)
        {
            sscopProtocol::pduMapIterator iter =
                protocol_->_retransmissionQueue.begin();
            sscopSD_PDU *messenger = (*iter).second;
            pfFrame frame = messenger->getInformation();
            protocol_->sendSDpdu(frame, messenger->getN_S());
            messenger->setN_PS(protocol_->_VT_PS.getValue());
            protocol_->_retransmissionQueue.erase(iter);
            sscopSDLprocedureB(protocol_);
        }
        else if (protocol_->_transmissionQueue.empty() == 0)
        {
            if (moduloInteger::compareWithBase(protocol_->_VT_S,
                                               protocol_->_VT_MS,
                                               protocol_->_VT_A) < 0)
            {
                pfFrame frame = protocol_->_transmissionQueue.front();
                protocol_->_transmissionQueue.pop_front();
                protocol_->sendSDpdu(frame, protocol_->_VT_S.getValue());
                sscopSD_PDU *messenger = new sscopSD_PDU;
                messenger->setInformation(frame);
                messenger->setSequenceNumber(protocol_->_VT_S.getValue());
                messenger->setN_PS(protocol_->_VT_PS.getValue());
                protocol_->insertIntoTransmissionBuffer(messenger);
                protocol_->_VT_S++;
                sscopSDLprocedureB(protocol_);
            }
            else
            {
                protocol_->createSDpduQueuedUp();
                protocol_->_timerIDLE.stop();
                protocol_->_timerNO_RESPONSE.start();
                sscopSDLprocedureA(protocol_);
            }
        }
    }
    else
    {
        protocol_->createSDpduQueuedUp();
    }
    return;
}


//
// Functions: SDL procedures
//
// Description:
//     These implement some SSCOP Q.2110 SDL procedures of the state 10
//     (procedures A, B, D and L)
//

void sscopDataTransferReady :: sscopSDLprocedureA(
    sscopProtocol *protocol_) const
{
    protocol_->_VT_PS++;
#if USEPOLL
    debugUser("sscopSDLprocedureA");
    protocol_->sendPOLLpdu();
#else
    debugUser("sscopSDLprocedureA _NOT_ sending POLL");
#endif
    protocol_->_VT_PD = 0;
    protocol_->_timerPOLL.start();
    return;
}


void sscopDataTransferReady :: sscopSDLprocedureB(
    sscopProtocol *protocol_) const
{
    protocol_->_VT_PD++;
    if (protocol_->_timerPOLL.isActive() != 0)
    {
        if (protocol_->_VT_PD >= protocol_->_maxPD)
        {
            sscopSDLprocedureA(protocol_);
        }
    }
    else
    {
        if (protocol_->_timerIDLE.isActive() != 0)
        {
            protocol_->_timerIDLE.stop();
            protocol_->_timerNO_RESPONSE.start();
        }
        else
        {
            protocol_->_timerKEEP_ALIVE.stop();
        }
        if (protocol_->_VT_PD >= protocol_->_maxPD)
        {
            sscopSDLprocedureA(protocol_);
        }
        else
        {
            protocol_->_timerPOLL.start();
        }
    }
    return;
}


void sscopDataTransferReady :: sscopSDLprocedureD(
    sscopProtocol *protocol_,
    sscopError error_) const
{
    protocol_->resetDataTransferTimers();
    protocol_->sendMaaERRORind(error_);
    protocol_->_VT_CC = 1;
    protocol_->_VT_SQ++;
    protocol_->initializeVR_MR();
    protocol_->sendERpdu();
    protocol_->prepareRecovery();
    protocol_->_timerCC.start();
    protocol_->changeToOutgoingRecoveryPendingState();
    return;
}


void sscopDataTransferReady :: sscopSDLprocedureL(
    sscopProtocol *protocol_) const
{
    if (moduloInteger::compareWithBase(protocol_->_VT_S,
                                       protocol_->_VT_MS,
                                       protocol_->_VT_A) < 0)
    {
        if (protocol_->_credit == 0)
        {
            protocol_->_credit = 1;
            protocol_->sendMaaERRORind(SSCOP_ERROR_X);
        }
    }
    else
    {
        if (protocol_->_credit != 0)
        {
            protocol_->_credit = 0;
            protocol_->sendMaaERRORind(SSCOP_ERROR_W);
        }
    }
    if (protocol_->_timerPOLL.isActive() != 0)
    {
        protocol_->_timerNO_RESPONSE.start();
    }
    else if (protocol_->_timerIDLE.isActive() == 0)
    {
        protocol_->_timerKEEP_ALIVE.stop();
        protocol_->_timerNO_RESPONSE.stop();
        protocol_->_timerIDLE.start();
    }
    return;
}
