//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / testing/testadapter/uni
//
//File: unitest.cpp
//
//Version: $Revision: 1.3 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/08/20 15:07:44 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Timo Kokkonen
//
//Description:
//
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//
//Licence:
//
//
//History:
//
#include <typeinfo>
#include "pf/exception.h"
#include "pf/bytes.h"
#include "unipducoder.h"
#include <stdlib.h>
#include <string>
#include "pf/frame.h"
#include "pf/bitstring.h"
#include "pf/debug.h"
#include "testing/testadapter/adapter/msg.h"

void printUsage(string argv0_);
pfFrame decode_encode(pfFrame frame_);
void makeToFramePDUheader(pfUlong pduType_, pfFrame &frame_);
void makeToFrameCA_IE(pfFrame &frame_); // Cause
void makeToFrameCS_IE(pfFrame &frame_); // Call state
void makeToFrameAAL_IE(pfFrame &frame_); // ATM adaptation layer parameters
void makeToFrameATD_IE(pfFrame &frame_); // ATM traffic descriptor
void makeToFrameCI_IE(pfFrame &frame_); // Connection identifier
void makeToFrameQOS_IE(pfFrame &frame_); // Quality of service parameter
void makeToFrameBHL_IE(pfFrame &frame_); // Broadband high layer information
void makeToFrameBBC_IE(pfFrame &frame_); // Broadband bearer capability
void makeToFrameBLL_IE(pfFrame &frame_); // Broadband low-layer information
void makeToFrameBLSH_IE(pfFrame &frame_); // Broadband locking shift
void makeToFrameBNSH_IE(pfFrame &frame_); // Broadband non-locking shift
void makeToFrameBSC_IE(pfFrame &frame_); // Broadband sending complete
void makeToFrameBRI_IE(pfFrame &frame_); // Broadband repeat indicator
void makeToFrameCGN_IE(pfFrame &frame_); // Calling party number
void makeToFrameCGS_IE(pfFrame &frame_); // Calling party subaddress
void makeToFrameCDN_IE(pfFrame &frame_); // Called party number
void makeToFrameCDS_IE(pfFrame &frame_); // Called party subaddress
void makeToFrameTNS_IE(pfFrame &frame_); // Transit network selection
void makeToFrameRI_IE(pfFrame &frame_); // Restart indicator
void makeToFrameUN_IE(pfFrame &frame_); // Unknown IE

