//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project
//
//File: unistate_n10.cpp
//
//Version: $Revision: 1.16 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/12/14 13:27:09 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Jari Pusa
//
//Description:
//      State Active (N10)
//
//Copyright:
//
//
//Licence:
//
//
//History: 

#include "unistate_n10.h"

#include "unidefs.h"
#include "unistrings.h"
#include "uniprotocol.h"
#include "unipdu.h"
#include "uniprimitives.h"

uniNetworkActive *uniNetworkActive :: _only = 0;

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

uniNetworkActive :: uniNetworkActive(void)
    : uniNetworkState()
{
    return;
}

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

void uniNetworkActive :: uniCONNECT_ACKpduAct(uniCONNECT_ACKpdu *message_,
                                              pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    protocol->verifyMessage(message_, uniState_Active);
    return;
}

// Releasing activities

void uniNetworkActive :: uniRELEASEpduAct(uniRELEASEpdu *message_,
                                          pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    protocol->verifyMessage(message_, uniState_ReleaseRequest);
    protocol->stopAllTimers();
    protocol->clearPMPs(message_);
    protocol->sendRELEASEindToCC(message_);
    protocol->changeToReleaseRequestState();    
    return;
}

void uniNetworkActive :: uniRELEASE_COMPLETEpduAct(
    uniRELEASE_COMPLETEpdu *message_,
    pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    protocol->verifyMessage(message_, uniState_Null);
    protocol->stopAllTimers();
    protocol->clearPMPs(message_);
    protocol->sendRELEASEconfToCC(message_);
    protocol->changeToNullState();
    return;
}

void uniNetworkActive :: sigRELEASEreqAct(sigRELEASEreq *message_,
                                          pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    pfUlong causeR = (*message_)[uniCauseStr].getInteger(uniCause_ValueStr);
    protocol->setInteger(uniCauseRStr, causeR);
    protocol->stopAllTimers();
    protocol->clearPMPs(message_);
    protocol->sendRELEASEpduToCoOrd(message_);
    protocol->setInteger(uniT308TimeoutsStr, 0);
    protocol->startTimer(uniT308Str);
    protocol->changeToReleaseIndicationState();
    return;
}

void uniNetworkActive :: sigRELEASErespAct(sigRELEASEresp *message_,
                                           pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    protocol->stopAllTimers();
    protocol->clearPMPs(message_);
    protocol->sendRELEASE_COMPLETEpduToCoOrd(message_);
    protocol->finalClearing();
    return;
}

void uniNetworkActive :: uniLINK_RELEASEindAct(uniLINK_RELEASEind *,
                                               pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    protocol->sendLINK_ESTABLISHreqToCoOrd();
    return;
}

void uniNetworkActive :: uniLINK_ESTABLISHerrorAct(
    uniLINK_ESTABLISHerror *message_,
    pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    protocol->clearPMPs(message_);
    protocol->clearCall(uniCauseValue_DestinationOutOfOrder);
    return;
}

void uniNetworkActive :: uniLINK_ESTABLISHconfAct(
    uniLINK_ESTABLISHconf *,
    pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    protocol->stopTimer(uniT309Str);
    protocol->statusEnquiry();
    return;
}

//
// Method: uni*PARTY*Act
//
// Description:
//      Messages to and from PMP (Point to Multipoint Protocol)
//      Counting of PMP instances is performed as follows:
//      Increase: uniADD_PARTYpduAct
//                uniADD_PARTYreqAct
//      Decrease: uniADD_PARTYerrorAct
//                uniDROP_PARTYrespAct
//      All pdus include endpoint reference validy check: if failed,
//      a status message with cause #89, "invalid endpoint reference"
//      will be sent.
//

void uniNetworkActive :: uniADD_PARTYpduAct(
    uniADD_PARTYpdu *message_,
    pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    if (protocol->isMultipointConnection() != 0)
    {
        protocol->addPMP(message_);
        protocol->sendADD_PARTYreqToPMP(message_);
    }
    return;
}

void uniNetworkActive :: uniADD_PARTY_ACKpduAct(
    uniADD_PARTY_ACKpdu *message_,
    pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    if (protocol->isMultipointConnection() != 0)
    {
        pfUlong endpointRef = message_->getInteger(uniEndpointReferenceStr);
        if (protocol->isExistingPMP(endpointRef) != 0)
        {
            protocol->sendADD_PARTYrespToPMP(message_);
        }
        else
        {
            protocol->sendSTATUSpduToCoOrd(
                uniCauseValue_InvalidEndpointReference);
        }
    }
    return;
}

