//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / SIG
//
//File: sigprotocol.h
//
//Version: $Revision: 1.14 $
//
//State: $State: Exp $
//
//Date: $Date: 1999/03/10 16:07:32 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Sami Raatikainen
//
//Description:
//      SIG protocol conduit implementation. See corresponding header file.
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//
//Licence:
//
//
//History: 

#include "sigprotocol.h"
#include "sigstrings.h"

#include "pf/mux.h"
#include "pf/factory.h"
#include "pf/exception.h"
#include "pf/debug.h"
#include "pf/error.h"

#include "iface/sigif/sigupprimitives.h"
#include "iface/sigif/sigdownprimitives.h"

#include "protocol/uni/unistrings.h"
#include "ie/cause.h"
#include "ie/iestrings.h"

sigProtocol :: sigProtocol(void)
    : pfProtocol(),
      _mode(0),
      _multipoint(false),
      _location(sigLocation_User),
      _savedMsg(0)
{
    _mode = sigMode::instance();
    return;
}

sigProtocol :: sigProtocol(const sigProtocol &other_)
    : pfProtocol(other_),
      _mode(other_._mode),
      _multipoint(other_._multipoint),
      _location(other_._location),
      _savedMsg(0)
{
    return;
}

sigProtocol :: ~sigProtocol(void)
{
    clearSavedMessage();
    return;
}


//
// Method: setMode
//
// Description:
//      Signalling protocols usually operate in two modes, user and network, 
//      or defined as outgoing and incoming modes. Selection must be
//      performed with this method.
//

void sigProtocol :: setMode(sigMode *mode_)
{
    if (mode_ == 0)
    {
        throw pfNullPointerException(PF_EX_INFO);
    }
    _mode = mode_;
    return;
}

bool sigProtocol :: isNetworkMode(void)
{
    bool result = _mode->isNetworkMode();
    return result;
}


//
// Methods: send*ToCC
//
// Description:
//      Sends a primitive (response) to CC (upper) protocol. Writing these
//      methods, despite the obvious similarity, enables writing more actions
//      if needed at inherited protocols
//

void sigProtocol :: toCC(pfMessenger *receivedMsg_,
                         sigPrimitive *sendMsg_)
{
    if (_multipoint == true)
    {
        //setZeroEndpointReference(primitive_);
    }
    sendMsg_->adoptAll(receivedMsg_);
    toB(sendMsg_);
    return;
}


void sigProtocol :: sendSETUPindToCC(pfMessenger *primitive_)
{
    sigSETUPind *primitive = new sigSETUPind;
    toCC(primitive_, primitive);
    return;
}

void sigProtocol :: sendPROCEEDINGindToCC(pfMessenger *primitive_)
{
    sigPROCEEDINGind *primitive = new sigPROCEEDINGind;
    toCC(primitive_, primitive);
    return;
}

void sigProtocol :: sendALERTINGindToCC(pfMessenger *primitive_)
{
    sigALERTINGind *primitive = new sigALERTINGind;
    toCC(primitive_, primitive);
    return;
}

void sigProtocol :: sendPROGRESSindToCC(pfMessenger *primitive_)
{
    sigPROGRESSind *primitive = new sigPROGRESSind;
    toCC(primitive_, primitive);
    return;
}

void sigProtocol :: sendSETUPconfToCC(pfMessenger *primitive_)
{
    sigSETUPconf *primitive = new sigSETUPconf;
    toCC(primitive_, primitive);
    return;
}

void sigProtocol :: sendSETUP_COMPLETEindToCC(pfMessenger *primitive_)
{
    sigSETUP_COMPLETEind *primitive = new sigSETUP_COMPLETEind;
    toCC(primitive_, primitive);
    return;
}

void sigProtocol :: sendRELEASEindToCC(pfMessenger *primitive_)
{
    sigRELEASEind *primitive = new sigRELEASEind;
    toCC(primitive_, primitive);
    return;
}

