//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / BISUP
//
//File: niprotocol.cpp
//
//Version: $Revision: 1.17 $
//
//State: $State: Exp $
//
//Date: $Date: 1999/03/08 07:42:31 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Sami Raatikainen
//
//Description:
//
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//
//Licence:
//
//
//History: 

#include "niprotocol.h"
#include "nistate.h"
#include "bisupstrings.h"
#include "iface/mtpif/mtpdownprimitives.h"
#include "ie/iestrings.h"
#include "ie/callreference.h"

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

bisupIAMCoder *niProtocol :: _IAMCoder = 0;
bisupIAACoder *niProtocol :: _IAACoder = 0;
bisupIARCoder *niProtocol :: _IARCoder = 0;
bisupACMCoder *niProtocol :: _ACMCoder = 0;
bisupCPGCoder *niProtocol :: _CPGCoder = 0;
bisupANMCoder *niProtocol :: _ANMCoder = 0;
bisupRELCoder *niProtocol :: _RELCoder = 0;
bisupRLCCoder *niProtocol :: _RLCCoder = 0;

pfConduit niProtocol :: create(
    pfUlong pointCode_, 
    pfUlong destinationPointCode_)
{
    niProtocol *protocol = new niProtocol(pointCode_, destinationPointCode_);
    pfConduit newConduit(protocol);
    return newConduit;
}

niProtocol :: niProtocol(
    pfUlong pointCode_,
    pfUlong destinationPointCode_)
    : pfProtocol(),
      _OPC(pointCode_),
      _DPC(destinationPointCode_),
      _SLS(30), // ++TODO++ 
      _SIO(9)   // defined for BISUP
{
    changeState(niState::instance());
    return;
}

niProtocol :: ~niProtocol(void)
{
    _IAMCoder = 0;
    _IAACoder = 0;
    _IARCoder = 0;
    _ACMCoder = 0;
    _CPGCoder = 0;
    _ANMCoder = 0;
    _RELCoder = 0;
    _RLCCoder = 0;
    return;
}


bisupPduCoder *niProtocol :: getIAMCoder(void)
{
    if(_IAMCoder == 0)
    {
        _IAMCoder = new bisupIAMCoder;
    }
    return _IAMCoder;
}

bisupPduCoder *niProtocol :: getIAACoder(void)
{
    if(_IAACoder == 0)
    {
        _IAACoder = new bisupIAACoder;
    }
    return _IAACoder;
}

bisupPduCoder *niProtocol :: getIARCoder(void)
{
    if(_IARCoder == 0)
    {
        _IARCoder = new bisupIARCoder;
    }
    return _IARCoder;
}

bisupPduCoder *niProtocol :: getACMCoder(void)
{
    if(_ACMCoder == 0)
    {
        _ACMCoder = new bisupACMCoder;
    }
    return _ACMCoder;
}

bisupPduCoder *niProtocol :: getCPGCoder(void)
{
    if(_CPGCoder == 0)
    {
        _CPGCoder = new bisupCPGCoder;
    }
    return _CPGCoder;
}

bisupPduCoder *niProtocol :: getANMCoder(void)
{
    if(_ANMCoder == 0)
    {
        _ANMCoder = new bisupANMCoder;
    }
    return _ANMCoder;
}

bisupPduCoder *niProtocol :: getRELCoder(void)
{
    if(_RELCoder == 0)
    {
        _RELCoder = new bisupRELCoder;
    }
    return _RELCoder;
}

bisupPduCoder *niProtocol :: getRLCCoder(void)
{
    if(_RLCCoder == 0)
    {
        _RLCCoder = new bisupRLCCoder;
    }
    return _RLCCoder;
}


//
//Function: isMuxKeyAllocated
//
//Description:
//    Uses pfKeyQueryTransporter to find out if the given key
//    is allocated in the mux above or not. Returns non-zero if
//    allocated.
//

pfBoolean niProtocol :: isMuxKeyAllocated(const pfKey key_)
{
    pfKeyQueryTransporter keyQuery =
        pfKeyQueryTransporter::createKeyQueryTransporter(key_);
    toB(&keyQuery);
    pfBoolean result = keyQuery.keyAllocatedStatus();
    return result;
}

//
//Function: getDISDI / getOSID
//
//Description:
//      Get Destination(Origination Signalling Identifier from
//      the primitive. DSID will be removed from the primitive.
//

