/*
 * connection_Setup.cc
 *
 *  Created on: Feb 7, 2018
 *      Author: anay
 */


/*
 * connection_Setup.cpp
 *
 *  Created on: Nov 27, 2017
 *      Author: anay
 */
#include <omnetpp.h>
#include <stdio.h>
#include <stdlib.h>
#include "connection_Setup.h"

using namespace inet;

void connection_Setup::initialize(int stage) {
    int port = 1024;
    socket = create_UDPSocket(L3Address(), port);
}
void connection_Setup::handleMessage(cMessage *msg) {
    if (PN == 1 && msg->isSelfMessage()) {
        sendClientInitial(0x00000002, "FirstMessage");
    }
    if (PN == 1 && msg->arrivedOn("udpOut")
            && pkt == dynamic_cast<Long_Header*>(msg)) {
        if (pkt->getVersion() == 0x0000001 || pkt->getVersion() == 0x0000002) {
            version = pkt->getVersion();
            if (pkt->getType() == 0x81) {
                receiveVersionNegotiation(pkt);
            }
            if (pkt->getType() == 0x82) {
                receiveClientInitial(pkt);
            }
            if (pkt->getType() == 0x83) {
                receiveServerStatelessRetry(pkt);
            }
            if (pkt->getType() == 0x84) {
                receiveServerCleartext(pkt);
            }
            if (pkt->getType() == 0x85) {
                receiveClientCleartext(pkt);
            }
            if (pkt->getType() == 0x86) {
                receiveRTTProtected(pkt);
            }
        } else {
            sendVersionNegotiation();
        }

    }
}
void connection_Setup::sendVersionNegotiation() {
    Version_Negotiation *msg = new Version_Negotiation;
    Long_Header *pkt = new Long_Header();
    msg->setVersions("0x0000001, 0x00000002");
    pkt->setType(0x81);
    pkt->setCID(0x0101010101010101);
    pkt->setPN(PN);
    pkt->setVersion(0x00000002);
    pkt->encapsulate(msg);
    send_packet(pkt, L3AddressResolver().resolve("node2"), 1023, socket);
}

void connection_Setup::receiveVersionNegotiation(Long_Header *pkt) {
    Version_Negotiation *vn =
            dynamic_cast<Version_Negotiation*>(pkt->decapsulate());
    std::cout << vn->getVersions() << endl;
}

void connection_Setup::sendClientInitial(uint32_t version, const char* stream) {
    Client_Initial *msg = new Client_Initial();
    Long_Header *pkt = new Long_Header();
    Stream *str = new Stream();
    str->setType(0xcb);
    str->setStream_Id(0x00000000);
    str->setStream_Data("FirstCount");
    msg->setStream_0(str);
    pkt->setType(0x82);
    pkt->setCID(0x0101010101010101);
    pkt->setPN(PN);
    pkt->setVersion(0x00000002);
    pkt->encapsulate(msg);
    send_packet(pkt, L3AddressResolver().resolve("node2"), 1023, socket);
}

void connection_Setup::receiveClientInitial(Long_Header *pkt) {
    CID = pkt->getCID();
    Client_Initial *ci = dynamic_cast<Client_Initial*>(pkt->decapsulate());
    Stream *str = new Stream();
    str = ci->getStream_0();
    std::cout << str->getStream_Id() << "\t" << str->getStream_Data() << endl;
    sendServerCleartext(version, str->getStream_Data());
}

void connection_Setup::receiveClientCleartext(Long_Header *pkt) {
    Client_Cleartext *cc = dynamic_cast<Client_Cleartext*>(pkt->decapsulate());
    Ack* ack = cc->getAck_0();
    Stream* stream = cc->getStream_0();
    Padding* pad = cc->getPadding_0();
    lastAckPn = ack->getLargest_Acknowledged();
    std::cout << stream->getStream_Id() << "\t" << stream->getStream_Data()
            << endl;
    std::cout << strlen(pad->getPad()) << endl;
    sendRTTProtected(pkt->getVersion(), "SendingData");
}