void sigProtocol :: sendRELEASEindToCC(pfUlong cause_)
{
    sigRELEASEind *primitive = new sigRELEASEind;
    setCause(primitive, cause_);
    toB(primitive);
    return;
}

void sigProtocol :: sendRELEASEconfToCC(pfMessenger *primitive_)
{
    sigRELEASEconf *primitive = new sigRELEASEconf;
    toCC(primitive_, primitive);
    return;
}

void sigProtocol :: sendRELEASEconfToCC(pfUlong cause_)
{
    sigRELEASEconf *primitive = new sigRELEASEconf;
    setCause(primitive, cause_);
    toB(primitive);
    return;
}


void sigProtocol :: sendRESET_ERRORindToCC(pfMessenger *primitive_)
{
    sigRESET_ERRORind *primitive = new sigRESET_ERRORind;
    toCC(primitive_, primitive);
    return;
}

void sigProtocol :: sendRESETconfToCC(pfMessenger *primitive_)
{
    sigRESETconf *primitive = new sigRESETconf;
    toCC(primitive_, primitive);
    return;
}

void sigProtocol :: sendRESETindToCC(pfMessenger *primitive_)
{
    sigRESETind *primitive = new sigRESETind;
    toCC(primitive_, primitive);
    return;
}


//
// Methods: send*ToCoOrd
//
// Description:
//      Sends a message (primitive) to coordination (lower) functions.
//      Takes all IEs from sigPrimitive and sets call reference (pure 
//      virtual).
//

void sigProtocol :: toDown(sigPrimitive *primitive_,
                           pfMessenger *sendMsg_)
{
    sendMsg_->adoptAll(primitive_);
    setCallReference(primitive_);
    toA(sendMsg_);
    return;
}



//
// Methods: changeTo*State
//
// Description:
//      Makes a state change using sigMode which is protocol dependent.
//      Different states for UNI and NNI protocols.
//

// UNI States
void sigProtocol :: changeToNullState(void)
{
    changeState(_mode->createNullState());
    return;
}

void sigProtocol :: changeToCallInitiatedState(void)
{
    changeState(_mode->createCallInitiatedState());
    return;
}

void sigProtocol :: changeToOutgoingCallProceedingState(void)
{
    changeState(_mode->createOutgoingCallProceedingState());
    return;
}

void sigProtocol :: changeToCallDeliveredState(void)
{
    changeState(_mode->createCallDeliveredState());
    return;
}

void sigProtocol :: changeToCallPresentState(void)
{
    changeState(_mode->createCallPresentState());
    return;
}
void sigProtocol :: changeToCallReceivedState(void)
{
    changeState(_mode->createCallReceivedState());
    return;
}

void sigProtocol :: changeToUserConnectRequestState(void)
{
    changeState(_mode->createUserConnectRequestState());
    return;
}

void sigProtocol :: changeToNetworkConnectRequestState(void)
{
    changeState(_mode->createNetworkConnectRequestState());
    return;
}

void sigProtocol :: changeToIncomingCallProceedingState(void)
{
    changeState(_mode->createIncomingCallProceedingState());
    return;
}

void sigProtocol :: changeToActiveState(void)
{
    changeState(_mode->createActiveState());
    return;
}

void sigProtocol :: changeToReleaseRequestState(void)
{
    changeState(_mode->createReleaseRequestState());
    return;
}

void sigProtocol :: changeToReleaseIndicationState(void)
{
    changeState(_mode->createReleaseIndicationState());
    return;
}


// NNI States
void sigProtocol :: changeToIdleState(void)
{
    _mode->createIdleState();
    return;
}

void sigProtocol :: changeToAwaitIAAState(void)
{
    _mode->createAwaitIAAState();
    return;
}

void sigProtocol :: changeToAwaitACMState(void)
{
    _mode->createAwaitACMState();
    return;
}

void sigProtocol :: changeToAwaitANMState(void)
{
    _mode->createAwaitANMState();
    return;
}

void sigProtocol :: changeToAwaitAcceptedReqState(void)
{
    _mode->createAwaitAcceptedReqState();
    return;
}

