//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / SSCOP protocol
//
//File: sscopprotocol.cpp
//
//Version: $Revision: 1.35 $
//
//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 "sscopprotocol.h"
#include "sscoptimeouts.h"
#include "sscopinternals.h"
#include "sscopstate1.h"
#include "sscopstate2.h"
#include "sscopstate3.h"
#include "sscopstate4.h"
#include "sscopstate5.h"
#include "sscopstate6.h"
#include "sscopstate7.h"
#include "sscopstate8.h"
#include "sscopstate9.h"
#include "sscopstate10.h"
#include "protocol/saal/saal.h"
#include "protocol/saal/saallink.h"
#include "iface/cpcsif/cpcsdownprimitives.h"
#include "iface/aaif/aaupprimitives.h"
#include "pf/state.h"
#include "pf/timer.h"
#include "pf/bytes.h"
#include "pf/debug.h"

//
// Function: sscopProtocol constructors
//
// Description:
//     Constructor to initialize state variables, protocol parameters,
//     buffers, timers and initial state.
//     NOTE: Copy constructor only copies protocol parameter values and
//           timer timeouts, otherwise it works exactly as the ordinary
//           constructor. That means that the new protocol is initialized
//           to initial state, but with copied parameter values.
//

sscopProtocol :: sscopProtocol(saalLink *manager_)
    : pfProtocol(),
      _maxSDUsize(NNI_SSCOP_MAX_SDU_SIZE),
      _maxUUsize(NNI_SSCOP_MAX_UU_SIZE),
      _maxCC(NNI_SSCOP_MAX_CC),
      _maxPD(NNI_SSCOP_MAX_PD),
      _maxSTAT(SSCOP_DEFAULT_MAX_STAT),
      _initialVR_MR(SSCOP_INITIAL_VR_MR),
      _clearBuffers(false),
      _credit(false),
      _VT_S(SSCOP_SEQUENCE_MODULUS),
      _VT_PS(SSCOP_SEQUENCE_MODULUS),
      _VT_A(SSCOP_SEQUENCE_MODULUS),
      _VT_PA(SSCOP_SEQUENCE_MODULUS),
      _VT_MS(SSCOP_SEQUENCE_MODULUS),
      _VT_PD(0),
      _VT_CC(0),
      _VT_SQ(SSCOP_CC_SEQUENCE_MODULUS),
      _VR_R(SSCOP_SEQUENCE_MODULUS),
      _VR_H(SSCOP_SEQUENCE_MODULUS),
      _VR_MR(SSCOP_SEQUENCE_MODULUS),
      _VR_SQ(SSCOP_CC_SEQUENCE_MODULUS),
      _timerCC(),
      _timerKEEP_ALIVE(),
      _timerNO_RESPONSE(),
      _timerPOLL(),
      _timerIDLE(), 
      _saveCCtimeout(NNI_SSCOP_TIMER_CC_TIMEOUT),
      _saveKEEP_ALIVEtimeout(NNI_SSCOP_TIMER_KEEP_ALIVE_TIMEOUT),
      _saveNO_RESPONSEtimeout(NNI_SSCOP_TIMER_NO_RESPONSE_TIMEOUT),
      _savePOLLtimeout(NNI_SSCOP_TIMER_POLL_TIMEOUT),
      _saveIDLEtimeout(NNI_SSCOP_TIMER_IDLE_TIMEOUT),
      _lastBGNframe(),
      _lastENDframe(),
      _lastRSframe(),
      _lastERframe(),
      _lastBGNsscop_uu(),
      _lastBGAKsscop_uu(),
      _lastBGREJsscop_uu(),
      _transmissionQueue(),
      _transmissionBuffer(),
      _retransmissionQueue(),
      _receiverBuffer(),
      _unassuredQueue(),
      _managementQueue(),
      _manager(manager_),
      _lowerLayerIsBusy(false),
      _powerUpRobustness(true)
{
    setAllInitialValues();
    changeToIdleState();
    return;
}


