//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / TRS
//
//File: managementclient.cpp
//
//Version: $Revision: 1.1 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/10/06 12:41:21 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Harri Sunila
//
//Description:
//      See corresponding header file
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//
//Licence:
//
//
//History: 

#include "managementclient.h"
#include "common/orbnamingservice.h"
#include "pf/exception.h"

//
// Function: trsManagementClient
//
// Description:
//     Initialize the trsManagementClient to operate to the network
//     networkPrefix_
//

trsManagementClient :: trsManagementClient(const string &networkPrefix_)
    : _networkPrefix(networkPrefix_),
      _routeServer(0)
{
    return;
}

//
// Function: ~trsManagementClient
//
// Description:  
//

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

//
// Function: registerNode
//
// Description:
//     Register a node in the TOVE Route Service
//

void trsManagementClient :: registerNode(const trsNode &node_)
{
    try
    {
        // Transform node
        trs_Node node;

        transformNode(node_,
                      node);

        // Register node
        getRouteServer()->registerNode(node);
    }
    catch(pfMethodFailed)
    {
        throw pfMethodFailed("Could not get object reference to RouteServer",
                             PF_EX_INFO);
    }
    catch(trs_InvalidAddress &)
    {
        throw pfMethodFailed("InvalidAddress exception", PF_EX_INFO);
    }
    catch(...)
    {
        // CORBA Exception
        throw pfMethodFailed("CORBA Exception", PF_EX_INFO);
    }
    return;
}

//
// Function: unregisterNode
//
// Description:
//     Remove a node from the TOVE RouteService
//

void trsManagementClient :: unregisterNode(const trsNode &node_)
{
    try
    {
        // Transform node
        trs_Node node;

        transformNode(node_,
                      node);

        // Unregister node
        getRouteServer()->unregisterNode(node);
    }
    catch(pfMethodFailed)
    {
        throw pfMethodFailed("Could not get object reference to RouteServer",
                             PF_EX_INFO);
    }
    catch(trs_InvalidAddress)
    {
        throw pfMethodFailed("InvalidAddress exception", PF_EX_INFO);
    }
    catch(...)
    {
        // CORBA Exception
        throw pfMethodFailed("CORBA Exception", PF_EX_INFO);
    }
    return;
}

//
// Function: addLinks
//
// Description:
//     Add new links to an existing node in TOVE Route Service
//

void trsManagementClient :: addLinks(const trsNode &node_,
                                     const trsLinkList &additionalLinks_)
{
    try
    {
        // Transform node
        trs_Node node;

        transformNode(node_,
                      node);

        // Transform links
        trs_LinkList links;

        transformLinks(additionalLinks_,
                       links);
        
        // Add links
        getRouteServer()->addLinks(node,
                                   links);
    }
    catch(pfMethodFailed)
    {
        throw pfMethodFailed("Could not get object reference to RouteServer",
                             PF_EX_INFO);
    }
    catch(trs_InvalidAddress)
    {
        throw pfMethodFailed("InvalidAddress exception", PF_EX_INFO);
    }
    catch(...)
    {
        // CORBA Exception
        throw pfMethodFailed("CORBA Exception", PF_EX_INFO);
    }
    return;
}

//
// Function: removeLinks
//
// Description:
//     Remove links from an existing node in TOVE Route Service
//

void trsManagementClient :: removeLinks(const trsNode &node_,
                                        const trsLinkList &removableLinks_)
{
    try
    {
        // Transform node
        trs_Node node;

        transformNode(node_,
                      node);

        // Transform links
        trs_LinkList links;

        transformLinks(removableLinks_,
                       links);
        
        // Add links
        getRouteServer()->addLinks(node,
                                   links);
    }
    catch(pfMethodFailed)
    {
        throw pfMethodFailed("Could not get object reference to RouteServer",
                             PF_EX_INFO);
    }
    catch(trs_InvalidAddress)
    {
        throw pfMethodFailed("InvalidAddress exception", PF_EX_INFO);
    }
    catch(...)
    {
        // CORBA Exception
        throw pfMethodFailed("CORBA Exception", PF_EX_INFO);
    }
    return;
}