void uniNetworkActive :: uniADD_PARTY_REJECTpduAct(
    uniADD_PARTY_REJECTpdu *message_,
    pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    if (protocol->isMultipointConnection() != 0)
    {
        pfUlong endpointRef = message_->getInteger(uniEndpointReferenceStr);
        if (protocol->isExistingPMP(endpointRef) != 0)
        {        
            protocol->sendADD_PARTYerrorToPMP(message_);
        }
        else
        {
            protocol->sendSTATUSpduToCoOrd(
                uniCauseValue_InvalidEndpointReference);
        }
    }
    return;
}

void uniNetworkActive :: uniDROP_PARTYpduAct(
    uniDROP_PARTYpdu *message_,
    pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    if (protocol->isMultipointConnection() != 0)
    {
        pfUlong endpointRef = message_->getInteger(uniEndpointReferenceStr);
        if (protocol->isExistingPMP(endpointRef) != 0)
        {
            protocol->sendDROP_PARTYreqToPMP(message_);
        }
        else
        {
            protocol->sendSTATUSpduToCoOrd(
                uniCauseValue_InvalidEndpointReference);
        }
    }
    return;
}

void uniNetworkActive :: uniDROP_PARTY_ACKpduAct(
    uniDROP_PARTY_ACKpdu *message_,
    pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    if (protocol->isMultipointConnection() != 0)
    {
        pfUlong endpointRef = message_->getInteger(uniEndpointReferenceStr);
        if (protocol->isExistingPMP(endpointRef) != 0)
        {        
            protocol->sendDROP_PARTYrespToPMP(message_);
        }
        else
        {
            protocol->sendSTATUSpduToCoOrd(
                uniCauseValue_InvalidEndpointReference);
        }
    }
    return;
}

void uniNetworkActive :: uniADD_PARTYreqAct(
    uniADD_PARTYreq *message_,
    pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    if (protocol->isMultipointConnection() != 0)
    {
        protocol->addPMP(message_);
        protocol->sendADD_PARTYpduToCoOrd(message_);
    }
    return;
}

void uniNetworkActive :: uniADD_PARTYrespAct(
    uniADD_PARTYresp *message_,
    pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    if (protocol->isMultipointConnection() != 0)
    {
        protocol->sendADD_PARTY_ACKpduToCoOrd(message_);
    }
    return;
}

void uniNetworkActive :: uniADD_PARTYerrorAct(
    uniADD_PARTYerror *message_,
    pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    if (protocol->isMultipointConnection() != 0)
    {
        protocol->sendADD_PARTY_REJECTpduToCoOrd(message_);
        protocol->removePMP(message_);
    }
    return;
}

void uniNetworkActive :: uniDROP_PARTYreqAct(
    uniDROP_PARTYreq *message_,
    pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    if (protocol->isMultipointConnection() != 0)
    {
        protocol->sendDROP_PARTYpduToCoOrd(message_);
    }
    return;
}

void uniNetworkActive :: uniDROP_PARTYrespAct(
    uniDROP_PARTYresp *message_,
    pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    if (protocol->isMultipointConnection() != 0)
    {
        protocol->sendDROP_PARTY_ACKpduToCoOrd(message_);
        protocol->removePMP(message_);
    }
    return;
}

void uniNetworkActive :: uniSTATUSrespAct(
    uniSTATUSresp *message_,
    pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    if (protocol->isMultipointConnection() != 0)
    {
        protocol->sendSTATUSpduToCoOrd(message_);
    }
    return;
}

void uniNetworkActive :: uniSTATUS_ENQUIRYpduAct(
    uniSTATUS_ENQUIRYpdu *message_,
    pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);

    // Check if multipoint messages are allowed and if this is a
    // multipoint message. If not, send normal status response.
    if ((message_->isMultipointMessage() != 0) &&
        (protocol->isMultipointConnection() != 0))
    {
        pfUlong endpointRef = message_->getInteger(uniEndpointReferenceStr);
        if (protocol->isExistingPMP(endpointRef) != 0)
        {        
            protocol->sendSTATUSreqToPMP(message_);
        }
        else
        {
            protocol->sendSTATUSpduToCoOrd(
                uniCauseValue_InvalidEndpointReference);
        }
    }
    else
    {
        protocol->sendSTATUSpduToCoOrd(message_);
    }

    return;
}

void uniNetworkActive :: uniTREMOVEDtimeoutAct(pfProtocol *protocol_)
{
    uniProtocol *protocol = dynamic_cast<uniProtocol*>(protocol_);
    protocol->setBooleanTrue(uniAllowFinalClearingStr);
    return;
}

