//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / gsmpswitch
//
//File: gsmpswitchprotocol.cpp
//
//Version: $Revision: 1.1 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/08/03 11:40:43 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Sami Raatikainen
//
//Description:
//      See the corresponding header file.
//
//Copyright:
//
//
//Licence:
//
//
//History: 

#include "gsmpswitchprotocol.h"
#include "gsmpswitchidlestate.h"
#include "gsmpswitchactivestate.h"
#include "protocol/gsmp/gsmpconfigurationmessages.h"
#include "protocol/gsmp/gsmpconnectionmanagementmessages.h"
#include "protocol/gsmp/gsmpinternalmessages.h"
//#include "gsmpportmanagementmessages.h"
//#include "protocol/gsmp/gsmpport.h"
//#include "protocol/gsmp/gsmppoint.h"

#include <time.h>
#include "gsnprotocol.h"
#include "gsnmessage.h"



//
// Class: gsmpSwitchProtocol
//
// Description: 
//


//
// Function: create 
//
// Description:
//     A static method to create a new protocol
//

pfConduit gsmpSwitchProtocol :: create(void) throw (pfMemoryAllocationException)
{
    gsmpSwitchProtocol *protocol = new gsmpSwitchProtocol;
    if (protocol == 0)
    {
        throw pfMemoryAllocationException(PF_EX_INFO,
                                          sizeof(gsmpSwitchProtocol));
    }
    pfConduit conduit = pfConduit(protocol);
    return conduit;
}

//
// Function: gsmpSwitchProtocol 
//
// Description:
//     Constructor
//

gsmpSwitchProtocol :: gsmpSwitchProtocol(void)
    : pfProtocol(),
      _connectionMap(),
      _portDataMap()
{
    toGsmpSwitchIdleState();
    return;
}

//
// Function: gsmpSwitchProtocol
//
// Description:
//     Copy constructor
//

gsmpSwitchProtocol :: gsmpSwitchProtocol(const gsmpSwitchProtocol &other_)
    : pfProtocol(other_),
      _connectionMap(other_._connectionMap),
      _portDataMap(other_._portDataMap)
{
    toGsmpSwitchIdleState();
    return;
}

//
// Function: ~gsmpSwitchProtocol
//
// Description:  
//     Destructor
//

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

//
// Function: clone
//
// Description:  
//

pfProtocol *gsmpSwitchProtocol :: cloneImplementation(void)
    throw (pfMemoryAllocationException)
{
    pfProtocol *newProtocol = new gsmpSwitchProtocol(*this);
    if (newProtocol == 0)
    {
        throw pfMemoryAllocationException(PF_EX_INFO,
                                          sizeof(gsmpSwitchProtocol));
    }
    return newProtocol;
}


//
// Function: toGsmpSwitchIdleState
//
// Description:
//     Change state to idle state.
//

void gsmpSwitchProtocol :: toGsmpSwitchIdleState(void)
{
    changeState(gsmpSwitchIdleState::instance());
    cout << "GsmpSwitchProtocol: To 'Idle' state" << endl;
    return;
}


//
// Function: toGsmpSwitchActiveState
//
// Description:
//     Change state to active state.
//

void gsmpSwitchProtocol :: toGsmpSwitchActiveState(void)
{
    changeState(gsmpSwitchActiveState::instance());
    initializePorts();
    cout << "GsmpSwitchProtocol: To 'Active' state" << endl;
    return;
}


//
// Function: initializePorts
//
// Description:
//     Set configuration values for all ports
//

void gsmpSwitchProtocol :: initializePorts(void)
{
    srand(time(0));
    pfUlong portSessionNumber;
    pfUlong port;
    
    // loop while (port = ??? )
    for (port=1; port<8; port++)
    {
        pfUlong minVPI = 0;
        pfUlong maxVPI = 0;
        pfUlong minVCI = 32;
        pfUlong maxVCI = 65535;
        pfUlong cellrate = 1;
        pfByte portStatus = 1;  // 1 = available
        pfByte portType = 39;   // 39 = GSMP_IF_SDH
        pfByte lineStatus = 1;  // 1 = up
        pfByte priorities = 0;  // 0 = highest priority
        
        if (portExists(port) == 0)
        {
            makeConfigurationEntry(port);
        }
        portSessionNumber = rand();
        setPortSessionNumber( port, portSessionNumber );
        setVPIRange( port, minVPI, maxVPI );
        setVCIRange( port, minVCI, maxVCI );
        setCellRate( port, cellrate );
        setPortStatus( port, portStatus );
        setPortType( port, portType );
        setLineStatus( port, lineStatus );
        setPriorities( port, priorities );
        cout << "initialized" << endl;
    }
    // end loop
    
    return;
}


