//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project
//
//File: example.cpp
//
//Version: $Revision: 1.5 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/12/16 16:57:24 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Harri Sunila
//
//Description:
//      A brief introduction to the use of gsmpConnectionManagement and
//      gsmpConfigurationManagement. 
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999 
//
//Licence:
//
//
//History: 

// The infrastructure to get GSMP running

// Common modules

#include <typeinfo>
#include <iostream.h>
#include <string>
#include "pf/conduit.h"
#include "pf/system.h"
#include "pf/atmsocket.h"
#include "pf/newtrace.h"
#include "trace/texttrace.h"

// Modules to get GSMP instantiated

#include "protocol/cpcs/cpcsaadapter.h"
#include "gsmpdefs.h"                   // constant GSMP_MTU
#include "gsmpadjacencyprotocol.h"
#include "gsmpprotocol.h"
#include "gsmpfactory.h"

#include <assert.h>
#include <unistd.h>

// Scheduling

#include "sf/fifoscheduler.h"
#include "pf/exception.h"
#include "sf/exception.h"

// To get GSMP running

#include "gsmpprimitives.h"

// To create and modify connections with GSMP we also need modules
// "gsmpConnectionManagement" and "gsmpConfigurationManagement".
// They are specified in modules gsmpconnectionmanagement.h and
// gsmpconfigurationmanagement.h, which are included in gsmpfactory.h.

// First setup the protocol stack.
//
//     +------------+   
//     |GSMP Factory|   GSMP Factory is an object, which creates
//     +------------+   management objects
//          |
//     +---------+
//     |  GSMP   |      Ipsilon's General Switch Management Protocol and...
//     +---------+      
//     |Adjacency|      ...adjacency protocol, which are implemented separately
//     +---------+      
//     |  CPCS   |      CPCS-adapter
//     +---------+
//

void setupGsmpProtocol(int port_,
                       int vci_,
                       int trace_)
{
    pfId id = 1;

    // Trace definitions
    if (trace_ != 0)
    {
        pfNewTrace::instance()->setTrace(tvTextTrace::create(), id);
    }

    // Socket Device for the signalling VCI
    pfDevice *cpcs = 0;
    pfATMsocket *atm = new cpcsATMAdapter(GSMP_MTU);
    assert(atm != 0);
    atm->openDevice(port_, 0, vci_);
    cpcs = atm;

    // GSMP protocol
    pfConduit gsmpProxy;
    try
    {
        gsmpProxy = gsmpProtocol::create();
    }

    // Adjacency Protocol
    pfConduit adjacencyProxy;
    try
    {
        adjacencyProxy = gsmpAdjacencyProtocol::create(port_);
    }
    catch (pfException &exception)
    {
        exception.printInfo();
        throw;
    }

    cpcs->readDevice();

    pfConduit cpcsProxy(cpcs);
    cpcsProxy.setId(id);
    adjacencyProxy.setId(id);
    gsmpProxy.setId(id);
    
    // Set trace on
    if (trace_ != 0)
    {
        cpcsProxy.setTraceOn();
        adjacencyProxy.setTraceOn();
    } 

    // Connect Conduits
    gsmpProxy.connectToA(adjacencyProxy);
    adjacencyProxy.connectToB(gsmpProxy);
    adjacencyProxy.connectToA(cpcsProxy);
    cpcsProxy.connectToA(adjacencyProxy);
    
    // Start Adjacency Protocol
    gsmpStartAdjacencyProtocol *transporter =
        gsmpStartAdjacencyProtocol::createGsmpStartAdjacencyProtocol();
    cout << "Starting GSMP Protocol..." << endl;
    adjacencyProxy.accept(transporter);

    // Create a gsmpFactory.
    gsmpFactory *factory = gsmpFactory::instance();
    if (factory != 0)
    {
        // Initialize the factory to use this GSMP instance
        factory->init(gsmpProxy);
    }
    return;
}

// GSMP must be initialized before any connections can be established.
// GSMP protocol initializes itself automatically after syncronization
// with the switch, but gsmpConfigurationManagement must be initialized. 

void initializeGsmp(void)
{
    gsmpConfigurationManagement manager(
        gsmpFactory::createConfigurationManagement());
    // Get the switchwide configuration. Not mandatory.
    manager.configureSwitch();  
    // Get the configuration for all ports. Mandatory
    manager.configureAllPorts();
    return;
}

void createConnection(pfUlong inputPort_,
                      pfUlong outputPort_,
                      veAckObj *ackObj_,
                      pfByte priority = 0)
{
    // First we must get a free VPI/VCI pair in both ports.
    gsmpPoint inputPoint(inputPort_);
    gsmpPoint outputPoint(outputPort_);

    // Bind the input point to get a free VPI/VCI pair.
    gsmpConfigurationManagement::bind(inputPoint);

    // Check that VPI and VCI are valid
    pfUlong VPI = inputPoint.getVPI();
    pfUlong VCI = inputPoint.getVCI();
    if ((VPI != gsmpPoint::GSMP_VPI_ANY) &&
        (VCI != gsmpPoint::GSMP_VCI_ANY))
    {
        // Create a new connection
        gsmpConnectionManagement connection(
            gsmpFactory::createConnectionManagement(ackObj_,
                                                    inputPort_,
                                                    VPI,
                                                    VCI));

        // Set the priority. Default is 0 (highest)
        connection.setPriority(priority);
        
        // Bind the output point and add the branch
        gsmpConfigurationManagement::bind(outputPoint);
        
        // Check that VPI and VCI are valid
        pfUlong VPI = outputPoint.getVPI();
        pfUlong VCI = outputPoint.getVCI();
        if ((VPI != gsmpPoint::GSMP_VPI_ANY) &&
            (VCI != gsmpPoint::GSMP_VCI_ANY))
        {
            // Add the output branch
            connection.addBranch(outputPort_,
                                 VPI,
                                 VCI);
        }
        // The connection and output point should probably be saved.
    }
    return;
}

void closeConnection(gsmpConnectionManagement &connection_,
                     gsmpPoint &outputPoint_)
{
    pfUlong port = outputPoint_.getPort();
    pfUlong VPI = outputPoint_.getVPI();
    pfUlong VCI = outputPoint_.getVCI();

    // Do not unbind the output point. GSMP (Connection Management) does it.

    // Delete the output branch.
    connection_.deleteBranch(port,
                             VPI,
                             VCI);
    return;
}
