/*
        Chat program proof-of-concept using UDP.

        Tested on Bridged Mode with two VMs under the same router (same and different computers),
        and on NAT Network Mode with two VMs using the same virtualized NAT.

*/

U8                              *dest_ip_string         = StrGet("Destination IPV4: "),
                                *port_string            = StrGet("RX & TX UDP Port: ");
CIPV4Address    *dest_address           = CAlloc(sizeof(CIPV4Address));

I64                              port                           = Str2I64(port_string);
CTask                   *chat_display_task      = NULL;
CTask                   *chat_message_task      = NULL;

U0 ChatDisplayTask(I64)
{ // display received messages.
        DocTermNew;
        DocCursor;
        DocPrint(, "$WW,1$");

        while (TaskValidate(chat_message_task))
        {
                Refresh;
        }
}

U0 ChatMessageTask(I64)
{ // take in text.
        U8      *message;
        I64  de_index;
        U8      *payload;

        DocTermNew;
        DocPrint(, "$WW,1$");

        while (message = StrGet("> ",, SGF_SHIFT_ESC_EXIT))
        {
                DocBottom(chat_display_task->put_doc);
                DocPrint(chat_display_task->put_doc, "$BG,BLUE$$BLACK$<local>$FG$$BG$ %s\n", message);

                de_index = UDPPacketAllocate(&payload, ipv4_globals.local_ip, port, dest_address->address, port, StrLen(message));
                MemCopy(payload, message, StrLen(message));
                UDPPacketFinish(de_index);

                DocClear;
                DocPrint(, "$WW,1$");

        }
}

U0 ChatInit()
{
        chat_message_task = Spawn(&ChatMessageTask, NULL, "UDP Chat Message");
        chat_display_task = Spawn(&ChatDisplayTask, NULL, "UDP Chat");
        chat_message_task->win_inhibit = WIG_USER_TASK_DEFAULT;
        chat_display_task->win_inhibit = WIG_USER_TASK_DEFAULT;
        LBts(&chat_message_task->display_flags, DISPLAYf_SHOW);
        LBts(&chat_display_task->display_flags, DISPLAYf_SHOW);

        WinFocus(chat_display_task);
        WinFocus(chat_message_task);

        chat_display_task->win_top              = 2;
        chat_display_task->win_bottom   = TEXT_ROWS / 3;
        chat_display_task->win_left             = TEXT_COLS / 3;
        chat_display_task->win_right    = TEXT_COLS / 3 * 2;

        chat_message_task->win_top              = chat_display_task->win_bottom + 2;
        chat_message_task->win_bottom   = chat_message_task->win_top + 3;
        chat_message_task->win_left             = chat_display_task->win_left;
        chat_message_task->win_right    = chat_display_task->win_right;

}

U0 Chat()
{
        CUDPSocket                      *udp_socket = UDPSocket(AF_INET);
        CSocketAddressIPV4      *sock_addr = CAlloc(sizeof(CSocketAddressIPV4));
        U8                                      *buffer[ETHERNET_FRAME_SIZE];

//      MemSet(buffer, 0, ETHERNET_FRAME_SIZE);

        "\nIP entered: %s\n", dest_ip_string;

        while (PresentationToNetwork(AF_INET, dest_ip_string, dest_address) == -1)
        {
                "ERROR: Bad IP entered. Retry.\n";
                dest_ip_string = StrGet("Destination IPV4: ");
        }

        ChatInit;

        sock_addr->port                         = EndianU16(port);
        sock_addr->family                       = AF_INET;
        sock_addr->address.address      = dest_address->address;
        UDPSocketBind(udp_socket, sock_addr);

        "\nIP entered: %s\n", dest_ip_string;

        while (TaskValidate(chat_message_task))
        {
                if (UDPSocketReceiveFrom(udp_socket, buffer, ETHERNET_FRAME_SIZE, NULL) != -1)
                {
                        DocBottom(chat_display_task->put_doc);
                        DocPrint(chat_display_task->put_doc, "$BG,PURPLE$$BLACK$<%s>$FG$$BG$  %s\n", dest_ip_string, buffer);//NetworkToPresentation(AF_INET, dest_address));
                        MemSet(buffer, 0, ETHERNET_FRAME_SIZE);
                }

                Refresh;

        }

        Free(sock_addr);
        UDPSocketClose(udp_socket);

}

Chat;