/*
    ORPP Client

    (C) 2005 Jason Hunt

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    Contact: huntjas2@msu.edu

    Compile with -lwsock32

    FILE: network.cpp
*/


#include <windows.h>
#include <stdio.h>

#pragma hdrstop

#include "display.h"
#include "network.h"
#include "camera.h"
#include "version.h"

char host_name[256];

SOCKET server_control_socket;

bool rec_data = false;           // true if date received
bool connected = false;          // true if date connected
bool attempting_connect = false;
bool no_connect = false;         // true if we do not want to connect

// motor controller values
unsigned char l_motor = 0x00, r_motor = 0x00, pan = 0x80, tilt = 0x80;


/************************
*** Network Functions ***
************************/

/* configure and init the network */
void startup_network(HWND hwnd)
{
    // fire up winsock
    WSADATA wsda;
    WSAStartup(MAKEWORD(1, 1),&wsda);
}
/* end of startup network */


/* set the server ost name */
void set_host_name(char *name)
{
    strcpy(host_name, name);
}
/* end of set_host_name */


/* attept to connect to te server */
void connect_to_server( void )
{
    char out[256];
    sprintf(out, "[Control] Connecting to %s:%d", host_name,PORT);
    add_line(out);

    // create the socket
    server_control_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (server_control_socket == INVALID_SOCKET)
    {
        add_line("[Control] Socket error.");
        return;
    }

    LPHOSTENT hostent;

    hostent = gethostbyname(host_name);

    if (!hostent)
    {
        add_line("[Control] Host name error.");
        return;
    }

    /* setup address information */
    SOCKADDR_IN server;
    
    memset(&server, 0, sizeof(server));

    server.sin_addr=*((LPIN_ADDR)*hostent->h_addr_list);
    server.sin_port=htons(PORT);
    server.sin_family=AF_INET;

    WSAAsyncSelect(server_control_socket, main_win, WM_NETEVENT, FD_WRITE | FD_CONNECT |
                                                    FD_READ | FD_CLOSE);
    connected = false;
    attempting_connect = true;

    connect(server_control_socket,(LPSOCKADDR)&server, sizeof(struct sockaddr));
}
/* end of connect_to_server */


/* shutdown win sock */
void shutdown_network(void)
{
    closesocket(server_control_socket);     // close server socket
    camera_disconnect();

    WSACleanup();
}
/* end of shutdown_network */


/* set controller to a contol set */
void echo_controller_value(char *comm)
{
    char out[1024];

    sprintf(out, "[Control] Return: %X %X %X %X",
                (unsigned char) comm[1], (unsigned char) comm[2],
                (unsigned char) comm[3], (unsigned char) comm[4]);

    add_line(out);
}
/* end of set controller */


/* get date from server and parse*/
void read_server_data(void)
{
    char buffer[rec_buffer_size]; // receive buffer
    char packet[5];

    unsigned int n_bytes = recv(server_control_socket, buffer, rec_buffer_size, 0);

    unsigned int bi = 0;
    
    if (n_bytes == 0) return;
     
    while(bi < n_bytes)
    {
        if (buffer[bi] == 0x20) // server wants to send a string
        {
            add_line("[Control] Message from server: ");            
            bi++;
            int len = buffer[bi++]; // get string length
        
            char out[300];
            memcpy(out, buffer + bi, len);
            bi += len; // eat the string
                        
            out[len] = 0;
                        
            add_line(out);            

        }  else
        if (buffer[bi] == 0x30) // echo controller value
        {
             echo_controller_value(buffer);
             bi+=5;
        }   else         
           bi++; // ignore
    }
}
/* end of read server data */


/* end of read_client_data */

void send_string( char *str )
{
    unsigned int len = strlen(str);
    
    if (len > 255) len = 255;
    
    char packet[len+2];
    
    packet[0] = 0x20; // display string
    packet[1] = len; // length
    
    memcpy(packet+2, str, len); 

    // note, the string is not null terminated
    
    if (send(server_control_socket, packet, strlen(packet) + 1, 0) == SOCKET_ERROR)
    {
        add_line("[Control] Unable to send data");
        connected = 0;
    }
}
/* end of send string */