//
// Function: addBranch
//
// Description:
//     Add new connection
//

pfBoolean gsmpSwitchProtocol :: addBranch(gsmpAddBranchMessage *message_)
{
    cout << "gsmpSwitchProtocol: addBranch" << endl;
    pfBoolean returnValue = true;
    gsmpAddBranchMessage *message;
    try
    {
        message = message_->clone();
    }
    catch (pfException &exception)
    {
        exception.printInfo();
        throw;
    }
    pfUlong inputPort = message->getInteger("_inputPort");
    pfUlong inputVPI = message->getInteger("_inputVPI");
    pfUlong inputVCI = message->getInteger("_inputVCI");
    pfUlong outputPort = message->getInteger("_outputPort");
    pfUlong outputVPI = message->getInteger("_outputVPI");
    pfUlong outputVCI = message->getInteger("_outputVCI");

    gsmpPoint inputPoint(inputPort);
    inputPoint.setVPI(inputVPI);
    inputPoint.setVCI(inputVCI);

    // create new gsnProxy and add it to the map
//    pfConduit gsnProxy = gsnProtocol::createGsnProtocol(inputVCI,
//                                                        inputVPI,
//                                                        inputPort,
//                                                        outputVPI,
//                                                        outputVCI,
//                                                        outputPort);
    pfConduit gsnProxy;    
    try
    {
        gsnProxy = gsnProtocol::createGsnProtocol(inputVCI,
                                                  inputVPI,
                                                  inputPort,
                                                  outputVPI,
                                                  outputVCI,
                                                  outputPort);
    }
    catch (pfException &exception)
    {
        exception.printInfo();
        throw;
    }
    
    addGsnProxy( inputPoint, gsnProxy );    
    return returnValue;
}


//
// Function: deleteBranch
//
// Description:
//     Delete specified connection
//

pfBoolean gsmpSwitchProtocol :: deleteBranch(gsmpDeleteBranchMessage *message_)
{
    cout << "gsmpSwitchProtocol: deleteBranch" << endl;
    pfBoolean returnValue = true;
    gsmpDeleteBranchMessage *message;
    try
    {
        message = message_->clone();
    }
    catch (pfException &exception)
    {
        exception.printInfo();
        throw;
    }
    pfUlong inputPort = message->getInteger("_inputPort");
    pfUlong inputVPI = message->getInteger("_inputVPI");
    pfUlong inputVCI = message->getInteger("_inputVCI");
//    pfUlong outputPort = message->getInteger("_outputPort");
//    pfUlong outputVPI = message->getInteger("_outputVPI");
//    pfUlong outputVCI = message->getInteger("_outputVCI");
    
    gsmpPoint inputPoint(inputPort);
    inputPoint.setVPI(inputVPI);
    inputPoint.setVCI(inputVCI);
    
    removeGsnProxy(inputPoint);
    
    return returnValue;
}


//
// Function: deleteAll
//
// Description: 
//     Delete all connections on specified input port      
//

pfBoolean gsmpSwitchProtocol :: deleteAll(pfUlong port_)
{
    cout << "gsmpSwitchProtocol: deleteAll" << endl;
    pfBoolean returnValue = true;
    gsmpPoint iterationPoint;
    gsnIterator i = _connectionMap.begin();
    
    while (i != _connectionMap.end())
    {
        iterationPoint = (*i).first;
        if (iterationPoint.getPort() == port_)
        {
            pfConduit gsnProxy = (*i).second; 
            gsnDisconnectMessage disconnecter =
                gsnDisconnectMessage::createDisconnectMessage();
            gsnProxy.accept(&disconnecter);
            _connectionMap.erase(i);
        }
        ++i;
    }
    
    return returnValue;
}



//
// Function: addProxy
//
// Description:
//     Add new gsnProxy to the _connectionMap.
//