sscopProtocol :: sscopProtocol(const sscopProtocol &other_,
                               saalLink *manager_)
    : pfProtocol(),
      _maxSDUsize(other_._maxSDUsize),
      _maxUUsize(other_._maxUUsize),
      _maxCC(other_._maxCC),
      _maxPD(other_._maxPD),
      _maxSTAT(other_._maxSTAT),
      _initialVR_MR(other_._initialVR_MR),
      _clearBuffers(false),
      _credit(false),
      _VT_S(SSCOP_SEQUENCE_MODULUS),
      _VT_PS(SSCOP_SEQUENCE_MODULUS),
      _VT_A(SSCOP_SEQUENCE_MODULUS),
      _VT_PA(SSCOP_SEQUENCE_MODULUS),
      _VT_MS(SSCOP_SEQUENCE_MODULUS),
      _VT_PD(0),
      _VT_CC(0),
      _VT_SQ(SSCOP_CC_SEQUENCE_MODULUS),
      _VR_R(SSCOP_SEQUENCE_MODULUS),
      _VR_H(SSCOP_SEQUENCE_MODULUS),
      _VR_MR(SSCOP_SEQUENCE_MODULUS),
      _VR_SQ(SSCOP_CC_SEQUENCE_MODULUS),
      _timerCC(),
      _timerKEEP_ALIVE(),
      _timerNO_RESPONSE(),
      _timerPOLL(),
      _timerIDLE(),
      _saveCCtimeout(other_._saveCCtimeout),
      _saveKEEP_ALIVEtimeout(other_._saveKEEP_ALIVEtimeout),
      _saveNO_RESPONSEtimeout(other_._saveNO_RESPONSEtimeout),
      _savePOLLtimeout(other_._savePOLLtimeout),
      _saveIDLEtimeout(other_._saveIDLEtimeout),
      _lastBGNframe(),
      _lastENDframe(),
      _lastRSframe(),
      _lastERframe(),
      _lastBGNsscop_uu(),
      _lastBGAKsscop_uu(),
      _lastBGREJsscop_uu(),
      _transmissionQueue(),
      _transmissionBuffer(),
      _retransmissionQueue(),
      _receiverBuffer(),
      _unassuredQueue(),
      _managementQueue(),
      _manager(manager_),
      _lowerLayerIsBusy(other_._lowerLayerIsBusy),
      _powerUpRobustness(other_._powerUpRobustness)
{
    setAllInitialValues();
    changeToIdleState();
    return;
}


sscopProtocol :: ~sscopProtocol(void)
{
    return;
}

//
// Functions: Send methods for AA primitives (indications, confirms)
//
// Description:
//     These methods create new AA primitive messengers, set their
//     parameters to given and default values and send the primitive
//     to the upper layer on conduit side B.
//

void sscopProtocol :: sendAaESTABLISHind(const pfFrame &sscop_uu_)
{
    aaESTABLISHind *message = new aaESTABLISHind;
    message->setSSCOP_UU(sscop_uu_);
    toB(message);
    return;
}


void sscopProtocol :: sendAaESTABLISHconf(const pfFrame &sscop_uu_)
{
    aaESTABLISHconf *message = new aaESTABLISHconf;
    message->setSSCOP_UU(sscop_uu_);
    toB(message);
    return;
}


void sscopProtocol :: sendAaRELEASEind(
    const pfFrame &sscop_uu_,
    pfUlong source_)
{
    aaRELEASEind *message = new aaRELEASEind;
    message->setSSCOP_UU(sscop_uu_);
    message->setSource(source_);
    toB(message);
    return;
}


void sscopProtocol :: sendAaRELEASEconf(void)
{
    aaRELEASEconf *message = new aaRELEASEconf;
    toB(message);
    return;
}


void sscopProtocol :: sendAaDATAind(
    const pfFrame &data_,
    pfUlong sequenceNumber_)
{
    aaDATAind *message = new aaDATAind;
    message->setMessageUnit(data_);
    message->setSequenceNumber(sequenceNumber_);
    toB(message);
    return;
}


void sscopProtocol :: sendAaRESYNCind(const pfFrame &sscop_uu_)
{
    aaRESYNCind *message = new aaRESYNCind;
    message->setSSCOP_UU(sscop_uu_);
    toB(message);
    return;
}


void sscopProtocol :: sendAaRESYNCconf(void)
{
    aaRESYNCconf *message = new aaRESYNCconf;
    toB(message);
    return;
}


void sscopProtocol :: sendAaRECOVERind(void)
{
    aaRECOVERind *message = new aaRECOVERind;
    toB(message);
    return;
}


void sscopProtocol :: sendAaUNITDATAind(const pfFrame &data_)
{
    aaUNITDATAind *message = new aaUNITDATAind;
    message->setMessageUnit(data_);
    toB(message);
    return;
}


void sscopProtocol :: sendAaRETRIEVEind(const pfFrame &data_)
{
    aaRETRIEVEind *message = new aaRETRIEVEind;
    message->setMessageUnit(data_);
    toB(message);
    return;
}


void sscopProtocol :: sendAaRETRIEVE_COMPLETEind(void)
{
    aaRETRIEVE_COMPLETEind *message = new aaRETRIEVE_COMPLETEind;
    toB(message);
    return;
}