//
// Function: updateLinks
//
// Description:
//     Update the information of the links of an node in TOVE Route Service
//

void trsManagementClient :: updateLinks(const trsNode &node_,
                                        const trsLinkList &updatedLinks_)
{
    try
    {
        // Transform node
        trs_Node node;

        transformNode(node_,
                      node);

        // Transform links
        trs_LinkList links;

        transformLinks(updatedLinks_,
                       links);
        
        // Update links
        getRouteServer()->updateLinks(node,
                                      links);
    }
    catch(pfMethodFailed)
    {
        throw pfMethodFailed("Could not get object reference to RouteServer",
                             PF_EX_INFO);
    }
    catch(trs_InvalidAddress)
    {
        throw pfMethodFailed("InvalidAddress exception", PF_EX_INFO);
    }
    catch(...)
    {
        // CORBA Exception
        throw pfMethodFailed("CORBA Exception", PF_EX_INFO);
    }
    return;
}

// Private methods

//
// Function: transformXX
//
// Description:
//     Transform parameters from standard types to types used in RouteServer
//     CORBA interface
//

void trsManagementClient :: transformNode(const trsNode &from_,
                                          trs_Node &to_)
{
    // Prefix
    string prefix = from_.getPrefix();
    to_.prefix = prefix.c_str();

    // Links
    trsLinkList links = from_.getLinks();
    transformLinks(links,
                   to_.links);
    return;
};

void trsManagementClient :: transformLinks(const trsLinkList &from_,
                                           trs_LinkList &to_)
{
    trsLinkList::const_iterator i = from_.begin();
    trsLinkList::const_iterator end = from_.end();

    trs_Link *link;
    string destination;
    pfUlong linkNumber;
    pfStorage qosParameters;
    
    while(i != end)
    {
        link = new trs_Link;

        // Destination
        destination = (*i).getDestination();
        link->destination = destination.c_str();

        // Link number
        linkNumber = (*i).getLinkNumber();
        link->linkNumber = linkNumber;

        // Assigned QoS parameters of the link
        qosParameters = (*i).getQosParameters();
        transformParameters(qosParameters,
                            link->qosParameters);

        // Insert trs_Link link into the trs_LinkList to_
        to_.insert(*link);
        i++;
    }
    return;
}

void trsManagementClient :: transformParameters(pfStorage &from_,
                                                trs_ParameterList &to_)
{
    trs_Parameter *parameter;

    // Start from the begin
    from_.first();

    string name;

    while(from_.isDone() == 0)
    {
        // Transform the parameter

        // Get the name of the parameter 
        name = from_.currentItem();

        try
        {
            // Just for sure
            if((from_.isValuePresent(name) != 0) &&
               (from_.getType(name) == pfStorage::INTTYPE))
            {
                // Parameter has an assigned integer value
                parameter = new trs_Parameter;

                // Assign the parameter with name
                parameter->name = name.c_str();
                
                // Assign the parameter with value
                parameter->value = from_.getInteger(name);

                // Insert the parameter in to_
                to_.insert(*parameter);
            }
            // Advance
            from_.next();
        }
        catch(pfException)
        {
            // Should never happen
        }
    }
    return;
}

//
// Function: getRouteServer
//
// Description:
//     Get the RouteServer CORBA object. Use orbNamingService if _routeServer
//     is a nil object reference since this method has not called before.
//

trs_RouteServer_var trsManagementClient :: getRouteServer(void)
{
    if(CORBA_is_nil(_routeServer) != 0)
    {
        string serverNameString = "Routing/" + _networkPrefix;
        
        CosNaming_Name serverName =
            orbNamingService::parseName(serverNameString);

        CORBA_Object_var serverObject =
            orbNamingService::instance()->resolve(serverName);

        _routeServer = trs_RouteServer::_narrow(serverObject);
        
        if(CORBA_is_nil(_routeServer) != 0)
        {
            throw pfMethodFailed("TOVE Route Server is a nil object reference",
                                 PF_EX_INFO);
        }
    }
    return _routeServer;
}