void connection_Setup::receiveServerCleartext(Long_Header *pkt) {
    Server_Cleartext *sc = dynamic_cast<Server_Cleartext*>(pkt->decapsulate());
    Ack* ack = sc->getAck_0();
    Stream* stream = sc->getStream_0();
    Padding* pad = sc->getPadding_0();
    lastAckPn = ack->getLargest_Acknowledged();
    std::cout << stream->getStream_Id() << "\t" << stream->getStream_Data()
            << endl;
    std::cout << strlen(pad->getPad()) << endl;
    sendClientCleartext(pkt->getVersion(), stream->getStream_Data());
}
void connection_Setup::receiveServerStatelessRetry(Long_Header *pkt) {
    Server_Stateless_Retry *ssr =
            dynamic_cast<Server_Stateless_Retry*>(pkt->decapsulate());
    Stream* stream = ssr->getStream_0();
    std::cout << stream->getStream_Id() << "\t" << stream->getStream_Data()
            << endl;
}
void connection_Setup::receiveRTTProtected(Long_Header *pkt) {
    _0_RTT_Protected *rp = dynamic_cast<_0_RTT_Protected*>(pkt->decapsulate());
    Stream* stream = rp->getStream_0();
    std::cout << stream->getStream_Id() << "\t" << stream->getStream_Data()
            << endl;
    sendRTTProtected(pkt->getVersion(), "SendingData2");

}

void connection_Setup::sendClientCleartext(uint32_t version,
        const char* stream) {
    Client_Cleartext *cc = new Client_Cleartext();
    Long_Header *pkt = new Long_Header();
    Stream *str = new Stream();
    Ack *ack = new Ack();
    Padding *pad = new Padding();
    str->setType(0xcb);
    str->setStream_Id(0x00000000);
    str->setStream_Data("ClientCleartext");
    ack->setType(0xa8);
    ack->setLargest_Acknowledged(PN);
    ack->setAck_Block_Section(stream);
    pad->setPad("000000000");
    cc->setAck_0(ack);
    cc->setStream_0(str);
    cc->setPadding_0(pad);
    pkt->setType(0x85);
    pkt->setCID(CID);
    pkt->setPN(++PN);
    pkt->setVersion(version);
    pkt->encapsulate(cc);
    send_packet(pkt, L3AddressResolver().resolve("node2"), 1023, socket);

}
void connection_Setup::sendServerCleartext(uint32_t version,
        const char* string) {
    Server_Cleartext *sc = new Server_Cleartext();
    Long_Header *pkt = new Long_Header();
    Stream *str = new Stream();
    Ack *ack = new Ack();
    Padding *pad = new Padding();
    str->setType(0xcb);
    str->setStream_Id(0x00000000);
    str->setStream_Data("ServerCleartext");
    ack->setType(0xa8);
    ack->setLargest_Acknowledged(PN);
    ack->setAck_Block_Section(string);
    pad->setPad("000000000");
    sc->setAck_0(ack);
    sc->setStream_0(str);
    sc->setPadding_0(pad);
    pkt->setType(0x84);
    pkt->setCID(CID);
    pkt->setPN(++PN);
    pkt->setVersion(version);
    pkt->encapsulate(sc);
    send_packet(pkt, L3AddressResolver().resolve("node2"), 1023, socket);
}
void connection_Setup::sendServerStatelessRetry(uint32_t version,
        const char* string) {
    Server_Stateless_Retry *ssr = new Server_Stateless_Retry();
    Long_Header *pkt = new Long_Header();
    Stream *str = new Stream();
    str->setType(0xcb);
    str->setStream_Id(0x00000000);
    str->setStream_Data("ServerStatelessRetry");
    ssr->setStream_0(str);
    pkt->setType(0x84);
    pkt->setCID(CID);
    pkt->setPN(++PN);
    pkt->setVersion(version);
    pkt->encapsulate(ssr);
    send_packet(pkt, L3AddressResolver().resolve("node2"), 1023, socket);
}
void connection_Setup::sendRTTProtected(uint32_t version, const char* string) {
    _0_RTT_Protected *rp = new _0_RTT_Protected();
    Long_Header *pkt = new Long_Header();
    Stream *str = new Stream();
    str->setType(0xcb);
    str->setStream_Id(0x00000000);
    str->setStream_Data("RTTProtected");
    rp->setStream_0(str);
    pkt->setType(0x86);
    pkt->setCID(CID);
    pkt->setPN(++PN);
    pkt->setVersion(version);
    pkt->encapsulate(rp);
    send_packet(pkt, L3AddressResolver().resolve("node2"), 1023, socket);
}


