//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / UNITEST
//
//File: unitestadapter.cpp
//
//Version: $Revision: 1.12 $
//
//State: $State: Exp $
//
//Date: $Date: 1999/01/25 13:09:01 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Jari Katajavuori
//
//Description:
//
//
//Copyright:
//
//
//Licence:
//
//
//History: 

#include "unitestadapter.h"

#include "protocol/uni/unistrings.h"

#include "pf/debug.h"

pfConduit uniTestAdapter :: createCommandConnection(string hostname_,
                                                    int localPort_,
                                                    int remotePort_,
                                                    pfUlong sduSize_)
{
    uniTestAdapter *udp = new uniTestAdapter(sduSize_);
    udp->openDevice(hostname_, localPort_, remotePort_);
    udp->readDevice();
    pfConduit uniTestProxy(udp);
    return uniTestProxy;
}

pfConduit uniTestAdapter :: createSelfoperateAdapter(string sourceAddr_,
                                                     string destAddr_,
                                                     pfUlong mode_)
{
    uniTestAdapter *udp = new uniTestAdapter(1);
    udp->setString("Destination Address", destAddr_);
    udp->setString("Source Address", sourceAddr_);
    udp->startTimer("TEST");

    debugPfUlong("Setting operating mode to ", mode_);
    udp->setOperatingMode(mode_);
    pfConduit uniTestProxy(udp);
    return uniTestProxy;
}

pfConduit uniTestAdapter :: createSelfoperateAdapter(string sourceAddr_,
                                                     pfUlong mode_)
{
    uniTestAdapter *udp = new uniTestAdapter(1);
    udp->setString("Source Address", sourceAddr_);

    debugPfUlong("Setting operating mode to ", mode_);
    udp->setOperatingMode(mode_);
    pfConduit uniTestProxy(udp);
    return uniTestProxy;
}

uniTestAdapter :: uniTestAdapter(pfUlong sduSize_)
    : pfUDPsocket(sduSize_),
      pfStorage(),
      _mode(FSR)
{
    defineTimer("TEST", uniTESTtimeout::create(), 5000);
    defineString("Destination Address");
    defineString("Source Address");
    defineStorage("Called Party Number");
    defineStorage("Calling Party Number");
    
    changeState(uniTestState::instance());
    return;
}

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

void uniTestAdapter :: readAction(pfFrame &frame_, pfUlong code_)
{
    debugFrame("Frame", frame_);
    debugPfUlong("Code", code_);

    if (frame_.length() > 0)
    {
        pfUlong id = frame_.getFirst();
        debugPfUlong("Tester: Identifier", id);

        switch (id)
        {
            case 5 :
                parseAndSendSETUPreq(frame_);
                break;

            case 77 :
                sendRELEASEreq();
                break;

            default:
                debugUser("Unspecified command.");
        }
    }
    else
    {
        debugUser("Dummy frame read!");
    }
    readDevice();
    return;
}

void uniTestAdapter :: writeAction(pfUlong)
{
    return;
}

void uniTestAdapter :: sendSETUPreq(void)
{
    sigSETUPreq *sr = new sigSETUPreq;
    string destAddr = getString("Destination Address");
    string sourAddr = getString("Source Address");

// defined in iface/sigif/sigprimitive.cpp : 
// sigPrimitive :: defineConnectionIdentifier
    sr->undefine(sigConnectionIdentifierStr);

    sr->getStorage(sigBroadbandLowLayerInfoStr)
        .undefine(sigBLLI_Layer2UserInfoStr);

    (*sr)[sigCalledPartyNumberStr].
        setString(sigCalledPartyNumber_DigitsStr, destAddr);
    pfStorage called = sr->getStorage(sigCalledPartyNumberStr);
    setStorage("Called Party Number", called);
    
    (*sr)[sigCallingPartyNumberStr].
        setString(sigCalledPartyNumber_DigitsStr, sourAddr);
    pfStorage calling = (*sr)[sigCallingPartyNumberStr];
    setStorage("Calling Party Number", calling);
    
    // NOTE! The symbols FORE and FSR are misleading since they mean 
    // whether the connection is PMP (FSR) or PP (FORE). This is due to
    // the fact that FORE needs some parameters which are not PMP or PP
    // specific. This name conflict can be changed easily.

    if (_mode == FSR)
    {
        sr->defineInteger(sigEndpointReferenceStr);
        sr->setInteger(sigEndpointReferenceStr, 0);
    }

    // PMP connection -> value is 1; PP connection -> value is 0
    if (_mode == FORE)
    {
        (*sr)[sigBroadbandBearerCapabilityStr].setInteger(
            sigBBC_UserPlaneConnectionConfigurationStr, 0);
    }
    else
    {
        (*sr)[sigBroadbandBearerCapabilityStr].setInteger(
            sigBBC_UserPlaneConnectionConfigurationStr, 1);
    }

    (*sr)[sigATDStr].setInteger(sigATD_BackwardPeakCellRateCLP1Str, 0);
    
    toA(sr);
    return;
}