void sigProtocol :: changeToAwaitAnswerState(void)
{
    _mode->createAwaitAnswerReqState();
    return;
}

void sigProtocol :: changeToAwaitAddressCompReqState(void)
{
    _mode->createAwaitAddressCompReqState();
    return;
}

void sigProtocol :: changeToCallAnsweredState(void)
{
    _mode->createCallAnsweredState();
    return;
}

void sigProtocol :: changeToAwaitRLCState(void)
{
    _mode->createAwaitRLCState();
    return;
}

void sigProtocol :: changeToAwaitReleaseRespState(void)
{
    _mode->createAwaitReleaseRespState();
    return;
}

void sigProtocol :: changeToRELCollisionState(void)
{
    _mode->createRELCollisionState();
    return;
}


//
// Method: finalClearing
//
// Description:
//      Removes SIGNALLING / CC conduits.
//

void sigProtocol :: finalClearing(void)
{
    stopAllTimers();
    debugUser("Removing CC / SIGNALLING...");
    pfKey key = getKey();
    pfUnInstallTransporter uninstaller =
        pfUnInstallTransporter::createUnInstallTransporter(key);
    toA(&uninstaller);
    return;
}


//
// Methods: set/isMultipointConnection
//
// Description:
//      Methods to set the multipoint connection flag, and to return it.
//

void sigProtocol :: setMultipointConnection(void)
{
    _multipoint = true;
    return;
}

bool sigProtocol :: isMultipointConnection(void)
{
    return _multipoint;
}

//
// Method: setXSideEndpointReference
//
// Description:
//      Methods to implement setting endpoint reference value to primitives.
//

void sigProtocol :: setZeroEndpointReferenceAtOSide(pfMessenger *)
{
    debugUser("This implementation does not support multipoint");
    THROW_INVALID_ENDPOINT_REFERENCE;
    return;
}

void sigProtocol :: setZeroEndpointReferenceAtTSide(pfMessenger *)
{
    debugUser("This implementation does not support multipoint");
    THROW_INVALID_ENDPOINT_REFERENCE;
    return;
}

void sigProtocol :: setZeroEndpointReference(pfMessenger *)
{
    debugUser("This implementation does not support multipoint");
    THROW_INVALID_ENDPOINT_REFERENCE;
    return;
}


//
// Methods: setLocation / getLocation
//
// Description:
//      Methods to set the location (2.2.3./Q.850), and to return it.
//

void sigProtocol :: setLocation(sigLocation location_)
{
    _location = location_;
    return;
}

pfUlong sigProtocol :: getLocation(void)
{
    return _location;
}


//
// Methods: saveMessage / getSavedMessage / clearSavedMessage
//
// Description:
//       Enables saving and resending of messages.
//       ++TODO++, check if ref counts are right???
//

void sigProtocol :: saveMessage(pfMessenger *msg_)
{
    if (_savedMsg != 0)
    {
        _savedMsg->decRefCount();
        if (_savedMsg->isReference() == false)
        {
            delete _savedMsg;
        }
    }
    _savedMsg = msg_;
    _savedMsg->incRefCount();
    return;
}

pfMessenger *sigProtocol :: getSavedMessage(void)
{
    if (_savedMsg == 0)
    {
        THROW_PROTOCOL_ERROR_UNSPECIFIED;
    }
    _savedMsg->decRefCount();
    return _savedMsg;
}

void sigProtocol :: clearSavedMessage(void)
{
    if (_savedMsg != 0)
    {
        _savedMsg->decRefCount();
        if (_savedMsg->isReference() == false)
        {
            delete _savedMsg;
        }
        _savedMsg = 0;
    }
    return;
}
        

void sigProtocol :: setCause(pfMessenger *primitive_, pfUlong cause_)
{
    ieCause *ie = new ieCause(cause_, _location);
    auto_ptr<pfIE> iePtr(ie);
    primitive_->setIE(ieCauseStr, iePtr);
    return;
}
