//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / COMMON
//
//File: ss7configure.cpp
//
//Version: $Revision: 1.20 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/11/20 14:07:17 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Timo Pärnänen
// 
//Description:
//      See corresponding header file.
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//
//Licence:
//
//
//History: 
//
//

#include <assert.h>
#include "ss7configure.h"
#include "pf/debug.h"
#include "pf/error.h"

ss7Configure ss7ConfigureImplementation :: createSS7Configure(void)
{
    ss7Configure newConfigure(new ss7ConfigureImplementation);
    return newConfigure;
}

ss7ConfigureImplementation :: ss7ConfigureImplementation(void)
    : _pointCode(0),
      _sccpPresent(0),
      _bisupPresent(0),
      _tcapPresent(0),
      _inapPresent(0),
      _gtMap(),
      _pcMap(),
      _ssnMap(),
      _routingMap()
{
    return;
}

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

// Point code value of this signalling point

void ss7ConfigureImplementation :: setPointCode(pfUlong pointCode_)
{
    _pointCode = pointCode_;
    return;
}

pfUlong ss7ConfigureImplementation :: getPointCode(void) const
{
    return _pointCode;
}

// Routing table

pfUlong ss7ConfigureImplementation :: findAALid(pfUlong DPC_) const
{
    routingMapConstIterType item = _routingMap.find(DPC_);
    if (item == _routingMap.end())
    {
        THROW_NO_ROUTE_TO_DESTINATION;
    }
    return (*item).second;
}

//
//Function: configureRoutingTable
//
//Description:
//    Add AAL identifiers to routing map with pointcodes from
//    start index to stop index. Reconfiguration is supported,
//    and then old routes are replaces.
//

void ss7ConfigureImplementation :: configureRoutingTable(pfUlong start_,
                                                         pfUlong stop_,
                                                         pfUlong AALid_)
{
    if (start_ > stop_)
    {
        THROW_UNSUPPORTED_COMBINATION_OF_TRAFFIC_PARAMETERS;
    }

    pair<routingMapIterType, bool> p;
    for (pfUlong i=start_; i<=stop_; i++)
    {
        p = _routingMap.insert(routingMapType::value_type(i, AALid_));
        if (p.second == 0)
        {
            _routingMap.erase(p.first);
            _routingMap.insert(routingMapType::value_type(i, AALid_));
        }
    }
    return;
}

// Mapping table (for address translation)

bool ss7ConfigureImplementation :: translateAddress(string &GT_,
                                                         pfUlong &SSN_,
                                                         pfUlong &DPC_) const
{
    bool result = translateAddress(GT_, DPC_);
    integerMapConstIterType ssnItem = _ssnMap.find(GT_);        
    if (ssnItem != _ssnMap.end())
    {
        SSN_ = (*ssnItem).second;
        debugPfUlong("SSN (new)", SSN_);
    }
    return result;
}

bool ss7ConfigureImplementation :: translateAddress(string &GT_,
                                                    pfUlong &DPC_) const
{
    debugUser("======== ADDRESS TRANSLATION ==========");
    debugString("GT (old)", GT_);
    bool result = 0;
    integerMapConstIterType pcItem = _pcMap.find(GT_);
    if (pcItem != _pcMap.end())
    {
        result = 1;
        DPC_ = (*pcItem).second;
	debugPfUlong("DPC (new)", DPC_);

        stringMapConstIterType gtItem = _gtMap.find(GT_);
        if (gtItem != _gtMap.end())
        {
            GT_ = (*gtItem).second;
	    debugString("GT (new)", GT_);
        }
    }
    return result;
}

//
//Function: Address transformation table configuration methods.
//
//Description:
//    Configure address transformation tables. Reconfiguration is 
//    supported, and then old definitions are replaced.
//

void ss7ConfigureImplementation :: addGTtoPCandSSN(string GT_,
                                                   pfUlong DPC_,
                                                   pfUlong SSN_)
{
    // GT -> DPC
    addGTtoPC(GT_, DPC_);

    // GT -> SSN
    addGTtoSSN(GT_, SSN_);
    return;
}

void ss7ConfigureImplementation :: addGTtoPC(string GT_, pfUlong DPC_)
{
    // GT -> DPC
    pair<integerMapIterType, bool> p;
    p = _pcMap.insert(integerMapType::value_type(GT_, DPC_));
    if (p.second == 0)
    {
        _pcMap.erase(p.first);
        // Use recursion
        addGTtoPC(GT_, DPC_);
    }
    return;
}