void uniTestAdapter :: parseAndSendSETUPreq(pfFrame &frame_)
{
    sigSETUPreq *sr = new sigSETUPreq;
    sr->undefine(sigConnectionIdentifierStr);
    sr->undefine(sigBroadbandLowLayerInfoStr);
    
    // Called Address
    int calledLen = frame_.getFirst();
    string tmp;
    for (int i=0; i<calledLen; i++)
    {
        tmp.append(1, frame_.getFirst());
    }
    sr->getStorage(sigCalledPartyNumberStr).
        setString(sigCalledPartyNumber_DigitsStr, tmp);
    
    // Calling Address
    int callingLen = frame_.getFirst();
    if (callingLen != 0)
    {
        tmp = "";
        for (int i=0; i<callingLen; i++)
        {
            tmp.append(1, frame_.getFirst());
        }
        sr->getStorage(sigCallingPartyNumberStr).
            setString(sigCalledPartyNumber_DigitsStr, tmp);
    } else 
    {
        sr->undefine(sigCallingPartyNumberStr);
    }
    
    // Qos
    sr->getStorage(sigQoSParametersStr).
        setInteger(sigQoS_ForwardStr, frame_.getFirst());
    sr->getStorage(sigQoSParametersStr).
        setInteger(sigQoS_BackwardStr, frame_.getFirst());

    // BBC
    pfStorage &bbc = sr->getStorage(sigBroadbandBearerCapabilityStr);
    bbc.setInteger(sigBBC_BearerClassStr, frame_.getFirst());
    bbc.setInteger(sigBBC_TrafficTypeStr, frame_.getFirst());
    bbc.setInteger(sigBBC_TimingRequirementsStr, frame_.getFirst());
    bbc.setInteger(sigBBC_SusceptibilityToClippingStr, frame_.getFirst());
    int multipoint = frame_.getFirst();
    bbc.setInteger(sigBBC_UserPlaneConnectionConfigurationStr,
                   multipoint);
    
    // ATD
    pfStorage &atd = sr->getStorage(sigATDStr);
    int pcr0 = frame_.getFirst24bit();
    int pcr1 = frame_.getFirst24bit();
    int scr0 = frame_.getFirst24bit();
    int scr1 = frame_.getFirst24bit();                
    int mbs0 = frame_.getFirst24bit();
    int mbs1 = frame_.getFirst24bit();
    int be = frame_.getFirst();
    int tf = frame_.getFirst();
    int tb = frame_.getFirst();
    
    atd.setInteger(sigATD_ForwardPeakCellRateCLP1Str, pcr1);
    
    if ((be != 0) && (multipoint == 0))
    {
        atd.setBooleanTrue(sigATD_BestEffortStr);
        atd.setInteger(sigATD_BackwardPeakCellRateCLP1Str, pcr1);
    } else
    {
        pfBoolean taggingPossible = 0;
        if (pcr0 != 0)
        {
            atd.setInteger(sigATD_ForwardPeakCellRateCLP0Str, pcr0);
            taggingPossible = 1;
        } else if (scr0 != 0)
        {
            atd.setInteger(sigATD_ForwardSustainableCLP0Str, scr0);
            atd.setInteger(sigATD_ForwardMaxBurstSizeCLP0Str, mbs0);
            taggingPossible = 1;
        } else if (scr1 != 0)
        {
            atd.setInteger(sigATD_ForwardSustainableCLP1Str, scr1);
            atd.setInteger(sigATD_ForwardMaxBurstSizeCLP1Str, mbs1);
        }
        if ((taggingPossible != 0) && (tf != 0))
        {
            atd.setBooleanTrue(sigATD_TaggingForwardStr);
        } else
        {
            atd.setBooleanFalse(sigATD_TaggingForwardStr);
        }
        
        if (multipoint == 0)
        {
            atd.setInteger(sigATD_BackwardPeakCellRateCLP1Str, pcr1);
            pfBoolean taggingPossibleB = 0;
            if (pcr0 != 0)
            {
                atd.setInteger(sigATD_BackwardPeakCellRateCLP0Str,
                               pcr0);
                taggingPossibleB = 1;
            } else if (scr0 != 0)
            {
                atd.setInteger(sigATD_BackwardSustainableCLP0Str,
                               scr0);
                atd.setInteger(sigATD_BackwardMaxBurstSizeCLP0Str,
                               mbs0);
                taggingPossibleB = 1;
            } else if (scr1 != 0)
            {
                atd.setInteger(sigATD_BackwardSustainableCLP1Str,
                               scr1);
                atd.setInteger(sigATD_BackwardMaxBurstSizeCLP1Str,
                               mbs1);
            }
            if ((taggingPossibleB != 0) && (tb != 0))
            {
                atd.setBooleanTrue(sigATD_TaggingBackwardStr);
            } else
            {
                atd.setBooleanFalse(sigATD_TaggingBackwardStr);
            }
        }
    }
    
    // Endpoint Reference
    
    if (multipoint != 0)
    {
        sr->defineInteger(sigEndpointReferenceStr);
        sr->setInteger(sigEndpointReferenceStr, frame_.getFirst16bit());   
    }
    
    // Send it
    toA(sr);
}