main(int argc, char* argv[])
{
    debugOutputCout();

    if (argc == 2)
    {
        pfFrame frame;

        if (argv[1][0] == 'a') // Alerting PDU
        {
            makeToFramePDUheader(B0000_0001, frame);

            debugFrame("Alerting-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);
    
            debugFrame("Encoded Alerting-pdu", newFrame);
        }
        else if (argv[1][0] == 'b') // Call proceeding PDU
        {
            makeToFrameCI_IE(frame);
            makeToFramePDUheader(B0000_0010, frame);

            debugFrame("Call proceedin-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);
    
            debugFrame("Encoded Call proceedin-pdu", newFrame);
        }
        else if (argv[1][0] == 'c') // Setup PDU
        {
            makeToFrameTNS_IE(frame);
            makeToFrameCDS_IE(frame);
            makeToFrameCDN_IE(frame);
            makeToFrameCGS_IE(frame);
            makeToFrameCGN_IE(frame);
            makeToFrameBSC_IE(frame);
            makeToFrameBLL_IE(frame); // 3th BLL
            makeToFrameBLL_IE(frame); // 2nd BLL
            makeToFrameBLL_IE(frame); // 1st BLL
            makeToFrameBRI_IE(frame);
            makeToFrameBBC_IE(frame);
            makeToFrameBHL_IE(frame);
            makeToFrameQOS_IE(frame);
            makeToFrameCI_IE(frame);
            makeToFrameATD_IE(frame);
            makeToFrameAAL_IE(frame);
            makeToFramePDUheader(B0000_0101, frame);

            debugFrame("Setup-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);

            debugFrame("Encoded Setup-pdu", newFrame);
        }
        else if (argv[1][0] == 'd') // Connect PDU
        {
            makeToFrameBLL_IE(frame);
            makeToFrameCI_IE(frame);
            makeToFramePDUheader(B0000_0111, frame);

            debugFrame("Connect-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);
    
            debugFrame("Encoded Connect-pdu", newFrame);
        }
        else if (argv[1][0] == 'e') // Connect acknowledge PDU
        {
            makeToFramePDUheader(B0000_1111, frame);

            debugFrame("Connect acknowledge-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);
    
            debugFrame("Encoded Connect acknowledge-pdu", newFrame);
        }
        else if (argv[1][0] == 'f') // Restart PDU
        {
            makeToFrameRI_IE(frame);
            makeToFrameCI_IE(frame);
            makeToFramePDUheader(B0100_0110, frame);

            debugFrame("Restart-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);
    
            debugFrame("Encoded Restart-pdu", newFrame);
        }
        else if (argv[1][0] == 'g') // Release PDU
        {
            makeToFrameCA_IE(frame);
            makeToFramePDUheader(B0100_1101, frame);

            debugFrame("Release-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);
    
            debugFrame("Encoded Release-pdu", newFrame);
        }
        else if (argv[1][0] == 'h') // Restart acknowledge PDU
        {
            makeToFrameRI_IE(frame);
            makeToFrameCI_IE(frame);
            makeToFramePDUheader(B0100_1110, frame);

            debugFrame("Restart acknowledge-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);
    
            debugFrame("Encoded Restart acknowledge-pdu", newFrame);
        }
        else if (argv[1][0] == 'i') // Release complete PDU
        {
            makeToFrameCA_IE(frame);
            makeToFramePDUheader(B0101_1010, frame);

            debugFrame("Release complete-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);
    
            debugFrame("Encoded Release complete-pdu", newFrame);
        }
        else if (argv[1][0] == 'j') // Status PDU
        {
            makeToFrameCS_IE(frame);
            makeToFrameCA_IE(frame);
            makeToFramePDUheader(B0111_1101, frame);

            debugFrame("Status-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);
    
            debugFrame("Encoded Status-pdu", newFrame);
        }
        else if (argv[1][0] == 'k') // Status enquiry PDU
        {
            makeToFramePDUheader(B0111_0101, frame);

            debugFrame("Status enquiry-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);
    
            debugFrame("Encoded Status enquiry-pdu", newFrame);
        }
        else if (argv[1][0] == 'l') // Unknown PDU
        {
            makeToFrameRI_IE(frame);
            makeToFrameCI_IE(frame);
            makeToFramePDUheader(B1111_1111, frame);

            debugFrame("Unknown-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);
    
            debugFrame("Encoded Unknown-pdu", newFrame);
        }
        else if (argv[1][0] == 'm') // Alerting + (RI_IE + UN_IE + CI_IE)
        {
            makeToFrameRI_IE(frame);
            makeToFrameUN_IE(frame);
            makeToFrameCI_IE(frame);
            makeToFramePDUheader(B0000_0001, frame);

            debugFrame("Alerting(RI_IE + UN_IE + CI_IE)-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);
    
            debugFrame("Encoding Alerting(RI_IE + UN_IE + CI_IE)-pdu", newFrame);
        }
        else if (argv[1][0] == 'n') // Alerting + BLSH_IE + BNSH_IE
        {
            makeToFrameBLSH_IE(frame);
            makeToFrameBNSH_IE(frame);
            makeToFramePDUheader(B0000_0001, frame);

            debugFrame("Alerting(BLSH_IE + BNSH_IE)-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);
    
            debugFrame("Encoding Alerting(BLSH_IE + BNSH_IE)-pdu", newFrame);
        }
        else if (argv[1][0] == 'o') // Alerting + (CS_IE with extra field)
        {
            // Call state IE
            frame.putFirst(B0010_1011); // Extra field
            frame.putFirst(B0010_1011);
            frame.putFirst16bit(2);
            frame.putFirst(B1111_1000);
            frame.putFirst(B0001_0100);

            makeToFramePDUheader(B0000_0001, frame);

            debugFrame("Alerting(CS_IE with extra field)-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);
    
            debugFrame("Encoding Alerting(CS_IE with extra field)-pdu", newFrame);
        }
        else if (argv[1][0] == 'p')
               // Alerting + (CA_IE with extra extensions in header and content)
        {
            // Cause IE
            frame.putFirst(B0010_1111);
            frame.putFirst(B0100_0010);
            frame.putFirst(B1010_0011);
            frame.putFirst(B1011_1000); // extra extension
            frame.putFirst(B0110_0001); // extra extension
            frame.putFirst(B0000_1011);
            frame.putFirst16bit(6);
            frame.putFirst(B1011_1010);
            frame.putFirst(B0111_1000); // extra extension
            frame.putFirst(B0000_1000);

            makeToFramePDUheader(B0000_0001, frame);

            debugFrame("Alerting(CA_IE with extra extensions)-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);
    
            debugFrame("Encoding Alerting(CA_IE with extra extensions)-pdu"
                       , newFrame);
        }
        else if (argv[1][0] == 'q') // Alerting + (CI_IE(too short) + RI_IE)
        {
            makeToFrameRI_IE(frame);
            // CI_IE ... last 3 octets missing
            frame.putFirst(B1111_0000);
            frame.putFirst(B1000_1000);
            frame.putFirst16bit(2);
            frame.putFirst(B1111_1000);
            frame.putFirst(B0101_1010);

            makeToFramePDUheader(B0000_0001, frame);

            debugFrame("Alerting + (CI_IE(too short) + RI_IE)-pdu created", frame);

            pfFrame newFrame = decode_encode(frame);

            debugFrame("Encoding Alerting + (CI_IE(too short) + RI_IE)-pdu"
                       , newFrame);
        }
        else if (argv[1][0] == 'r')
        {
            frame.putFirst(B1001_0010); // type oct. 2 (Instruction field)
            frame.putFirst(B0000_0001); // type alerting pdu
            frame.putFirst24bit(0);     // Call reference
            frame.putFirst(B0000_0011); // Call length & spares
            frame.putFirst(B0000_1001); // Protocol Discriminator

            debugFrame("Testing too short pdu-header", frame);
         
            pfFrame newFrame = decode_encode(frame);
         
            debugFrame("Testing too short pdu-header", newFrame);
        }
        else if (argv[1][0] == 's')
        {
            debugUser("Not used");
        }
        else if (argv[1][0] == 'u')
        {
            debugUser("Not used");
        }
        else
        {
            printUsage(argv[0]);
        }
    }
    else 
    {
        printUsage(argv[0]);
    }
}

void printUsage(string argv0_)
{
    string usage = "Usage: " + argv0_ + " [flag]";

    debugUser(usage);
    debugUser("a <-> Alerting PDU");
    debugUser("b <-> Call proceeding PDU");
    debugUser("c <-> Setup PDU");
    debugUser("d <-> Connect PDU");
    debugUser("e <-> Connect acknowledge PDU");
    debugUser("f <-> Restart PDU");
    debugUser("g <-> Release PDU");
    debugUser("h <-> Restart acknowledge PDU");
    debugUser("i <-> Release complete PDU");
    debugUser("j <-> Status PDU");
    debugUser("k <-> Status enquiry PDU");
    debugUser("l <-> Unknown PDU");
    debugUser("m <-> Alerting + (RI_IE + UN_IE + CI_IE)");
    debugUser("n <-> Alerting + BLSH_IE + BNSH_IE");
    debugUser("o <-> Alerting + (CS_IE with extra field)");
    debugUser("p <-> Alerting + (CA_IE with extra extensions in header and content)");
    debugUser("q <-> Alerting + (CI_IE(too short) + RI_IE)");
    debugUser("r <-> Testing too short pdu-header");
    debugUser("s <-> ");
    debugUser("t <-> ");
    debugUser("u <-> ");
    return;
}

pfFrame decode_encode(pfFrame frame_)
{
    uniPDUcoder *testcoder = new uniPDUcoder;

    otMessage::SerializedMessage testMessage = testcoder->decode(frame_);

    debugUser("Printing created otMessage::SerializedMessage...");
    for (pfUlong i = 0; i < testMessage.length(); ++i)
    {
        otMessage::ElementKind kind = testMessage[i].kind;
        string id = testMessage[i].identifier.in();
        string value = testMessage[i].value.in();
        pfUlong number = testMessage[i].number;
//        debugPfUlong("kind", kind);
        debugString("id", id);
        if (kind == otMessage::Integer ||
            kind == otMessage::Boolean)
        {
            debugPfUlong("number", number);
        }
        else
        {
            debugString("value", value);
        }
    }
    debugUser("encoding message from SerializedMessage...");
    pfFrame frame2 = testcoder->encode(testMessage);

    return frame2;
}

void makeToFramePDUheader(pfUlong pduType_, pfFrame &frame_)
{
    frame_.putFirst16bit(frame_.length()); // length
    frame_.putFirst(B1001_0010); // type oct. 2 (Instruction field)
    frame_.putFirst(pduType_); // type
    frame_.putFirst24bit(0); // Call reference
    frame_.putFirst(B0000_0011); // Call length & spares
    frame_.putFirst(B0000_1001); // Protocol Discriminator

    return;
}

void makeToFrameCA_IE(pfFrame &frame_) // Cause
{
    frame_.putFirst(B0010_1111);
    frame_.putFirst(B0100_0010);
    frame_.putFirst(B1010_0011);
    frame_.putFirst(B1000_1011);
    frame_.putFirst16bit(4);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0000_1000);

    return;
}

void makeToFrameCS_IE(pfFrame &frame_) // Call state
{
    frame_.putFirst(B0010_1011);
    frame_.putFirst16bit(1);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0001_0100);

    return;
}

void makeToFrameAAL_IE(pfFrame &frame_) // ATM adaptation layer parameters
{
    frame_.putFirst(B0011_0010);
    frame_.putFirst(B1000_0100);
    frame_.putFirst16bit(12345);
    frame_.putFirst16bit(11111);
    frame_.putFirst(B1000_0010);
    frame_.putFirst16bit(22222);
    frame_.putFirst(B1000_0001);
    frame_.putFirst16bit(33333);
    frame_.putFirst(B1000_1100);
    frame_.putFirst(B0010_1011);
    frame_.putFirst16bit(14);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0101_1000);

    return;
}

void makeToFrameATD_IE(pfFrame &frame_) // ATM traffic descriptor
{
    frame_.putFirst(B0000_0010);
    frame_.putFirst(B1011_1111);
    frame_.putFirst(B1011_1110);
    frame_.putFirst24bit(1231114);
    frame_.putFirst(B1011_0001);
    frame_.putFirst24bit(1231111);
    frame_.putFirst(B1011_0000);
    frame_.putFirst24bit(1213111);
    frame_.putFirst(B1010_0001);
    frame_.putFirst24bit(1211311);
    frame_.putFirst(B1010_0000);
    frame_.putFirst24bit(1211131);
    frame_.putFirst(B1001_0001);
    frame_.putFirst24bit(1211113);
    frame_.putFirst(B1001_0000);
    frame_.putFirst24bit(1211111);
    frame_.putFirst(B1000_1001);
    frame_.putFirst24bit(1121111);
    frame_.putFirst(B1000_1000);
    frame_.putFirst24bit(1112111);
    frame_.putFirst(B1000_0101);
    frame_.putFirst24bit(1111211);
    frame_.putFirst(B1000_0100);
    frame_.putFirst24bit(1111121);
    frame_.putFirst(B1000_0011);
    frame_.putFirst24bit(1111112);
    frame_.putFirst(B1000_0010);
    frame_.putFirst16bit(51);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0101_1001);    

    return;
}

void makeToFrameCI_IE(pfFrame &frame_) // Connection identifier
{
    frame_.putFirst16bit(155);
    frame_.putFirst16bit(43);
    frame_.putFirst(B1000_1000);
    frame_.putFirst16bit(5);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0101_1010);

    return;
}

void makeToFrameQOS_IE(pfFrame &frame_) // Quality of service parameter
{
    frame_.putFirst(B1000_0001);
    frame_.putFirst(B0001_1000);
    frame_.putFirst16bit(2);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0101_1100);

    return;
}

void makeToFrameBHL_IE(pfFrame &frame_) // Broadband high layer information
{
    frame_.putFirst(B1000_0000);
    frame_.putFirst(B0100_0000);
    frame_.putFirst(B0010_0000);
    frame_.putFirst(B0001_0000);
    frame_.putFirst(B0000_1000);
    frame_.putFirst(B0000_0100);
    frame_.putFirst(B0000_0010);
    frame_.putFirst(B0000_0001);
    frame_.putFirst(B1001_1000);
    frame_.putFirst16bit(9);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0101_1101);

    return;
}

void makeToFrameBBC_IE(pfFrame &frame_) // Broadband bearer capability
{
    frame_.putFirst(B1010_0001);
    frame_.putFirst(B1000_1001);
    frame_.putFirst(B0001_0000);
    frame_.putFirst16bit(3);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0101_1110);

    return;
}

void makeToFrameBLL_IE(pfFrame &frame_) // Broadband low-layer information
{
    frame_.putFirst(B1111_0010);
    frame_.putFirst(B1100_1011);
    frame_.putFirst(B1010_0001);
    frame_.putFirst(B1000_1001);
    frame_.putFirst(B0001_0000);
    frame_.putFirst16bit(5);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0101_1111);

    return;
}

void makeToFrameBLSH_IE(pfFrame &frame_) // Broadband locking shift
{
    frame_.putFirst(B1000_0011);
    frame_.putFirst16bit(1);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0110_0000);

    return;
}

void makeToFrameBNSH_IE(pfFrame &frame_) // Broadband non-locking shift
{
    frame_.putFirst(B1000_0100);
    frame_.putFirst16bit(1);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0110_0001);

    return;
}

void makeToFrameBSC_IE(pfFrame &frame_) // Broadband sending complete
{
    frame_.putFirst(B1010_0001);
    frame_.putFirst16bit(1);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0110_0010);

    return;
}

void makeToFrameBRI_IE(pfFrame &frame_) // Broadband repeat indicator
{
    frame_.putFirst(B1000_0101);
    frame_.putFirst16bit(1);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0110_0011);

    return;
}

void makeToFrameCGN_IE(pfFrame &frame_) // Calling party number
{
    frame_.putFirst(B0101_0111);
    frame_.putFirst(B0101_0101);
    frame_.putFirst(B0101_0011);
    frame_.putFirst(B0000_0010);
    frame_.putFirst(B1100_0010);
    frame_.putFirst(B0101_0100);
    frame_.putFirst16bit(6);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0110_1100);

    return;
}

void makeToFrameCGS_IE(pfFrame &frame_) // Calling party subaddress
{
    frame_.putFirst(B0101_1010);
    frame_.putFirst(B0000_1111);
    frame_.putFirst(B1001_0110);
    frame_.putFirst(B0011_1100);
    frame_.putFirst(B1100_0011);
    frame_.putFirst(B1101_0000);
    frame_.putFirst16bit(6);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0110_1101);

    return;
}

void makeToFrameCDN_IE(pfFrame &frame_) // Called party number
{
    frame_.putFirst(B0101_1010);
    frame_.putFirst(B0000_1111);
    frame_.putFirst(B0011_1100);
    frame_.putFirst(B0100_0011);
    frame_.putFirst(B1101_0100);
    frame_.putFirst16bit(5);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0111_0000);

    return;
}