void ss7ConfigureImplementation :: addGTtoPCandGT(string GT_,
                                                  pfUlong DPC_,
                                                  string newGT_)
{
    // GT -> DPC
    addGTtoPC(GT_, DPC_);

    // GT -> GT
    pair<stringMapIterType, bool> p;
    p = _gtMap.insert(stringMapType::value_type(GT_, newGT_));
    if (p.second == 0)
    {
        _gtMap.erase(p.first);
        _gtMap.insert(stringMapType::value_type(GT_, newGT_));
    }
    return;
}

void ss7ConfigureImplementation :: addGTtoSSN(string GT_, pfUlong SSN_)
{
    // GT -> SSN
    pair<integerMapIterType, bool> p;
    p = _ssnMap.insert(integerMapType::value_type(GT_, SSN_));
    if (p.second == 0)
    {
        _ssnMap.erase(p.first);
        // Use recursion
        addGTtoSSN(GT_, SSN_);
    }
    return;
}


// User parts (above MTP3)

void ss7ConfigureImplementation :: setSCCP(void)
{
    _sccpPresent = 1;
    return;
}

void ss7ConfigureImplementation :: setBISUP(void)
{
    _bisupPresent = 1;
    return;
}

bool ss7ConfigureImplementation :: isUserPartAvailable(
    pfUlong serviceIndicator_) const
{
    bool result = 0;
    if ((serviceIndicator_ == SCCP && _sccpPresent != 0) ||
        (serviceIndicator_ == BISUP && _bisupPresent != 0))
    {
        result = 1;
    }
    return result;
}

void ss7ConfigureImplementation :: setTCAP(void)
{
    _tcapPresent = 1;
    return;
}

void ss7ConfigureImplementation :: setINAP(void)
{
    _inapPresent = 1;
    return;
}

bool ss7ConfigureImplementation :: isSubSystemAvailable(
    pfUlong subSystemNumber_) const
{
    bool result = 0;
    if (subSystemNumber_ == INAP && _tcapPresent != 0 && _inapPresent != 0)
    {
        result = 1;
    }
    return result;    
}

//
//Fucntion: printConfigure
//
//Description:
//    Print current configure information to given output stream.
//    Get methods is used to get variable values because print method
//    is wanted to have same view as user to configuration values.
//

void ss7ConfigureImplementation :: printConfigure(ostream &stream_) const
{
    stream_ << "==================================" << endl;
    stream_ << "SS7 Configure values" << endl;
    stream_ << "----------------------------------" << endl;
    stream_ << "Point Code : " << getPointCode() << endl;
    stream_ << " - SCCP : ";
    printAvailableStatus(isUserPartAvailable(SCCP), stream_);
    stream_ << " - BISUP : ";
    printAvailableStatus(isUserPartAvailable(BISUP), stream_);    
    stream_ << " - INAP : ";
    printAvailableStatus(isSubSystemAvailable(INAP), stream_);
    stream_ << endl;
    stream_ << "Routing Table :" << endl;
    stream_ << "----------------" << endl;
    stream_ << "PC   :";

    for (routingMapConstIterType i = _routingMap.begin();
         i != _routingMap.end(); i++)
    {        
        stream_.width(3);
        stream_ << (*i).first;
    }
    stream_ << endl;
    stream_ << "AALid:";

    for (routingMapConstIterType j = _routingMap.begin();
         j != _routingMap.end(); j++)
    {
        stream_.width(3);
        stream_ << (*j).second;
    }
    stream_ << endl;
    stream_ << endl;
    stream_ << "Address Translation" << endl;
    stream_ << "-------------------" << endl;
    stream_ << " GT  ===>  DPC     GT    SSN" << endl;
    integerMapConstIterType item;
    for (item = _pcMap.begin(); item != _pcMap.end(); item++)
    {
        string GT = (*item).first;
        stream_ << GT << "\t    " << (*item).second;
        stringMapConstIterType gtItem = _gtMap.find(GT);
        if (gtItem != _gtMap.end())
        {
            stream_ << "\t  " << (*gtItem).second;
        }
	else
        {
            integerMapConstIterType ssnItem = _ssnMap.find(GT);
            if (ssnItem != _ssnMap.end())
            {
                stream_ << "\t\t  " << (*ssnItem).second;
            }
        }
        stream_ << endl;
    }
    stream_ << "==================================" << endl;
    return;
}

void ss7ConfigureImplementation ::
printAvailableStatus(bool present_, ostream &stream_) const
{
    if (present_ != 0)
    {
        stream_ << "Present" << endl;
    }
    else
    {
        stream_ << "Not present" << endl;
    }    
    return;
}

