/* ---------------------------------------------------
   tcp_client.cxx

   --------------------------------------------------- */
#include <simgear/compiler.h>
#include <iostream>

#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif

#include <iostream>
#ifdef _MSC_VER
#include <conio.h>
#endif

#include <simgear/debug/logstream.hxx>

#include "sg_socket.hxx"

#define DEF_HOST "192.168.1.174"
#define DEF_PORT "5050"
#define DEF_TYPE "tcp"
#define DEF_DIR  SG_IO_OUT

char * HostName = DEF_HOST;
char * HostPort = DEF_PORT;
char * HostType = DEF_TYPE;
SGProtocolDir HostDir = DEF_DIR;

class TcpClient
{
public:
    TcpClient( const char* host, const char* port );
    ~TcpClient();

    bool open();
    bool process();
    bool close();

private:
    SGIOChannel* channel;
};

TcpClient::TcpClient( const char* host, const char* port )
{
    channel = new SGSocket( host, port, HostType );
}

TcpClient::~TcpClient()
{
    delete channel;
}

bool
TcpClient::open()
{
    return channel->open( HostDir );
}

bool
TcpClient::process()
{
    char wbuf[1024];

    int slen = sprintf( wbuf, "hello world\n" );
    int length = channel->writestring( wbuf );
    SG_LOG( SG_IO, SG_INFO, "Write string returned " << length );
    if (slen != length) {
        SG_LOG( SG_IO, SG_ALERT, "Write FAILED!");
        return false;
    }
    return true;
}

bool
TcpClient::close()
{
    return channel->close();
}

#ifdef _MSC_VER
int check_key(void)
{
    int chr = _kbhit();
    if (chr)
        chr = _getch();
    return chr;
}
#endif

int  run_client(void)
{
    int iret = 1;
    SG_LOG( SG_IO, SG_INFO, "Creating TCP client: host " << HostName <<
        ", port " << HostPort << ", Direction " <<
        ((HostDir == SG_IO_BI) ? "BI" : (HostDir == SG_IO_IN) ? "IN" : "OUT"));

    TcpClient client( HostName, HostPort );
    if (!client.open())
    {
        SG_LOG(SG_IO,SG_ALERT,"Client open FAILED!");
	    return iret;
    }

#ifdef _MSC_VER
    SG_LOG( SG_IO, SG_INFO, "Any key to exit...");
#endif // _MSC_VER
    iret = 0;
    for (;;)
    {
        if (! client.process() ) {
            iret = 1;
            break;
        }
#ifdef _WIN32
        if (check_key())
            break;
        Sleep(1000);
        if (check_key())
            break;
#else
	    sleep(1);
#endif
    }

    SG_LOG( SG_IO, SG_INFO, "Closing client");
    client.close();

    return iret;
}

void give_help(void)
{
    printf("tcp_client [Options]\n");
    printf("Options:\n");
    printf(" -?        This help.\n");
    printf(" -d <dir>  Set Direction. Only 'BI', 'IN' or 'OUT' allowed. (def=%s)\n",
        ((HostDir == SG_IO_BI) ? "BI" :
        (HostDir == SG_IO_BI) ? "IN" : "OUT"));
    printf(" -h <host> Set HOST name (def=%s)\n", HostName);
    printf(" -p <port> Set PORT value (def=%s)\n", HostPort);
    printf(" -t <type> Set connection type. Only 'tcp' or 'udp' allowed. (def=%s)\n",
        HostType);
    printf("Set up a TCP client, and send data. Any key to EXIT.\n");
}

int main(int argc, char * argv[])
{
    int i, c;
    char * arg;
    sglog().setLogLevels( SG_ALL, SG_INFO );
    for (i = 1; i < argc; i++) {
        arg = argv[i];
        if (*arg == '-') {
            arg++;
            while (*arg == '-') arg++;
            c = *arg;
            switch (c)
            {
            case '?':
                give_help();
                return 0;
                break;
            case 'd':
                i++;
                if (i < argc) {
                    arg = argv[i];
                    HostDir = (strcmp(arg,"BI")==0) ? SG_IO_BI :
                        (strcmp(arg,"IN")==0) ? SG_IO_IN :
                        (strcmp(arg,"OUT")==0) ? SG_IO_OUT : (SGProtocolDir)-1;
                    if (HostDir == (SGProtocolDir)-1) {
                        SG_LOG(SG_IO,SG_ALERT,"Only 'BI', 'IN', 'OUT' allowed! Not [" << arg << "] Aborting");
                        return 1;
                    }
                    SG_LOG(SG_IO,SG_INFO,"Set Direction to [" << arg << "]");
                } else {
                    i++;
                    goto Req_Fol;
                }
                break;
            case 'h':
                i++;
                if (i < argc) {
                    arg = argv[i];
                    HostName = arg;
                    SG_LOG(SG_IO,SG_INFO,"Set HOST to [" << HostName << "]");
                } else {
                    i++;
                    goto Req_Fol;
                }
                break;
            case 'p':
                i++;
                if (i < argc) {
                    arg = argv[i];
                    HostPort = arg;
                    SG_LOG(SG_IO,SG_INFO,"Set PORT to [" << HostPort << "]");
                } else {
                    i++;
                    goto Req_Fol;
                }
                break;
            case 't':
                i++;
                if (i < argc) {
                    arg = argv[i];
                    HostType = arg;
                    if ((strcmp(arg,"tcp")==0)||(strcmp(arg,"udp")==0)) {
                        SG_LOG(SG_IO,SG_INFO,"Set TYPE to [" << HostType << "]");
                    } else {
                        SG_LOG(SG_IO,SG_ALERT,"Connection TYPE can ONLY be 'tcp' or 'upd', NOT [" << HostType << "]! Aborting");
                        return 1;
                    }
                } else {
                    i++;
                    goto Req_Fol;
                }
                break;
            default:
                goto Bad_Arg;
            }

        } else {
Req_Fol:
             SG_LOG( SG_IO, SG_ALERT, "ERROR: argument [" <<
                  argv[i] << "] requires a following argument! Aborting...");
             return 1;
Bad_Arg:
            SG_LOG( SG_IO, SG_ALERT, "ERROR: Unknown argument [" <<
                argv[i] << "] Aborting...");
            return 1;
        }
    }

    i = run_client();

    return i;
}