void makeToFrameCDS_IE(pfFrame &frame_) // Called party subaddress
{
    frame_.putFirst(B0000_1111);
    frame_.putFirst(B0011_1100);
    frame_.putFirst(B0100_0011);
    frame_.putFirst(B1101_0000);
    frame_.putFirst16bit(4);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0111_0001);

    return;
}

void makeToFrameTNS_IE(pfFrame &frame_) // Transit network selection
{
    frame_.putFirst(B0011_0000);
    frame_.putFirst(B0101_1000);
    frame_.putFirst(B0011_1000);
    frame_.putFirst(B0011_0111);
    frame_.putFirst(B0011_0100);
    frame_.putFirst(B0011_0011);
    frame_.putFirst(B0011_0010);
    frame_.putFirst(B1001_1100);
    frame_.putFirst16bit(8);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0111_1000);

    return;
}

void makeToFrameRI_IE(pfFrame &frame_) // Restart indicator
{
    frame_.putFirst(B1000_0111);
    frame_.putFirst16bit(1);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B0111_1001);

    return;
}

void makeToFrameUN_IE(pfFrame &frame_) // Unknown IE
{
    frame_.putFirst(B1100_0011);
    frame_.putFirst(B1111_1110);
    frame_.putFirst(B1101_1100);
    frame_.putFirst(B1011_1010);
    frame_.putFirst(B1001_1000);
    frame_.putFirst(B0111_0110);
    frame_.putFirst(B0101_0100);
    frame_.putFirst(B0011_0010);
    frame_.putFirst(B0001_0000);
    frame_.putFirst16bit(9);
    frame_.putFirst(B1111_1000);
    frame_.putFirst(B1111_1111);

    return;
}