//
// Functions: Send methods for MAA primitives (indications)
//
// Description:
//     These methods create new MAA primitive messengers, set their
//     parameters to given and default values and send the primitive
//     to the layer management object (not yet implemented).
//


void sscopProtocol :: sendMaaERRORind(sscopError code_, pfUlong count_)
{
    _manager->maaERRORindAct(code_, count_);
    return;
}


void sscopProtocol :: sendMaaUNITDATAind(const pfFrame &frame_)
{
    _manager->maaUNITDATAindAct(frame_);
    return;
}


//
// Functions: Send (and resend) methods for SSCOP PDUs
//
// Description:
//     These methods encode PDU frames from given and default field
//     values and send the PDU frame to the peer protocol instance
//     using CPCS protocol on conduit side A. Some PDUs must be
//     saved and possibly re-sent, so resend methods have been
//     defined for those.
//

void sscopProtocol :: sendBGNpdu(pfFrame &frame_)
{
    _lastBGNsscop_uu = frame_;
    sscopBGN_PDU::encode(frame_, _VT_SQ.getValue(), _VR_MR.getValue());
    _lastBGNframe = frame_;
    debugUser("sendBGNpdu");
    sendCpcsUNITDATAreq(frame_);
    return;
}


void sscopProtocol :: resendLastBGNpdu(void)
{
    debugUser("resendLastBGNpdu");
    sendCpcsUNITDATAreq(_lastBGNframe);
    return;
}


void sscopProtocol :: sendBGAKpdu(pfFrame &frame_)
{
    _lastBGAKsscop_uu = frame_;
    sscopBGAK_PDU::encode(frame_, _VR_MR.getValue());
    debugUser("sendBGAKpdu");
    sendCpcsUNITDATAreq(frame_);
    return;
}


void sscopProtocol :: sendBGREJpdu(pfFrame &frame_)
{
    _lastBGAKsscop_uu = frame_;
    sscopBGREJ_PDU::encode(frame_);
    debugUser("sendBGREJpdu");
    sendCpcsUNITDATAreq(frame_);
    return;
}


void sscopProtocol :: sendENDpdu(pfFrame &frame_, pfUlong source_)
{
    sscopEND_PDU::encode(frame_, source_);
    _lastENDframe = frame_;
    debugUser("sendENDpdu");
    sendCpcsUNITDATAreq(frame_);
    return;
}


void sscopProtocol :: resendLastENDpdu(void)
{
    debugUser("resendLastENDpdu");
    sendCpcsUNITDATAreq(_lastENDframe);
    return;
}


void sscopProtocol :: sendENDAKpdu(void)
{
    pfFrame frame;
    sscopENDAK_PDU::encode(frame);
    debugUser("sendENDAKpdu");
    sendCpcsUNITDATAreq(frame);
    return;
}


void sscopProtocol :: sendRSpdu(pfFrame &frame_)
{
    sscopRS_PDU::encode(frame_, _VT_SQ.getValue(), _VR_MR.getValue());
    _lastRSframe = frame_;
    debugUser("sendRSpdu");
    sendCpcsUNITDATAreq(frame_);
    return;
}


void sscopProtocol :: resendLastRSpdu(void)
{
    debugUser("resendLastRSpdu");
    sendCpcsUNITDATAreq(_lastRSframe);
    return;
}


void sscopProtocol :: sendRSAKpdu(void)
{
    pfFrame frame;
    sscopRSAK_PDU::encode(frame, _VR_MR.getValue());
    debugUser("sendRSAKpdu");
    sendCpcsUNITDATAreq(frame);
    return;
}


void sscopProtocol :: sendERpdu(void)
{
    pfFrame frame;
    sscopER_PDU::encode(frame, _VT_SQ.getValue(), _VR_MR.getValue());
    _lastERframe = frame;
    debugUser("sendERpdu");
    sendCpcsUNITDATAreq(frame);
    return;
}


void sscopProtocol :: resendLastERpdu(void)
{
    debugUser("resendLastERpdu");
    sendCpcsUNITDATAreq(_lastERframe);
    return;
}


void sscopProtocol :: sendERAKpdu(void)
{
    pfFrame frame;
    sscopERAK_PDU::encode(frame, _VR_MR.getValue());
    debugUser("sendERAKpdu");
    sendCpcsUNITDATAreq(frame);
    return;
}


