//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / 
//
//File: bisupprotocol.cpp
//
//Version: $Revision: 1.28 $
//
//State: $State: Exp $
//
//Date: $Date: 1999/03/10 15:02:31 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Sami Raatikainen
//
//Description:
//      See corresponding header file.
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//
//Licence:
//
//
//History:

#include "bisupprotocol.h"
#include "bisupstrings.h"
#include "bisupmode.h"
#include "bisuptimeouts.h"

#include "iface/sigif/sigupprimitives.h"
#include "iface/sigif/sigdownprimitives.h"
#include "protocol/cc/ccprotocol.h"
#include "ie/iestrings.h"
#include "ie/callreference.h"
#include "pf/error.h"
#include "pf/debug.h"


bisupProtocol *bisupProtocol :: create(void)
{
    bisupProtocol *protocol = new bisupProtocol;
    return protocol;
}

bisupProtocol :: bisupProtocol(void)
    : sigProtocol(),
      _DSID(0),
      _T1bvalue(30),
      _T7bvalue(30),
      _T9bvalue(60),
      _T40bvalue(4)
{
    debugUser("bisupProtocol created");
    setMode(bisupMode::instance());
    initTimers();
    changeToIdleState();
    return;
}

bisupProtocol :: bisupProtocol(const bisupProtocol &other_)
    : sigProtocol(other_),
      _DSID(0),
      _T1bvalue(other_._T1bvalue),
      _T7bvalue(other_._T7bvalue),
      _T9bvalue(other_._T9bvalue),
      _T40bvalue(other_._T40bvalue)
{
    debugUser("bisupProtocol created");
    setMode(bisupMode::instance());
    initTimers();
    changeToIdleState();
    return;
}

bisupProtocol :: ~bisupProtocol(void)
{
    delete _DSID;
    debugUser("bisupProtocol deleted");
    return;
}

pfProtocol *bisupProtocol :: cloneImplementation(void) const
{
    bisupProtocol *protocol = new bisupProtocol(*this);
    return protocol;
}


//
// Methods: createConduitsConnection
//
// Description:
//       BISUP doesn't support multipoint connections. Method creates
//       new ccProtocol and connects two proxies (CC and this) together.
//

void bisupProtocol :: createConduitsConnection(void)
{
    pfConduit cc(ccProtocol::create());
    pfConduit proxy(this);
    cc.connectToA(proxy);
    proxy.connectToB(cc);
    cc.setId(getId());
    return;
}

//
// Methods: changeTo*State
//
// Description:
//      Makes a state change using bisupMode which is protocol dependent,
//      (ie. BISUP and ISUP may have different state changes).
//


//
// Methods: send*ToX
//
// Description:
//      Those methods that need different functionality are implemented
//      in this inherited protocol.
//

void bisupProtocol :: sendIAMpduToDown(sigSETUPreq *primitive_)
{
    nniIAMpdu *pdu = new nniIAMpdu;
    saveMessage(primitive_);
    toDown(primitive_, pdu);
    return;
}

void bisupProtocol :: sendIAApduToDown(sigPROCEEDINGreq *primitive_)
{
    nniIAApdu *pdu = new nniIAApdu;
    toDown(primitive_, pdu);
    return;
}

void bisupProtocol :: sendIARpduToDown(sigRELEASEresp *primitive_)
{
    nniIARpdu *pdu = new nniIARpdu;
    toDown(primitive_, pdu);
    return;
}

void bisupProtocol :: sendACMpduToDown(sigALERTINGreq *primitive_)
{
    nniACMpdu *pdu = new nniACMpdu;
    toDown(primitive_, pdu);
    return;
}

/*
void bisupProtocol :: sendCPGpduToDown(sigPROGRESSreq *primitive_)
{
    nniCPGpdu *pdu = new nniCPGpdu;
    toDown(primitive_, pdu);
    return;
}
*/

void bisupProtocol :: sendANMpduToDown(sigSETUPresp *primitive_)
{
    nniANMpdu *pdu = new nniANMpdu;
    toDown(primitive_, pdu);
    return;
}

void bisupProtocol :: sendRELpduToDown(sigRELEASEreq *primitive_)
{
    nniRELpdu *pdu = new nniRELpdu;
    toDown(primitive_, pdu);
    return;
}