void uniTestAdapter :: sendPROCEEDINGreq(pfStorage &storage_)
{
    sigPROCEEDINGreq *pr = new sigPROCEEDINGreq;
    //pr->setStorage(sigConnectionIdentifierStr,
    //               storage_[sigConnectionIdentifierStr]);
    pr->undefine(sigConnectionIdentifierStr);
    toA(pr);
    return;
}

void uniTestAdapter :: sendSETUPresp(pfStorage &storage_)
{
    sigSETUPresp *sr = new sigSETUPresp;

    //sr->setStorage(sigConnectionIdentifierStr,
    //               storage_[sigConnectionIdentifierStr]);
    toA(sr);
    return;
}

void uniTestAdapter :: sendRELEASEreq(void)
{
    sigRELEASEreq *rr = new sigRELEASEreq;
    (*rr)[sigCauseStr].setInteger(sigCause_LocationStr, 0);
    (*rr)[sigCauseStr].setInteger(sigCause_ValueStr, 10);
    toA(rr);
    return;
}

void uniTestAdapter :: sendRELEASEresp(pfStorage &storage_)
{
    sigRELEASEresp *rr = new sigRELEASEresp;
    rr->setStorage(sigCauseStr, storage_[sigCauseStr]);
    toA(rr);
    return;
}

void uniTestAdapter :: sendADD_PARTYreq(void)
{
    uniADD_PARTYreq *ar = uniADD_PARTYreq::create();
    string destAddr = getString("Destination Address");
    string sourAddr = getString("Source Address");

    ar->defineStorage(sigCalledPartyNumberStr);
    // ++test++
    // ar->setStorage(sigCalledPartyNumberStr,
    //                getStorage("Called Party Number"));
    pfStorage cpn = getStorage("Called Party Number");
    string num("47.0005.80FFE1000000F21A26D8.0020EA000EE0.11");
    cpn.setString(sigCalledPartyNumber_DigitsStr, num);
    ar->setStorage(sigCalledPartyNumberStr, cpn);
    // ++end test++
    
    ar->defineStorage(sigCallingPartyNumberStr);
    ar->setStorage(sigCallingPartyNumberStr,
                   getStorage("Calling Party Number"));

    ar->defineInteger(sigEndpointReferenceStr);
    ar->setInteger(sigEndpointReferenceStr, 123);
    toA(ar);
    return;
}

void uniTestAdapter :: sendDROP_PARTYreq(void)
{
    uniDROP_PARTYreq *dr = uniDROP_PARTYreq::create();
    toA(dr);
    return;
}

void uniTestAdapter :: setOperatingMode(pfUlong mode_)
{
    _mode=mode_;
    return;
}