void sscopProtocol :: sendSDpdu(pfFrame &frame_, pfUlong sequenceNumber_)
{
    sscopSD_PDU::encode(frame_, sequenceNumber_);
    debugUser("sendSDpdu");
    sendCpcsUNITDATAreq(frame_);
    return;
}


void sscopProtocol :: sendPOLLpdu(void)
{
    pfFrame frame;
    sscopPOLL_PDU::encode(frame, _VT_PS.getValue(), _VT_S.getValue());
    debugUser("sendPOLLpdu");
    sendCpcsUNITDATAreq(frame);
    return;
}


void sscopProtocol :: sendSTATpdu(pfFrame &frame_, pfUlong N_PS_)
{
    sscopSTAT_PDU::encode(frame_, N_PS_, _VR_MR.getValue(), _VR_R.getValue());
    debugUser("sendSTATpdu");
    sendCpcsUNITDATAreq(frame_);
    return;
}


void sscopProtocol :: sendUSTATpdu(
    pfUlong listElement1_,
    pfUlong listElement2_)
{
    pfFrame frame;
    sscopUSTAT_PDU::encode(frame, listElement1_, listElement2_,
                           _VR_MR.getValue(), _VR_R.getValue());
    debugUser("sendUSTATpdu");
    sendCpcsUNITDATAreq(frame);
    return;
}


void sscopProtocol :: sendUDpdu(pfFrame &frame_)
{
    sscopUD_PDU::encode(frame_);
    debugUser("sendUDpdu");
    sendCpcsUNITDATAreq(frame_);
    return;
}


void sscopProtocol :: sendMDpdu(pfFrame &frame_)
{
    sscopMD_PDU::encode(frame_);
    debugUser("sendMDpdu");
    sendCpcsUNITDATAreq(frame_);
    return;
}


//
// Function: sscopProtocol :: createSDpduQueuedUp
//
// Description:
//     Create a "SD PDU Queued Up" internal event and put it to the
//     message queue of this protocol
//

void sscopProtocol :: createSDpduQueuedUp(void)
{
    sscopSDpduQueuedUp *messenger = new sscopSDpduQueuedUp;
    accept(messenger);
    return;
}


//
// Functions: Set methods for protocol parameters
//
// Description:
//     Set methods for protocol parameters that will be set from
//     outside of the SSCOP and its state machine (states are allowed
//     to modify context directly, so set methods for internal state
//     variables are not needed..
//

void sscopProtocol :: setMaxSDUsize(pfUlong SDUsize_)
{
    _maxSDUsize = SDUsize_;
    return;
}


void sscopProtocol :: setMaxUUsize(pfUlong UUsize_)
{
    _maxUUsize = UUsize_;
    return;
}


void sscopProtocol :: setMaxCC(pfUlong CC_)
{
    _maxCC = CC_;
    return;
}


void sscopProtocol :: setMaxPD(pfUlong PD_)
{
    _maxPD = PD_;
    return;
}


void sscopProtocol :: setInitialVR_MR(pfUlong windowSize_)
{
    _initialVR_MR = windowSize_;
    return;
}


void sscopProtocol :: setLowerLayerBusy(void)
{
    _lowerLayerIsBusy = true;
    return;
}


void sscopProtocol :: clearLowerLayerBusy(void)
{

//    if (_transmissionQueue.length > 0)
//    {
//        createSDpduQueuedUp();
//    }
    _lowerLayerIsBusy = false;
    return;
}

bool sscopProtocol :: lowerLayerIsBusy(void)
{
    return _lowerLayerIsBusy;
}

bool sscopProtocol :: isPowerUpRobustnessEnabled(void)
{
    return _powerUpRobustness;
}

// MODIFIED: jturunen
void sscopProtocol :: changeToIdleState(void)
{
    changeState(sscopIdle::instance());
    return;
}


void sscopProtocol :: changeToOutgoingConnectionPendingState(void)
{
    changeState(sscopOutgoingConnectionPending::instance());
    return;
}


void sscopProtocol :: changeToIncomingConnectionPendingState(void)
{
    changeState(sscopIncomingConnectionPending::instance());
    return;
}


void sscopProtocol :: changeToOutgoingDisconnectionPendingState(void)
{
    changeState(sscopOutgoingDisconnectionPending::instance());
    return;
}


void sscopProtocol :: changeToOutgoingResynchronizationPendingState(void)
{
    changeState(sscopOutgoingResynchronizationPending::instance());
    return;
}


void sscopProtocol :: changeToIncomingResynchronizationPendingState(void)
{
    changeState(sscopIncomingResynchronizationPending::instance());
    return;
}