void bisupProtocol :: sendRELpduToDown(pfUlong cause_)
{
    nniRELpdu *pdu = new nniRELpdu;
    setCause(pdu, cause_);
    toA(pdu);
    return;
}

void bisupProtocol :: sendRLCpduToDown(sigRELEASEresp *primitive_)
{
    nniRLCpdu *pdu = new nniRLCpdu;
    toDown(primitive_, pdu);
    return;
}



//
// Methods: saveDSID
//
// Description:
//       The signaling identifier of the other side has to saved, and it
//       will be included in every message from now on.
//

void bisupProtocol :: saveDSID(pfMessenger *msg_)
{
    _DSID = msg_->adoptIE(ieOSIDStr);
    return;
}



//
// Methods: start/stop*timer
//
// Description:
//       Methods to define the timers to be started and stopped for
//       different situations.
//

void bisupProtocol :: startIAAtimer(void)
{
    startTimer(bisupT40bStr);
    startTimer(bisupT7bStr);
    return;
}

void bisupProtocol :: stopIAAtimer(void)
{
    stopTimer(bisupT40bStr);
    return;
}

void bisupProtocol :: startACMtimer(void)
{
    return;
}

void bisupProtocol :: stopACMtimer(void)
{
    stopTimer(bisupT7bStr);
    return;
}

void bisupProtocol :: startANMtimer(void)
{
    startTimer(bisupT9bStr);
    return;
}

void bisupProtocol :: stopANMtimer(void)
{
    stopTimer(bisupT9bStr);
    return;
}

void bisupProtocol :: startRLCtimer(void)
{
    startTimer(bisupT1bStr);
    return;
}

void bisupProtocol :: stopRLCtimer(void)
{
    stopTimer(bisupT1bStr);
    return;
}


void bisupProtocol :: incomingResourcesRejectedAct(sigRELEASEresp *primitive_)
{
    sendIARpduToDown(primitive_);
    finalClearing();
    return;
}

void bisupProtocol :: releaseCollisionAct(nniRELpdu *primitive_)
{
    changeToRELCollisionState();
    sendRELEASEindToCC(primitive_);
    return;
}


//
// Method: initTimers / stopAllTimers
//
// Description:
//      Sets (resets) all timers to their default values. 11./Q.2764
//

void bisupProtocol :: initTimers(void)
{
    defineTimer(bisupT1bStr, bisupT1btimeout::create(), _T1bvalue);
    defineTimer(bisupT7bStr, bisupT7btimeout::create(), _T7bvalue);
    defineTimer(bisupT9bStr, bisupT9btimeout::create(), _T9bvalue);
    defineTimer(bisupT40bStr, bisupT40btimeout::create(), _T40bvalue);
    return;
}

void bisupProtocol :: stopAllTimers(void)
{
    stopTimer(bisupT1bStr);
    stopTimer(bisupT7bStr);
    stopTimer(bisupT9bStr);
    stopTimer(bisupT40bStr);
    return;
}


void bisupProtocol :: reportIncompatibleMessage(pfMessenger *)
{
    // ++TODO++ what is the right thing?!
    startReleaseProcess(sigCauseValue_MessageNotCompatibleWithCallState);
    return;
}

void bisupProtocol :: setCallReference(pfMessenger *message_)
{
    auto_ptr<pfIE> iePtr(_DSID);
    message_->setIE(ieDSIDStr, iePtr);
    return;
}


//
// Method: startReleaseProcess
//
// Description:
//      Begins the call release process by sending RELEASE to
//      other side of the call, and an indication to the user.
//

// ++TODO++ cc action has to be checked and defined
void bisupProtocol :: startReleaseProcess(pfUlong cause_)
{
    debugPfUlong("Starting release process with cause ", cause_);
    stopAllTimers();
    sendRELEASEindToCC(cause_);
    sendRELpduToDown(cause_);
    startRLCtimer();
    changeToAwaitRLCState();
    return;
}

//
// Method: clearCall
//
// Description:
//      Clears the call. After sending a release conf to CC, signaling
//      protocol has to wait CC to inform with release resp that all
//      resources has been unallocated and implementations may be removed.
//

void bisupProtocol :: clearCall(pfUlong cause_)
{
    debugPfUlong("Clearing call with cause ", cause_);
    stopAllTimers();
    sendRELEASEconfToCC(cause_);
    changeToIdleState();
    // Wait for response from cc
    return;
}