/* sends version string to client */
void send_version( void )
{
    send_string(VERSION);
}
/* end of send_version */


/* send a control packet to the server */
void send_packet(char *packet, unsigned int size)
{
    if (send(server_control_socket, packet, size, 0) == SOCKET_ERROR)
    {
        add_line("[Control] Unable to send data");

        char out[256];
        sprintf(out, "Error: %ld ", WSAGetLastError());
        add_line(out);
        
        connected = false;
    }
}
/* end of set_packet */



/* engage firing system */
void fire_on(void)
{
    char p[1]; p[0] = 0x40;
    send_packet(p, 1);
   // add_line("Fire on");    
}
/* end of fire_on */


/* disengage firing system */
void fire_off(void)
{
    char p[1]; p[0] = 0x41;
    send_packet(p, 1);
   // add_line("Fire on");    
}
/* end of fire off */


/* send the controller values to the server */
void send_controller_values()
{
    if (!connected) return;

    char out[256];
    sprintf(out, "[Control] Send: %X %X %X %X", l_motor, r_motor, pan, tilt);
    add_line(out);

    char data_packet[5]; // the data packet

    data_packet[0] = 0x30; // command byte data (01 == update movement data)
    data_packet[1] = l_motor;
    data_packet[2] = r_motor;
    data_packet[3] = pan;
    data_packet[4] = tilt;

    send_packet(data_packet, 5);
}
/* end of send_controller_values */


void send_value(char v)
{
    if (!connected) return;

//    char out[256];
//    sprintf(out, "[Control] Send: %X", v);
//    add_line(out);

    char data_packet[2]; // the data packet

    data_packet[0] = v; // command byte data (01 == update movement data)


    send_packet(data_packet, 1);
}
/* end of send_controller_values */




/* force stop */
void stop( void )
{
    add_line("Stopping");

    l_motor = 0;
    r_motor = 0;
    
    send_controller_values();
}
/* force stop */



/* send keepalive data */
void send_keep_alive( void )
{
    char data_packet[5]; // the data packet

    memset(data_packet, 0, 5); // make the packet all zeros

    send_packet(data_packet, 5);
}
/* end of send_control_state */



/* send keepalive data */
void remote_shutdown( void )
{
    char data_packet[5]; // the data packet

    memset(data_packet, 0, 5); // make the packet all zeros

    data_packet[0] = 0x02;

    send_packet(data_packet, 5);

    add_line("[Control] Sent remote shutdown command.");
}
/* end of send_control_state */


/* connect to server */
void connect(void)
{
//    closesocket(server_control_socket);
    connected = false;
    no_connect = false;
}
/* end of conenct to server */


/* disconnect from server */
void disconnect(void)
{
    send_string("Good bye!");
    closesocket(server_control_socket);
    connected = false;
    no_connect = true;
    add_line("[Control] Disconnect.");
    
    camera_disconnect();
}
/* end of disconnect */



/* get a hostname from the user */
void get_servername( void )
{
/*    char tmp_name[128];

    HWND hdialog;

    if (GetDlgItemText(NULL, ID_ITEMNAME, tmp_name, 128))
        set_host_name(tmp_name);*/
}
/* end of get hostname */


/* deal with network messages */
void control_socket_message(WPARAM wParam,LPARAM lParam)
{
    switch (WSAGETSELECTEVENT(lParam))
    {
        case FD_ACCEPT:
            break;

        case FD_CONNECT:
            if(WSAGETSELECTERROR(lParam))
            {
                add_line("[Control] Time out.");
                attempting_connect = 0;
                closesocket(server_control_socket);
            }
            else
            {
                add_line("[Control] Connected.");
                connected = 1;
                attempting_connect = 0;
                send_version();
            }
            break;

        case FD_CLOSE:
            add_line("[Control] Server disconnect.");
            connected = 0;
            closesocket(server_control_socket);
            break;

        // data back from server
        case FD_READ:
            read_server_data();
            break;

        case FD_WRITE:
            break;
    }
}
/* end of network_message */



/*******************************
*** End of Network Functions ***
*******************************/