void sscopProtocol :: changeToOutgoingRecoveryPendingState(void)
{
    changeState(sscopOutgoingRecoveryPending::instance());
    return;
}


void sscopProtocol :: changeToRecoveryResponsePendingState(void)
{
    changeState(sscopRecoveryResponsePending::instance());
    return;
}


void sscopProtocol :: changeToIncomingRecoveryPendingState(void)
{
    changeState(sscopIncomingRecoveryPending::instance());
    return;
}


void sscopProtocol :: changeToDataTransferReadyState(void)
{
    // MODIFIED: jturunen
    if (lowerLayerIsBusy() == 0)
    {
        // Eli tähän koodi jossa tarkastetaan
        //if (_transmissionQueue > 0)
        //{
        //    createSDpduQueuedUp();
        //}
    }

    changeState(sscopDataTransferReady::instance());
    return;
}


//
// Functions: Set methods for SSCOP timer timeouts
//
// Description:
//     These methods are used to initialize SSCOP timer timeout values.
//     They need to be modified from outside, because timeout values
//     are different on UNI and NNI sides, thus set methods. Methods
//     make conversion from milliseconds to (seconds, microseconds)
//     format used by pfTimers. Also, the timeout value is saved into
//     variable so that copy constructor is able to copy it.
//

void sscopProtocol :: setCCtimeout(pfUlong msec_)
{
    _timerCC.setTimeout(msec_);
    _saveCCtimeout = msec_;
    return;
}


void sscopProtocol :: setKEEP_ALIVEtimeout(pfUlong msec_)
{
    _timerKEEP_ALIVE.setTimeout(msec_);
    _saveKEEP_ALIVEtimeout = msec_;
    return;
}


void sscopProtocol :: setNO_RESPONSEtimeout(pfUlong msec_)
{
    _timerNO_RESPONSE.setTimeout(msec_);
    _saveNO_RESPONSEtimeout = msec_;
    return;
}


void sscopProtocol :: setPOLLtimeout(pfUlong msec_)
{
    _timerPOLL.setTimeout(msec_);
    _savePOLLtimeout = msec_;
    return;
}


void sscopProtocol :: setIDLEtimeout(pfUlong msec_)
{
    _timerIDLE.setTimeout(msec_);
    _saveIDLEtimeout = msec_;
    return;
}

// MODIFIED: jturunen
void sscopProtocol :: setTimerByType(pfTimer &timerType_,
                                     pfUlong &saveValue_,
                                     pfTimerMessenger *message_)
{
    // Data members of the class are passed as references so that
    // their value can be changed
    timerType_.setHost(this);
    timerType_.setMessenger(message_);
    timerType_.setTimeout(saveValue_);
    return;
}

void sscopProtocol :: setAllInitialValues(void)
{
    pfTimerMessenger *messenger = 0;

    messenger = new sscopCCtimeout;
    assert(messenger != 0);
    setTimerByType(_timerCC, _saveCCtimeout, messenger);
    
    messenger = new sscopKEEP_ALIVEtimeout;
    assert(messenger != 0);
    setTimerByType(_timerKEEP_ALIVE, _saveKEEP_ALIVEtimeout, messenger);
    
    messenger = new sscopNO_RESPONSEtimeout;
    assert(messenger != 0);
    setTimerByType(_timerNO_RESPONSE, _saveNO_RESPONSEtimeout, messenger);
    
    messenger = new sscopPOLLtimeout;
    assert(messenger != 0);
    setTimerByType(_timerPOLL, _savePOLLtimeout, messenger);
    
    messenger = new sscopIDLEtimeout;
    assert(messenger != 0);
    setTimerByType(_timerIDLE, _saveIDLEtimeout, messenger);
    
    _VT_S = 0;
    _VT_PS = 0;
    _VT_A = 0;
    _VT_PA = 0;
    _VT_MS = 0;
    _VT_SQ = 0;
    _VR_R = 0;
    _VR_H = 0;
    _VR_MR = 0;
    _VR_SQ = 0;
    _clearBuffers = true;

    return;
}


//
// Function: sscopProtocol :: sendCpcsUNTIDATAreq
//
// Description:
//     Sends a CPCS-UNITDATA.request to the CPCS protocol connected
//     to the side A of this conduit
//

void sscopProtocol :: sendCpcsUNITDATAreq(const pfFrame &frame_)
{
    cpcsUNITDATAreq *message = new cpcsUNITDATAreq;
    assert(message != 0);
    message->setInterfaceData(frame_);
    toA(message);
    return;
}


//
// Function: clearTransmissionQueue
//
// Description:
//     Clears the transmission queue structure
//