void gsmpSwitchProtocol :: addGsnProxy(gsmpPoint &point_,
                                       pfConduit &gsnProxy_)
{
    _connectionMap.insert(gsnValue(point_, gsnProxy_));
    cout << "  ...new gsnProxy inserted(?) to _connectionMap" << endl;
    return;
}


//
// Function: removeProxy
//
// Description:
//     Remove gsnProxy from the _connectionMap.
//

void gsmpSwitchProtocol :: removeGsnProxy(gsmpPoint &point_)
{
    gsnIterator i = _connectionMap.find(point_);
    if (i != _connectionMap.end())
    {
        // use gsnProtocol's method to delete cpcs-adapters
        pfConduit gsnProxy = (*i).second;        
        gsnDisconnectMessage disconnecter =
            gsnDisconnectMessage::createDisconnectMessage();
        gsnProxy.accept(&disconnecter);
        // Remove the old reference and the map item
        //        pfConduit nilConduit;
        //        (*i).second = nilConduit;
        _connectionMap.erase(i);
    }    
    cout << "  ...gsnProxy removed(?) from _connectionMap" << endl;
    return;
}



//
// Function: portExists
//
// Description:  
//     Return true, if port exits
//

pfBoolean gsmpSwitchProtocol :: portExists(pfUlong portNumber_) const
{
    pfBoolean returnValue = false;
    constConfigurationIterator i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
        returnValue = true;
    }
    return returnValue;
}

//
// Function: makeConfigurationEntry
//
// Description:
//     Make a new entry for configuration information with specified port number.
//

void gsmpSwitchProtocol :: makeConfigurationEntry(pfUlong portNumber_)
{
    pfStorage storage;
    storage.defineInteger("_portSessionNumber");
    storage.defineInteger("_minVPI");
    storage.defineInteger("_maxVPI");
    storage.defineInteger("_minVCI");
    storage.defineInteger("_maxVCI");
    storage.defineInteger("_cellRate");
    storage.defineInteger("_portStatus");
    storage.defineInteger("_portType");
    storage.defineInteger("_lineStatus");
    storage.defineInteger("_priorities");
    _portDataMap.insert(configurationValue(portNumber_, storage));
    cout << "gsmpSwitch: Port " << portNumber_ << " added, ";
    return;
}

//
// Function: getPortSessionNumber
//
// Description:  
//     Return port session number for specified port. Return 0 if the specified port
//     does not exist.
//
                     
pfUlong gsmpSwitchProtocol :: getPortSessionNumber(pfUlong portNumber_) const
{
    pfUlong portSessionNumber = 0;
    constConfigurationIterator i;
    i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
        portSessionNumber = (*i).second.getInteger("_portSessionNumber");
    }
    return portSessionNumber;
}

//
// Function: setPortSessionNumber
//
// Description:  
//

void gsmpSwitchProtocol :: setPortSessionNumber(pfUlong portNumber_,
                                          pfUlong portSessionNumber_)
{
    configurationIterator i;
    i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
        (*i).second.setInteger("_portSessionNumber", portSessionNumber_);
    }
    return;
}

//
// Function: setVPIRange 
//
// Description:  
//

void gsmpSwitchProtocol :: setVPIRange(pfUlong portNumber_,
                                 pfUlong minVPI_,
                                 pfUlong maxVPI_)
{
    configurationIterator i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
        (*i).second.setInteger("_minVPI", minVPI_);
        (*i).second.setInteger("_maxVPI", maxVPI_);
    }
    return;
}

//
// Function: getMinVPI
//
// Description:  
//
                     
pfUlong gsmpSwitchProtocol :: getMinVPI(pfUlong portNumber_) const
{
    pfUlong minVPI;
    constConfigurationIterator i;
    i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
       minVPI = (*i).second.getInteger("_minVPI");
    }
    return minVPI;
}

//
// Function: getMaxVPI
//
// Description:  
//
                     
pfUlong gsmpSwitchProtocol :: getMaxVPI(pfUlong portNumber_) const
{
    pfUlong maxVPI;
    constConfigurationIterator i;
    i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
       maxVPI = (*i).second.getInteger("_maxVPI");
    }
    return maxVPI;
}

//
// Function: setVCIRange 
//
// Description:  
//

