//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / SSCOP protocol
//
//File: sscopstate2.cpp
//
//Version: $Revision: 1.19 $
//
//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 "sscopstate2.h"
#include "sscoppdu.h"
#include "sscopprotocol.h"
#include "iface/aaif/aadownprimitives.h"
#include "pf/frame.h"
#include "pf/timer.h"
#include "pf/error.h"

//
// Variable: sscopOutgoingConnectionPending :: _only
// Function: sscopOutgoingConnectionPending :: instance()
//
// Description:
//     Implements the singleton pattern used for actual states
//

sscopOutgoingConnectionPending *
sscopOutgoingConnectionPending :: _only = 0;

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


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

sscopOutgoingConnectionPending :: ~sscopOutgoingConnectionPending(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 sscopOutgoingConnectionPending :: aaRELEASEreqAct(
    aaRELEASEreq *messenger_,
    pfProtocol *protocol_) const
{
    sscopProtocol *sscop = dynamic_cast<sscopProtocol *>(protocol_);
    THROW_IF_DYNAMIC_CAST_FAILED(sscop);
    sscop->_timerCC.stop();
    sscop->_VT_CC = 1;
    sscop->sendENDpdu(messenger_->getSSCOP_UU(), SSCOP_RELEASE_USER);
    sscop->_timerCC.start();
    sscop->changeToOutgoingDisconnectionPendingState();
    return;
}


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

void sscopOutgoingConnectionPending :: sscopBGNpduAct(
    sscopBGN_PDU *messenger_,
    sscopProtocol *protocol_) const
{
    if (protocol_->detectRetransmission(messenger_->getN_SQ()) == 0)
    {
        protocol_->_timerCC.stop();
        protocol_->_VT_MS = messenger_->getN_MR();
        protocol_->initializeVR_MR();
        protocol_->sendBGAKpdu(protocol_->_lastBGNsscop_uu);
        protocol_->sendAaESTABLISHconf(messenger_->getSSCOP_UU());
        protocol_->initializeStateVariables();
        protocol_->setDataTransferTimers();
        protocol_->changeToDataTransferReadyState();
    }
    return;
}

void sscopOutgoingConnectionPending :: sscopBGAKpduAct(
    sscopBGAK_PDU *messenger_,
    sscopProtocol *protocol_) const
{
    protocol_->_timerCC.stop();
    protocol_->_VT_MS = messenger_->getN_MR();
    protocol_->sendAaESTABLISHconf(messenger_->getSSCOP_UU());
    protocol_->initializeStateVariables();
    protocol_->setDataTransferTimers();
    protocol_->changeToDataTransferReadyState();
    return;
}

void sscopOutgoingConnectionPending :: sscopBGREJpduAct(
    sscopBGREJ_PDU *messenger_,
    sscopProtocol *protocol_) const
{
    protocol_->_timerCC.stop();
    protocol_->sendAaRELEASEind(messenger_->getSSCOP_UU(),
                                SSCOP_RELEASE_USER);
    protocol_->changeToIdleState();
    return;
}


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

void sscopOutgoingConnectionPending :: sscopCCtimeoutAct(
    sscopProtocol *protocol_) const
{
    if (protocol_->_VT_CC >= protocol_->_maxCC)
    {
        protocol_->sendErrorReleaseEND(SSCOP_ERROR_O, 0, 1, 1);
        protocol_->changeToIdleState();
    }
    else
    {
        protocol_->_VT_CC++;
        protocol_->resendLastBGNpdu();
        protocol_->_timerCC.start();
    }
    return;
}