void sscopProtocol :: clearTransmissionQueue(void)
{
    //debugUser("sscopProtocol::clearTransmissionQueue");
    _transmissionQueue.erase(_transmissionQueue.begin(),
                             _transmissionQueue.end());
    return;
}


//
// Function: clearTransmissionBuffer
//
// Description:
//     Clears the transmission buffer structure
//

void sscopProtocol :: clearTransmissionBuffer(void)
{
    //debugUser("sscopProtocol::clearTransmissionBuffer");
    _transmissionBuffer.erase(_transmissionBuffer.begin(),
                              _transmissionBuffer.end());
    return;
}


//
// Function: insertIntoTransmissionBuffer
//
// Description:
//     A method to insert a received SD PDU into transmission buffer,
//     provided for convenience.
//

void sscopProtocol :: insertIntoTransmissionBuffer(sscopSD_PDU *messenger_)
{
    //debugUser("sscopProtocol::insertIntoTransmissionBuffer");
    // No need to make a copy of the SD PDU for storing it into
    // the transmission buffer
    _transmissionBuffer.insert(
        pduMap::value_type(messenger_->getSequenceNumber(), messenger_));
    return;
}


//
// Function: clearRetransmissionQueue
//
// Description:
//     Clears the retransmission queue structure
//

void sscopProtocol :: clearRetransmissionQueue(void)
{
    //debugUser("sscopProtocol::insertIntoTransmissionBuffer");
    _retransmissionQueue.erase(_retransmissionQueue.begin(),
                               _retransmissionQueue.end());
    return;
}


//
// Function: insertIntoRetransmissionQueue
//
// Description:
//     A method to insert a received SD PDU into retransmission queue,
//     provided for convenience.
//

void sscopProtocol :: insertIntoRetransmissionQueue(sscopSD_PDU *messenger_)
{
    //debugUser("sscopProtocol::insertIntoRetransmissionQueue");
    // No need to make a copy of the SD PDU for storing it into
    // the retransmission queue, because the original is already
    // stored in the transmission buffer and will not be deleted
    // from there before it is removed from the retransmission
    // queue.
    _retransmissionQueue.insert(
        pduMap::value_type(messenger_->getSequenceNumber(), messenger_));
    return;
}


//
// Function: clearReceiverBuffer
//
// Description:
//     Clears the receiver buffer structure
//

void sscopProtocol :: clearReceiverBuffer(void)
{
    //debugUser("sscopProtocol::clearReceiverBuffer");
    _receiverBuffer.erase(_receiverBuffer.begin(),
                          _receiverBuffer.end());
    return;
}


//
// Function: receiverBufferIsFull
//
// Description:
//     Returns the status of the receiver buffer.
//

bool sscopProtocol :: receiverBufferIsFull(void) const
{
    //debugUser("sscopProtocol::receiverBufferIsFull");
    // Currently the receiver buffer is never full...
    bool isFull = false;
    return isFull;
}


//
// Function: insertIntoReceiverBuffer
//
// Description:
//     A method to insert a received SD PDU into receiver buffer,
//     provided for convenience.
//

void sscopProtocol :: insertIntoReceiverBuffer(sscopSD_PDU *messenger_)
{
    //debugUser("sscopProtocol::insertIntoReceiverBuffer");
    // Make a copy of the received SD PDU for storing it into
    // the receiver buffer - the original will be destroyed
    // by the conduit accept method.
    sscopSD_PDU *msg = new sscopSD_PDU;
    msg->setInformation(messenger_->getInformation());
    msg->setSequenceNumber(messenger_->getSequenceNumber());
    _receiverBuffer.insert(pduMap::value_type(msg->getSequenceNumber(), msg));
    return;
}


// Method: runCallback
//
// Description:
//     Overriding runCallback from pfProtocol to allow debug info
//     be printed here.
//

void sscopProtocol :: acceptSynchronous(pfTransporter *transporter_)
{
#if 0
    debugUser("sscopProtocol::acceptSynchronous");
    debugString("SSCOP state", pfDebug::getStateName(this->getState()));
    debugUser("State variables in SSCOP before");
    printStateVariables();
#endif
    pfProtocol::acceptSynchronous(transporter_);
#if 0
    debugUser("State variables in SSCOP after");
    printStateVariables();
#endif
    return;
}

