//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / TCAP
//
//File: tcapadapter.cpp
//
//Version: $Revision: 1.4 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/12/16 14:01:35 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author: 
//      Timo Pärnänen
//
//Description:
//      See corresponding header file.
//
//Copyright:
//
//
//Licence:
//
//
//History: 

#include <string>
//#include <limits.h>
#include <stdio.h>
#include "tcapadapter.h"
#include "sf/orbscheduler.h"
#include "pf/naming.h"
#include "pf/conduit.h"
#include "iface/sccpif/sccpdownprimitives.h"
#include "tcapstate.h"

#include "tcap.h"

//
//Function: creatTCAP
//      
//Description:
//    Static create method creates implementation of TCAP
//    adapter and return proxy to implementation.
//

pfConduit tcapAdapter :: createTCAP(pfUlong pointCode_)
{
    // Create implementation
    tcapAdapter *newAdapter = new tcapAdapter(pointCode_);

    char instanceId[10];
    sprintf(instanceId, "%ld", pointCode_);

    //
    // Create name structure for adapter
    //
    CosNaming_Name name;
    name.length(2);
    name[0].id = CORBA_string_dup(instanceId);
    name[0].kind = CORBA_string_dup("");
    name[1].id = CORBA_string_dup("TCAPadapter");
    name[1].kind = CORBA_string_dup("");    

    try
    {
        pfNaming::instance()->bind(name, newAdapter);
    }
    catch (CORBA_UserException &exception)
    {
        // Exception deletion must be done due to compiler's
        // buggy exception handling
        delete &exception;

        cerr << "tcapAdapter: bind to NS failed" << endl;
        exit(1);
    }

    pfConduit proxy(newAdapter);
    return proxy;
}

//
//Functions: constructor and destructor
//
//Description:
//    Implements default constructor and destructor.
//

tcapAdapter :: tcapAdapter(pfUlong pointCode_)
    : tcap_tcapDown_skel(),
      pfAdapter(),
      _tcap(0),
      _pointCode(pointCode_)
{
    changeState(tcapState::instance());
    return;
}

tcapAdapter :: ~tcapAdapter(void)
{
    char instanceId[10];
    sprintf(instanceId, "%ld", _pointCode);

    CosNaming_Name name;
    name.length(2);
    name[0].id = CORBA_string_dup(instanceId);
    name[0].kind = CORBA_string_dup("");
    name[1].id = CORBA_string_dup("TCAPprotocol");
    name[1].kind = CORBA_string_dup("");    
    
    try
    {
        pfNaming::instance()->unbind(name);
    }
    catch (CORBA_UserException &exception)
    {
        // Exception deletion must be done due to compiler's
        // buggy exception handling
        delete &exception;        
        cerr << "tcapAdapter: unbind to NS failed" << endl;
    }

    return;
}

//
//Functions: Implemented IDL interface methods
//

//
// IDL:tcap/tcapDown/N_UNITDATAreq:1.0
//

void tcapAdapter :: N_UNITDATAreq(const tcap_AddressType &calledAddress_,
                                  const tcap_AddressType &callingAddress_,
                                  const tcap_UserDataType &userData_)
{
    pfStorage calledAddress = createAddress(calledAddress_);
    pfStorage callingAddress = createAddress(callingAddress_);

    pfFrame userData;
    int length = userData_.length();
    for (int i=0; i<length; i++)
    {
	// ++TODO++ CHECK: putLast or putFirst ?
        userData.putLast(userData_[i]);
    }
    
    sccpN_UNITDATAreq *messenger = new sccpN_UNITDATAreq;
    messenger->setCalledAddress(calledAddress);
    messenger->setCallingAddress(callingAddress);
    messenger->setUserData(userData);
    toA(messenger);
    return;
}

//
//Function: sendToTCAP
//
//Description:
//    Forward  "primitive" to CORBA object corresponding
//    dialogueID or to TCAP factory if object not foound.
//

void tcapAdapter :: sendToTCAP(tcap_AddressType calledAddress_,
                               tcap_AddressType callingAddress_,
                               tcap_UserDataType userData_)
{
    if (CORBA_is_nil(_tcap) != 0)
    {
        resolveIOR();
    }
    try
    {
        _tcap->N_UNITDATAind(calledAddress_,
                             callingAddress_,
                             userData_);
    }
    catch (...)
    {
        // Try to resolve IOR again
        resolveIOR();
        // Possibly exceptions are catched in tcapState
        _tcap->N_UNITDATAind(calledAddress_,
                             callingAddress_,
                             userData_);
    }
    return;
}

// private methods

void tcapAdapter :: resolveIOR(void)
{
    char instanceId[10];
    sprintf(instanceId, "%ld", _pointCode);
            
    //
    // Create name structure for factory
    //
    CosNaming_Name name;
    name.length(2);
    name[0].id = CORBA_string_dup(instanceId);
    name[0].kind = CORBA_string_dup("");
    name[1].id = CORBA_string_dup("TCAPprotocol");
    name[1].kind = CORBA_string_dup("");    
            
    try
    {
        _tcap = tcap_tcapUp::_narrow(pfNaming::instance()->resolve(name));
    }
    catch (CORBA_UserException &exception)
    {
        // Exception deletion must be done due to compiler's
        // buggy exception handling
        delete &exception;
        
        cerr << "tcapAdapter: resolve to NS failed" << endl;
        exit(1);
    }
    return;
}

//
//Function: createAddress
//
//Description:
//    Method transforms user defined CORBA IDL addresss
///   type to pfStorage type address.
//

pfStorage tcapAdapter :: createAddress(const tcap_AddressType &idlAddress_)
{
    pfStorage address;
    address.defineInteger("routingIndicator");
    address.defineInteger("pointCode");
    address.defineInteger("subSystemNumber");
    address.defineString("globalTitle");
    tcap_RoutingType type = idlAddress_.routingIndicator;
    
    if (type & 1)
    {
        address.setInteger("pointCode",
                           (long)idlAddress_.pointCode);
    }
    if (type & 2)
    {
        address.setInteger("subSystemNumber",
                           (long)idlAddress_.subSystemNumber);
    }
    if (type & 4)
    {
        string globalTitle(idlAddress_.globalTitle);
        address.setString("globalTitle", globalTitle);
    }
    return address;
}





