//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / SSCOP protocol
//
//File: sscopstate1.cpp
//
//Version: $Revision: 1.21 $
//
//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 "sscopstate1.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: sscopIdle :: _only
// Function: sscopIdle :: instance()
//
// Description:
//     Implements the singleton pattern used for actual states
//

sscopIdle *sscopIdle :: _only = 0;

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


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


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


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

void sscopIdle :: aaESTABLISHreqAct(aaESTABLISHreq *messenger_,
                                    pfProtocol *protocol_) const
{
    sscopProtocol *sscop = dynamic_cast<sscopProtocol *>(protocol_);
    THROW_IF_DYNAMIC_CAST_FAILED(sscop);
    sscop->clearTransmitter();
    sscop->_clearBuffers = messenger_->getBufferRelease();
    sscop->_VT_CC = 1;
    sscop->_VT_SQ++;
    sscop->initializeVR_MR();
    sscop->sendBGNpdu(messenger_->getSSCOP_UU());
    sscop->_timerCC.start();
    sscop->changeToOutgoingConnectionPendingState();
    return;
}

void sscopIdle :: aaRETRIEVEreqAct(aaRETRIEVEreq *messenger_,
                                   pfProtocol *protocol_) const
{
    sscopProtocol *sscop = dynamic_cast<sscopProtocol *>(protocol_);
    THROW_IF_DYNAMIC_CAST_FAILED(sscop);
    sscop->dataRetrieval(messenger_->getRetrievalNumber());
    return;
}


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

void sscopIdle :: sscopBGNpduAct(sscopBGN_PDU *messenger_,
                                 sscopProtocol *protocol_) const
{
    if ((protocol_->isPowerUpRobustnessEnabled() == false) && 
       (protocol_->detectRetransmission(messenger_->getN_SQ()) != 0))
    {
        protocol_->sendBGREJpdu(protocol_->_lastBGREJsscop_uu);
    }
    else
    {
        if (protocol_->isPowerUpRobustnessEnabled() != false)
        {
            protocol_->_VR_SQ = messenger_->getN_SQ();
        }
        protocol_->_VT_MS = messenger_->getN_MR();
        protocol_->sendAaESTABLISHind(messenger_->getSSCOP_UU());
        protocol_->changeToIncomingConnectionPendingState();
    }

    return;
}

void sscopIdle :: sscopBGAKpduAct(sscopBGAK_PDU *,
                                  sscopProtocol *protocol_) const
{
    protocol_->sendErrorReleaseEND(SSCOP_ERROR_C, 0, 0, 1);
    return;
}

void sscopIdle :: sscopBGREJpduAct(sscopBGREJ_PDU *,
                                   sscopProtocol *protocol_) const
{
    protocol_->sendErrorReleaseEND(SSCOP_ERROR_D);
    return;
}

void sscopIdle :: sscopENDpduAct(sscopEND_PDU *,
                                 sscopProtocol *protocol_) const
{
    protocol_->sendENDAKpdu();
    return;
}

void sscopIdle :: sscopRSpduAct(sscopRS_PDU *,
                                sscopProtocol *protocol_) const
{
    protocol_->sendErrorReleaseEND(SSCOP_ERROR_J, 0, 0, 1);
    return;
}

void sscopIdle :: sscopRSAKpduAct(sscopRSAK_PDU *,
                                  sscopProtocol *protocol_) const
{
    protocol_->sendErrorReleaseEND(SSCOP_ERROR_K, 0, 0, 1);
    return;
}

void sscopIdle :: sscopERpduAct(sscopER_PDU *,
                                sscopProtocol *protocol_) const
{
    protocol_->sendErrorReleaseEND(SSCOP_ERROR_L, 0, 0, 1);
    return;
}

void sscopIdle :: sscopERAKpduAct(sscopERAK_PDU *,
                                  sscopProtocol *protocol_) const
{
    protocol_->sendErrorReleaseEND(SSCOP_ERROR_M, 0, 0, 1);
    return;
}

void sscopIdle :: sscopSDpduAct(sscopSD_PDU *,
                                sscopProtocol *protocol_) const
{
    protocol_->sendErrorReleaseEND(SSCOP_ERROR_A, 0, 0, 1);
    return;
}

void sscopIdle :: sscopPOLLpduAct(sscopPOLL_PDU *,
                                  sscopProtocol *protocol_) const
{
    protocol_->sendErrorReleaseEND(SSCOP_ERROR_G, 0, 0, 1);
    return;
}

void sscopIdle :: sscopSTATpduAct(sscopSTAT_PDU *messenger_,
                                  sscopProtocol *protocol_) const
{
    // Founded by SSCOP-T0038
    // We check that the PDU is proper length of the STAT PDU at state 1.
    // If it is proper length, this is error that we report using management
    // error reporting. If the length is not preper for this PDU at this
    // state, the pdu is invalid and we should ignore it in the basis
    // of Q.2110 7.1 page 10. 
    if (messenger_->getNItems() == 0)
    {
        protocol_->sendErrorReleaseEND(SSCOP_ERROR_H, 0, 0, 1);
    }
    return;
}

void sscopIdle :: sscopUSTATpduAct(sscopUSTAT_PDU *,
                                   sscopProtocol *protocol_) const
{
    protocol_->sendErrorReleaseEND(SSCOP_ERROR_I, 0, 0, 1);
    return;
}
