//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / UNI
//
//File: unirsnstate.cpp
//
//Version: $Revision: 1.12 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/10/10 15:57:12 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Jari Katajavuori
//
//Description:
//      See header file.
//
//Copyright:
//
//
//Licence:
//
//
//History: 

#include "unirsnstate.h"

#include "pf/protocol.h"
#include "pf/debug.h"

#include "unidefs.h"
#include "unistrings.h"
#include "unirsnprotocol.h"

//
// Class: uniRSNNullState
//
// Method: contructor & destructor
//
// Description:
//

uniRSNState :: uniRSNState(void)
    : uniDownRSNInputs(),
      uniRSNMessageInputs(),
      uniStatusMessageInputs(),
      uniRSNTimeoutInputs(),
      pfState()
{
    return;
}

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

//
// Methods: uni*Act
//
// Description:
//      Dummy actions.
//

void uniRSNState :: uniRESETreqAct(uniRESETreq *,
                                   pfProtocol *)
{
    return;
}

void uniRSNState :: uniSTATUSpduAct(uniSTATUSpdu *,
                                    pfProtocol *)
{
    return;
}

void uniRSNState :: uniRESTART_ACKpduAct(uniRESTART_ACKpdu *,
                                         pfProtocol *)
{
    return;
}

void uniRSNState :: uniT316timeoutAct(pfProtocol *)
{
    return;
}

//------------------------------------------------------------------
// Class: uniRSNNullState
//

uniRSNNullState *uniRSNNullState :: _only = 0;

//
// Method: instance
//
// Description:
//      This static method returns the only instance of the current class.
//

uniRSNNullState *uniRSNNullState :: instance(void)
{
    if (_only == 0)
    {
        _only = new uniRSNNullState;
    }
    return _only;
}

//
// Method: constructor & destructor
//
// Description:
//

uniRSNNullState :: uniRSNNullState(void)
    : uniRSNState()
{
    return;
}

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

//
// Method: uniRESETreqAct
//
// Description:
//      Called when RESET req from CC received. Send a RESET pdu and
//      wait for response from opposite party.
//

void uniRSNNullState :: uniRESETreqAct(uniRESETreq *message_,
                                       pfProtocol *protocol_)
{
    debugUser("RSN NullState: uniRESETreqAct");
    message_->print();
    uniRSNProtocol *protocol = (uniRSNProtocol *) protocol_;
    
    protocol->setStorage(uniRSNConnectIDsStr,
                         (*message_)[uniConnectionIdentifierStr]);
    protocol->setInteger(uniRSNTimeoutsStr, 0);
    protocol->sendRESTARTpdu(*message_);
    protocol->startTimer(uniT316Str);
    protocol->changeToRestartRequestState();
    return;
}

//------------------------------------------------------------------
// Class: uniRSNRestartRequestState
//

uniRSNRestartRequestState *uniRSNRestartRequestState :: _only = 0;

//
// Method: instance
//
// Description:
//      This static method returns the only instance of the current class.
//

uniRSNRestartRequestState *uniRSNRestartRequestState :: instance(void)
{
    if (_only == 0)
    {
        _only = new uniRSNRestartRequestState;
    }
    return _only;
}

//
// Method: contructor & destructor
//
// Description:
//

uniRSNRestartRequestState :: uniRSNRestartRequestState(void)
    : uniRSNState()
{
    return;
}

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

//
// Method: uniSTATUSpduAct
//
// Description:
//      

void uniRSNRestartRequestState :: uniSTATUSpduAct(
    uniSTATUSpdu *,
    pfProtocol *protocol_)
{
    uniRSNProtocol *protocol = dynamic_cast<uniRSNProtocol *>(protocol_);
    if (0 /*if CS not compatible*/)
    {
        protocol->sendRESET_ERRORind(
            uniResetError_PeerIncompatibleState,
            uniState_RestartRequest);
    }
    return;
}

//
// Method: uniRESTART_ACKpduAct
//
// Description:
//      RESTART ACK pdu received: reset performed at the opposite
//      party. Check if VPCI/VCI matches and if, inform upper protocols.
//

void uniRSNRestartRequestState :: uniRESTART_ACKpduAct(
    uniRESTART_ACKpdu *message_,
    pfProtocol *protocol_)
{
    uniRSNProtocol *protocol = (uniRSNProtocol *) protocol_;

    // Check if saved Connection Identifier is the same as current.
    // If sometime is possible to compare two storages, then here is
    // an application..
    pfUlong idVPCIsaved = (*protocol)[uniRSNConnectIDsStr].
        getInteger(uniConnectionIdentifier_VPCIStr);
    pfUlong idVCIsaved = (*protocol)[uniRSNConnectIDsStr].
        getInteger(uniConnectionIdentifier_VCIStr);
    pfUlong idVPCIcurrent = (*message_)[uniConnectionIdentifierStr]. 
        getInteger(uniConnectionIdentifier_VPCIStr);
    pfUlong idVCIcurrent = (*message_)[uniConnectionIdentifierStr].
        getInteger(uniConnectionIdentifier_VCIStr);
    
    if ((idVPCIsaved == idVPCIcurrent) &&
        (idVCIsaved == idVCIcurrent))
    {
        protocol->stopTimer(uniT316Str);
        protocol->sendRESETconf();
        protocol->changeToNullState();
    }
    return;
}

//
// Method: uniT316timeoutAct
//  
// Description:
//      Called when timer T316 expires. If expired under
//      uniRSNNumberOfRestartsSent times, resend RESTART pdu. If the amount
//      is greater, inform uni and fail.
//

void uniRSNRestartRequestState :: uniT316timeoutAct(pfProtocol *protocol_)
{
    uniRSNProtocol *protocol = (uniRSNProtocol *) protocol_;
    pfUlong timeouts = protocol->getInteger(uniRSNTimeoutsStr);
    timeouts++;
    if (timeouts >= uniRSNMaxRestartsSent)
    {
        protocol->sendRESET_ERRORind(uniResetError_NoResponse,
                                     uniState_RestartRequest);
        protocol->changeToNullState();
    }
    else
    {
        protocol->setInteger(uniRSNTimeoutsStr, timeouts);
        protocol->sendRESTARTpdu();
        protocol->startTimer(uniT316Str);
    }
    return;
}