void sscopProtocol :: printStateVariables(void)
{
    debugUser("sscopProtocol::printStateVariables");
    debugPfUlong("_VT_S", _VT_S.getValue());
    debugPfUlong("_VT_PS", _VT_PS.getValue());
    debugPfUlong("_VT_A", _VT_A.getValue());
    debugPfUlong("_VT_PA", _VT_PA.getValue());
    debugPfUlong("_VT_MS", _VT_MS.getValue());
    debugPfUlong("_VT_PD", _VT_PD);
    debugPfUlong("_VT_CC", _VT_CC);
    debugPfUlong("_VT_SQ", _VT_SQ.getValue());
    debugPfUlong("_VR_R", _VR_R.getValue());
    debugPfUlong("_VR_H", _VR_H.getValue());
    debugPfUlong("_VR_MR", _VR_MR.getValue());
    debugPfUlong("_VR_SQ", _VR_SQ.getValue());

    debugPfUlong("_POLL", _savePOLLtimeout);
    debugPfUlong("_KEEPALIVE", _saveKEEP_ALIVEtimeout);
    return;
}


// moved here from sscopstate.ccp



















//
// Function: sscopState :: releaseBuffers
//
// Description:
//     Q.2110 SDL macro (page 76)
//

void sscopProtocol :: releaseBuffers(void)
{
    //debugUser("sscopProtocol::releaseBuffers");
    clearTransmissionQueue();
    clearTransmissionBuffer();
    clearRetransmissionQueue();
    clearReceiverBuffer();
    return;
}


//
// sscopProtocol :: prepareRetrieval
//
// Description:
//     Q.2110 SDL macro (page 76)
//

void sscopProtocol :: prepareRetrieval(void)
{
    //debugUser("sscopProtocol::prepareRetrieval");
    if (_clearBuffers != 0)
    {
        //debugUser("sscopProtocol::prepareRetrieval::clearBuffers");
        clearTransmissionQueue();
        clearTransmissionBuffer();
    }
    clearRetransmissionQueue();
    clearReceiverBuffer();
    return;
}


//
// sscopProtocol :: prepareRecovery
//
// Description:
//     Q.2110 SDL macro (page 76)
//

void sscopProtocol :: prepareRecovery(void)
{
    //debugUser("sscopProtocol::prepareRecovery");
    if (_clearBuffers != 0)
    {
        //debugUser("sscopProtocol::prepareRecovery::clearBuffers");
        clearTransmissionQueue();
        clearTransmissionBuffer();
    }
    clearRetransmissionQueue();
    return;
}


//
// sscopProtocol :: clearTransmitter
//
// Description:
//     Q.2110 SDL macro (page 76)
//     NOTE: Implementation differs from the Q.2110 SDL description:
//           YES and NO branches of the decision are exchanged
//

void sscopProtocol :: clearTransmitter(void)
{
    //debugUser("sscopProtocol::clearTransmitter");
    if (_clearBuffers != 0)
    {
        //debugUser("sscopProtocol::clearTransmitter::clearBuffers");
        clearTransmissionQueue();
        clearTransmissionBuffer();
    }
    return;
}


//
// sscopProtocol :: deliverData
//
// Description:
//     Q.2110 SDL macro (page 76)
//

void sscopProtocol :: deliverData(void)
{
    //debugUser("sscopProtocol::deliverData");
    if (_clearBuffers == 0)
    {
        //debugUser("sscopProtocol::deliverData::clearBuffers");
        sscopProtocol::pduMapIterator iter =
            _receiverBuffer.begin();
        while (iter != _receiverBuffer.end())
        {
            sscopSD_PDU *msg = (*iter).second;
            sendAaDATAind(msg->getInformation(),
                                     msg->getSequenceNumber());
            _receiverBuffer.erase(iter);
            delete msg;
            iter = _receiverBuffer.begin();
        }
    }
    clearReceiverBuffer();
    return;
}


//
// sscopProtocol :: initializeStateVariables
//
// Description:
//     Q.2110 SDL macro (page 76)
//

void sscopProtocol :: initializeStateVariables(void)
{
    //debugUser("sscopProtocol::initializeStateVariables");
    _VT_S = 0;
    _VT_PS = 0;
    _VT_A = 0;
    _VT_PA = 1;
    _VT_PD = 0;
    _credit = true;
    _VR_R = 0;
    _VR_H = 0;
    return;
}


//
// sscopProtocol :: dataRetrieval
//
// Description:
//     Q.2110 SDL macro (page 77)
//