pfUlong niProtocol :: getDSID(pfMessenger *msg_) const
{
    // ++TODO++ delete ie, not useful to bo to bisup
    pfIE *ieRef = msg_->getIE(ieDSIDStr);
    ieCallReference *ie = ieCallReference::narrow(ieRef);
    pfUlong DSID = ie->getValue();
    return DSID;
}

pfUlong niProtocol :: getOSID(pfMessenger *msg_) const
{
    pfIE *ieRef = msg_->getIE(ieOSIDStr);
    ieCallReference *ie = ieCallReference::narrow(ieRef);
    pfUlong OSID = ie->getValue();
    return OSID;
}


//
//Function: toBisup
//
//Description:
//      Sends primitive to the correct bisup instance. This niProtocol
//      assings the new SID for the new BISUP, if there was no DSID in the
//      message, by the OSID. This is possible, since there is one ni-instance
//      for every link.
//

void niProtocol :: toBisup(pfMessenger *msg_)
{
    try
    {
        pfUlong DSID = getDSID(msg_);
        if (isMuxKeyAllocated(DSID) == 0)
        {
            debugUser("Requested bisup not present, creating new one!");
            // ++TODO++ check if this works in bisup
        }
        else
        {
            msg_->defineInteger(bisupMuxReferenceStr);
            msg_->setInteger(bisupMuxReferenceStr, DSID);
        }
        toB(msg_);
    }
    catch(pfException &exception) // no DSID in the message
    {
        (void)exception;
        try
        {
            pfUlong OSID;
            OSID = getOSID(msg_);
            debugUser("No DSID present, sending message to factory!");
            msg_->defineInteger(bisupMuxReferenceStr);
            msg_->setInteger(bisupMuxReferenceStr, OSID);
            toB(msg_);
        }
        catch(pfException &exception)
        {
            exception.printInfo();
            debugUser("No DSID or OSID present, discarding the message!");
        }
    }
    return;
}

void niProtocol :: sendACMtoMtp(pfMessenger *msg_)
{
    bisupPduCoder *ACM = getACMCoder();
    encodeAndSendToMtp(ACM, msg_);
    return;
}

void niProtocol :: sendANMtoMtp(pfMessenger *msg_)
{
    bisupPduCoder *ANM = getANMCoder();
    encodeAndSendToMtp(ANM, msg_);
    return;
}

void niProtocol :: sendCPGtoMtp(pfMessenger *msg_)
{
    bisupPduCoder *CPG = getCPGCoder();
    encodeAndSendToMtp(CPG, msg_);
    return;
}

void niProtocol :: sendIAAtoMtp(pfMessenger *msg_)
{
    bisupPduCoder *IAA = getIAACoder();
    encodeAndSendToMtp(IAA, msg_);
    return;
}

void niProtocol :: sendIARtoMtp(pfMessenger *msg_)
{
    bisupPduCoder *IAR = getIARCoder();
    encodeAndSendToMtp(IAR, msg_);
    return;
}

void niProtocol :: sendIAMtoMtp(pfMessenger *msg_)
{
    bisupPduCoder *IAM = getIAMCoder();
    encodeAndSendToMtp(IAM, msg_);
    return;
}

void niProtocol :: sendRELtoMtp(pfMessenger *msg_)
{
    bisupPduCoder *REL = getRELCoder();
    encodeAndSendToMtp(REL, msg_);
    return;
}

void niProtocol :: sendRLCtoMtp(pfMessenger *msg_)
{
    bisupPduCoder *RLC = getRLCCoder();
    encodeAndSendToMtp(RLC, msg_);
    return;
}

//
//Function: encodeAndSendToMtp
//
//Description:
//      Encode the received message with the given coder, and then sends
//      it to MTP3.
//

void niProtocol :: encodeAndSendToMtp(pduCoder *pduCoder_, pfMessenger *msg_)
{
    pfFrame frame;
    pduCoder_->encode(frame, msg_);
    sendTRANSFERreqToMtp(frame);
    return;
}
        

//
//Function: sendTRANSFERreqToMtp
//
//Description:
//      Sends a TRANSFERreq to mtp. DPC, OPC, SLS, and SIO are set
//      into the message.
//

void niProtocol :: sendTRANSFERreqToMtp(pfFrame &frame_)
{
    mtpTRANSFERreq *message = new mtpTRANSFERreq;
    message->setSignallingInformation(frame_);
    message->setDestinationPointCode(_DPC);
    message->setOriginatingPointCode(_OPC);
    message->setSignallingLinkSelection(_SLS);
    message->setServiceInformationOctet(_SIO);
    toA(message);
    return;
}