void gsmpSwitchProtocol :: setVCIRange(pfUlong portNumber_,
                                 pfUlong minVCI_,
                                 pfUlong maxVCI_)
{
    configurationIterator i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
        (*i).second.setInteger("_minVCI", minVCI_);
        (*i).second.setInteger("_maxVCI", maxVCI_);
    }
    return;
}

//
// Function: getMinVCI
//
// Description:  
//
                     
pfUlong gsmpSwitchProtocol :: getMinVCI(pfUlong portNumber_) const
{
    pfUlong minVCI;
    constConfigurationIterator i;
    i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
       minVCI = (*i).second.getInteger("_minVCI");
    }
    return minVCI;
}

//
// Function: getMaxVPI
//
// Description:  
//
                     
pfUlong gsmpSwitchProtocol :: getMaxVCI(pfUlong portNumber_) const
{
    pfUlong maxVCI;
    constConfigurationIterator i;
    i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
       maxVCI = (*i).second.getInteger("_maxVPI");
    }
    return maxVCI;
}

//
// Function: getCellRate
//
// Description:  
//
                     
pfUlong gsmpSwitchProtocol :: getCellRate(pfUlong portNumber_) const
{
    pfUlong cellRate;
    constConfigurationIterator i;
    i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
       cellRate = (*i).second.getInteger("_cellRate");
    }
    return cellRate;
}

//
// Function: setCellRate 
//
// Description:  
//

void gsmpSwitchProtocol :: setCellRate(pfUlong portNumber_,
                                 pfUlong cellRate_)
{
    configurationIterator i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
        (*i).second.setInteger("_cellRate", cellRate_);
    }
    return;
}

//
// Function: getPortStatus
//
// Description:  
//
                     
pfByte gsmpSwitchProtocol :: getPortStatus(pfUlong portNumber_) const
{
    pfByte portStatus;
    constConfigurationIterator i;
    i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
       portStatus = pfByte((*i).second.getInteger("_portStatus"));
    }
    return portStatus;
}

//
// Function: setPortStatus
//
// Description:  
//

void gsmpSwitchProtocol :: setPortStatus(pfUlong portNumber_,
                                   pfByte portStatus_)
{
    configurationIterator i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
        (*i).second.setInteger("_portStatus", portStatus_);
    }
    return;
}

//
// Function: getPortType
//
// Description:  
//
                     
pfByte gsmpSwitchProtocol :: getPortType(pfUlong portNumber_) const
{
    pfByte portType;
    constConfigurationIterator i;
    i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
       portType = pfByte((*i).second.getInteger("_portType"));
    }
    return portType;
}

//
// Function: setPortType
//
// Description:  
//

void gsmpSwitchProtocol :: setPortType(pfUlong portNumber_,
                                 pfByte portType_)
{
    configurationIterator i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
        (*i).second.setInteger("_portType", portType_);
    }
    return;
}

//
// Function: getLineStatus
//
// Description:  
//
                     
pfByte gsmpSwitchProtocol :: getLineStatus(pfUlong portNumber_) const
{
    pfByte lineStatus;
    constConfigurationIterator i;
    i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
       lineStatus = pfByte((*i).second.getInteger("_lineStatus"));
    }
    return lineStatus;
}

//
// Function: setLineStatus
//
// Description:  
//

void gsmpSwitchProtocol :: setLineStatus(pfUlong portNumber_,
                                   pfByte lineStatus_)
{
    configurationIterator i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
        (*i).second.setInteger("_lineStatus", lineStatus_);
    }
    return;
}

//
// Function: getPriorities
//
// Description:  
//
                     
pfByte gsmpSwitchProtocol :: getPriorities(pfUlong portNumber_) const
{
    pfByte priorities;
    constConfigurationIterator i;
    i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
       priorities = pfByte((*i).second.getInteger("_priorities"));
    }
    return priorities;
}

//
// Function: setPriorities
//
// Description:  
//

void gsmpSwitchProtocol :: setPriorities(pfUlong portNumber_,
                                   pfByte priorities_)
{
    configurationIterator i = _portDataMap.find(portNumber_);
    if (i != _portDataMap.end())
    {
        (*i).second.setInteger("_priorities", priorities_);
    }
    return;
}