void sscopProtocol :: dataRetrieval(pfUlong retrievalNumber_)
{
    sscopSD_PDU *msg = 0;
    //debugUser("sscopProtocol::dataRetrieval");
    if (retrievalNumber_ != NNI_RETRIEVE_UNKNOWN)
    {
        moduloInteger i(SSCOP_SEQUENCE_MODULUS);
        if (retrievalNumber_ == NNI_RETRIEVE_TOTAL)
        {
            i = _VT_A;
        }
        else
        {
            i = retrievalNumber_ + 1;
        }
        while ((moduloInteger::compareWithBase(_VT_A,
                                               i,
                                               _VT_A) <= 0) &&
               (moduloInteger::compareWithBase(i,
                                               _VT_S,
                                               _VT_A) < 0))
        {
            sscopProtocol::pduMapIterator iter =
                _transmissionBuffer.find(i.getValue());
            msg = (*iter).second;                
            sendAaRETRIEVEind(msg->getInformation());
            _transmissionBuffer.erase(iter);
            delete msg;
            i++;
        }
    }
    while (_transmissionQueue.empty() == 0)
    {
        pfFrame data = _transmissionQueue.front();
        _transmissionQueue.pop_front();
        sendAaRETRIEVEind(data);
    }
    sendAaRETRIEVE_COMPLETEind();
    return;
}


//
// sscopProtocol :: detectRetransmission
//
// Description:
//     Q.2110 SDL macro (page 77)
//

bool sscopProtocol :: detectRetransmission(pfUlong N_SQ_)
{
#if 0
    debugUser("sscopProtocol::detectRetransmission");
    debugPfUlong("N(SQ)", N_SQ_);
    debugPfUlong("VR(SQ)", _VR_SQ.getValue());
#endif
    bool retrans = true;
    if (N_SQ_ != _VR_SQ.getValue())
    {
        // debugUser("sscopProtocol::detectRetransmission::new transmission");
        _VR_SQ = N_SQ_;
        retrans = false;
    }
    else
    {
        // debugUser("sscopProtocol::detectRetransmission::retransmission detected");
    }
    return retrans;
}


//
// sscopProtocol :: setPOLLtimer
//
// Description:
//     Q.2110 SDL macro (page 77)
//

void sscopProtocol :: setPOLLtimer(void)
{
    debugUser("sscopProtocol::setPOLLtimer");
    if ((_transmissionQueue.empty() != 0) &&
        (_VT_S.getValue() == _VT_A.getValue()))
    {
        debugUser("sscopProtocol::setPOLLtimer::keep alive");
        _timerKEEP_ALIVE.start();
    }
    else
    {
        debugUser("sscopProtocol::setPOLLtimer::poll");
        _timerPOLL.start();
    }
    return;
}


//
// sscopProtocol :: resetDataTransferTimers
//
// Description:
//     Q.2110 SDL macro (page 78)
//

void sscopProtocol :: resetDataTransferTimers(void)
{
    debugUser("sscopProtocol::resetDataTransferTimers");
    _timerPOLL.stop();
    _timerKEEP_ALIVE.stop();
    _timerNO_RESPONSE.stop();
    _timerIDLE.stop();
    return;
}


//
// sscopProtocol :: setDataTransferTimers
//
// Description:
//     Q.2110 SDL macro (page 78)
//

void sscopProtocol :: setDataTransferTimers(void)
{
    debugUser("sscopProtocol::setDataTransferTimers");
    _timerPOLL.start();
    _timerNO_RESPONSE.start();
    return;
}


//
// sscopProtocol :: initializeVR_MR
//
// Description:
//     Q.2110 SDL macro (page 78)
//

void sscopProtocol :: initializeVR_MR(void)
{
    debugUser("sscopProtocol::initializeVR_MR");
    _VR_MR = _initialVR_MR;
    return;
}


//
// sscopProtocol :: sendErrorReleaseEND
//
// Description:
//     A SDL "macro" function for starting SSCOP release procedure.
//     Sends an error indication to the layer management, and optionally
//     sends an END PDU to the peer SSCOP and an AA-RELEASE.indication
//     to the SSCOP user.
//

void sscopProtocol :: sendErrorReleaseEND(
    sscopError code_,
    pfUlong count_,
    bool sendRelease_,
    bool sendEND_)
{
    debugUser("sscopProtocol::sendErrorReleaseEND");
    sendMaaERRORind(code_, count_);
    if (sendEND_ != false)
    {
        debugUser("sscopProtocol::sendErrorReleaseEND::send end");
        pfFrame emptyFrame;
        sendENDpdu(emptyFrame, SSCOP_RELEASE_SSCOP);
    }
    if (sendRelease_ != false)
    {
        debugUser("sscopProtocol::sendErrorReleaseEND::send release ind");
        pfFrame emptyFrame;
        sendAaRELEASEind(emptyFrame, SSCOP_RELEASE_SSCOP);
    }
    return;
}