//----------------------------------------------------------------------
// Reference counter is not implemented. May be added in future.
// Implementation is not deleted in proxy destructor.
//

ss7Configure :: ss7Configure (ss7ConfigureImplementation *implementation_)
    : _implementation(implementation_)
{
    return;
}

ss7Configure :: ss7Configure(const ss7Configure &other_)
    : _implementation(other_._implementation)
{
    return;
}

ss7Configure :: ~ss7Configure(void)
{
    return;
}
        
const ss7Configure& ss7Configure :: operator = (const ss7Configure &other_)
{
    if (this != &other_) // if not x = x situation
    {
        _implementation = other_._implementation;
    }
    return *this;
}

// Point code value of this signalling point

void ss7Configure :: setPointCode(pfUlong pointCode_)
{
    if (_implementation != 0)
    {
        _implementation->setPointCode(pointCode_);
    }
    return;
}

pfUlong ss7Configure :: getPointCode(void) const
{
    pfUlong result = 0;
    if (_implementation != 0)
    {
        result = _implementation->getPointCode();
    }
    return result;
}

// Routing table

pfUlong ss7Configure :: findAALid(pfUlong DPC_) const
{
    pfUlong result = 0;
    if (_implementation != 0)
    {
       result = _implementation->findAALid(DPC_);
    }
    return result;
}

void ss7Configure :: configureRoutingTable(pfUlong start_,
                                           pfUlong stop_,
                                           pfUlong AALid_)
{
    if (_implementation != 0)
    {
        _implementation->configureRoutingTable(start_, stop_, AALid_);
    }
    return;
}

// Mapping table (for address translation)

bool ss7Configure :: translateAddress(string &GT_,
                                           pfUlong &SSN_,
                                           pfUlong &DPC_) const
{
    bool result = 0;
    if (_implementation != 0)
    {
        result = _implementation->translateAddress(GT_, SSN_, DPC_);
    }
    return result;
}

bool ss7Configure :: translateAddress(string &GT_,
                                           pfUlong &DPC_) const
{
    bool result = 0;
    if (_implementation != 0)
    {
        result = _implementation->translateAddress(GT_, DPC_);
    }
    return result;    
}

void ss7Configure :: addGTtoPCandSSN(string GT_,
                                     pfUlong DPC_,
                                     pfUlong SSN_)
{
    if (_implementation != 0)
    {
        _implementation->addGTtoPCandSSN(GT_, DPC_, SSN_);
    }
    return;
}

void ss7Configure :: addGTtoPC(string GT_, pfUlong DPC_)
{
    if (_implementation != 0)
    {
        _implementation->addGTtoPC(GT_, DPC_);
    }
    return;
}

void ss7Configure :: addGTtoPCandGT(string GT_,
                                    pfUlong DPC_,
                                    string newGT_)
{
    if (_implementation != 0)
    {
        _implementation->addGTtoPCandGT(GT_, DPC_, newGT_);
    }
    return;
}

void ss7Configure :: addGTtoSSN(string GT_,
                                pfUlong SSN_)
{
    if (_implementation != 0)
    {
        _implementation->addGTtoSSN(GT_, SSN_);
    }
    return;
}

// User parts (above MTP3)

void ss7Configure :: setSCCP(void)
{
    if (_implementation != 0)
    {
        _implementation->setSCCP();
    }
    return;
}

void ss7Configure :: setBISUP(void)
{
    if (_implementation != 0)
    {
        _implementation->setBISUP();
    }
    return;
}

bool ss7Configure :: isUserPartAvailable(pfUlong serviceIndicator_) const
{
    bool result = 0;
    if (_implementation != 0)
    {
        result = _implementation->isUserPartAvailable(serviceIndicator_);
    }
    return result;
}

void ss7Configure :: setTCAP(void)
{
    if (_implementation != 0)
    {
        _implementation->setTCAP();
    }
    return;
}

void ss7Configure :: setINAP(void)
{
    if (_implementation != 0)
    {
        _implementation->setINAP();
    }
    return;
}

bool ss7Configure :: isSubSystemAvailable(pfUlong subSystemNumber_) const
{
    bool result = 0;
    if (_implementation != 0)
    {
        result = _implementation->isSubSystemAvailable(subSystemNumber_);
    }
    return result;
}

// Print current configure

void ss7Configure :: printConfigure(ostream &stream_) const
{
    if (_implementation != 0)
    {
        _implementation->printConfigure(stream_);
    }
    return;
}

