// $Id: econcmds.c,v 1.22 2016/06/07 21:16:08 lpoulsen Exp $
//
// Copyright (c) 2008 by AFAR Technologies, Inc, Goleta, CA 93117 USA
//
// $Log: econcmds.c,v $
// Revision 1.22  2016/06/07 21:16:08  lpoulsen
// Resolve problem in Linux ECON causing a hard hanging process when you
//     do a multi-radio connect/download sequence. The resolution was to
//     use a local mutex instead of a global mutex to bracket the
//     pthread_cond_timedwait() in WaitForSingleObject()
// Also, use DBFLG_ECON_PKTS to turn on debugging output of ECON packets
//     instead of debug_level
//
// Revision 1.21  2011/12/14 23:35:09  lpoulsen
// At then end of DISCOVER, say "Use CONNECT"
//
// Revision 1.20  2011/10/07 00:54:08  lpoulsen
// Add "diagnose" command.
// Handle automatic adding of the correct extension for a download file
//    in networks with mixed radio types.
//
// Revision 1.19  2011/08/23 18:42:44  lpoulsen
// Suppress message for bad packet length unless "debug nethealth" is set.
//   With "debug nethealth" dump first 46 bytes of packet./
//
// Revision 1.18  2011/07/08 22:54:27  lpoulsen
// Change command line option -d to take a string argument for initial
//     value of debug_flags (instead of making it count up debug_level).
//
// Revision 1.17  2011/07/08 21:50:30  lpoulsen
// Eliminate (almost all) use of debug_level, use debug_flags instead.
//
// Revision 1.16  2011/06/30 22:23:03  lpoulsen
// Add "set" command. (For now just "set output=")
//
// Revision 1.15  2011/05/06 22:15:14  lpoulsen
// Preparing for ECON 04.07 release
//
// Revision 1.14  2011/03/22 00:26:10  lpoulsen
// Resolve sequence errors on very weak links
// Resolve hangs when Ctrl-C between "dir" and "download"
// Resolve conflicting build date information
//
// Revision 1.13  2011/02/21 22:26:36  lpoulsen
// "adapter" command works on Linux
//
// Revision 1.12  2011/02/18 22:31:09  lpoulsen
// Add "adapter" command to switch to another ethernet port
//
// Revision 1.11  2011/02/08 22:07:02  lpoulsen
// evived the LINUX build of ECON - now ECON-PLUS
//
// Revision 1.10  2011/02/04 22:29:07  lpoulsen
// Many little fixes.
//
// Revision 1.9  2010/12/23 02:25:41  lpoulsen
// Add "loss" command for testing retransmissions
//
// Revision 1.8  2010/12/22 17:36:33  lpoulsen
// Select/Deselect list of ranges
// Expand to up to 511 radios
// Protocol fixes
//
// Revision 1.7  2008/08/05 23:58:37  lpoulsen
// User interface updates.
//
// Revision 1.6  2008/07/25 00:43:27  lpoulsen
// Added "select all" and "edit" commands.
// Optional OEM_COMPANY personalization
//
// Revision 1.5  2008/07/16 00:00:28  lpoulsen
// Add deselect command.
//
// Revision 1.4  2008/07/11 20:14:10  lpoulsen
// Resolve many compiler warnings on Linux
//
// Revision 1.3  2008/07/11 16:28:46  lpoulsen
// Econ 4.00 release candidate supports UPDATE and SELECT commands.
//
// Revision 1.2  2008/06/10 00:06:10  lpoulsen
// New -X option is now working
// Updated -I and -O implementation
//
// Revision 1.1  2008/05/31 00:35:09  lpoulsen
// Econ 4.x preview - now with command shell
//

#include <stdio.h>
#include <stdlib.h>
#ifdef LINUX
#include <unistd.h>
#endif

#include "afartype.h"
#include "parser.h"
#include "epacket.h"
#include "ucon.h"
#include "adapter.h"

extern void clear_device_table(void);

#ifdef WIN32
#define EDITOR "notepad"
#else
#define EDITOR "/bin/vi"
#endif

extern int system(const char *cmd);

// The command interpreter is case insensitive, but commands listed
// here must be all lowercase.

extern const Command cmd_list[];
extern Command *current_command_table;

extern_cmd_func version_cmd;
extern_cmd_func debug_cmd;
extern_cmd_func delete_cmd;
extern_cmd_func directory_cmd;
extern_cmd_func econ_adapter;
extern_cmd_func econ_connect;
extern_cmd_func econ_discover;
extern_cmd_func econ_screen;
extern_cmd_func econ_select;
extern_cmd_func econ_deselect;
extern_cmd_func econ_diagnose;
extern_cmd_func econ_download;
extern_cmd_func econ_set;
extern_cmd_func econ_show;
extern_cmd_func econ_sort;
extern_cmd_func edit_cmd;
extern_cmd_func loss_cmd;

extern Arg      onefile_args[];
extern Arg      adapter_args[];
extern Arg      connect_args[];
extern Arg      debug_args[];
extern Arg      loss_args[];
extern Arg      screen_args[];
extern Arg      select_args[];
extern Arg      set_args[];
extern Arg      show_args[];
extern Arg      sort_args[];
extern Arg      diagnose_args[];
extern Arg      download_args[];

Command *current_command_table = (Command *)&cmd_list[0];

const Command cmd_list[] =
{
{ "Econsole",          NULL,            NULL,             PARSER_COMMENT},
   { "adapter",           adapter_args,    econ_adapter,      0 },
   { "connect",           connect_args,    econ_connect,      0 },
   { "discover",          no_args,         econ_discover,     0 },
   { "select",            select_args,     econ_select,       0 },
   { "deselect",          select_args,     econ_deselect,     0 },
   { "diagnose",          diagnose_args,   econ_diagnose,     0 },
   { "download",          download_args,   econ_download,     0 },
   { "set",               set_args,        econ_set,          0 },
   { "show",              show_args,       econ_show,         0 },
   { "sort",              sort_args,       econ_sort,         0 },
{ "Miscellaneous",     NULL,            NULL,             PARSER_COMMENT},
   { "delete-file",       onefile_args,    delete_cmd,        0 },
   { "directory",         onefile_args,    directory_cmd,     0 },
   { "edit",              onefile_args,    edit_cmd,          0 },
   { "help",              parser_help_args, parser_help,      0 },
   { "quit",              no_args,         session_logout,    0 },
   { "exit",              CMD_ALIAS,       session_logout,    PARSER_NOHELP },
   { "logout",            CMD_ALIAS,       session_logout,    PARSER_NOHELP },
#ifdef WIN32
   { "screen",            screen_args,     econ_screen,       0 },
#endif
   { "version",           no_args,         version_cmd,       0 },
   { "debug",             debug_args,      debug_cmd,         0 },
   { "loss-percent",      loss_args,       loss_cmd,          PARSER_DEBUG },
  { NULL }
};

Arg onefile_args[] = {
 { "filename", STRING,    0 },
 { NULL,       END_ARGS,  0 }
};

cmd_ret_t
delete_cmd(Argument_List *a, ucio_session *s)
{
    char *tmp;

    tmp = parser_get_value(a, "filename");
    if (tmp) {
        unlink(tmp);
    }
    return CMD_SUCCESS;
}

cmd_ret_t
directory_cmd(Argument_List *a, ucio_session *s)
{
    char *tmp;
    char  command[80];

    tmp = parser_get_value(a, "filename");
    if (tmp) {
        sprintf(command, "dir %-64.64s", tmp);
        system(command);
    } else {
        system("dir");
    }
    return CMD_SUCCESS;
}

cmd_ret_t
edit_cmd(Argument_List *a, ucio_session *s)
{
    char *tmp;
    char  command[80];
    char *editor;

    editor = getenv("EDITOR");
    if (editor == NULL) editor = EDITOR;

    tmp = parser_get_value(a, "filename");
    if (tmp) {
        sprintf(command, "%s %1.64s", editor, tmp);
        system(command);
    } else {
        system(editor);
    }
    return CMD_SUCCESS;
}

// These definitions must align with the #define 's in dbflags.h
Select debug_bit_defs[] = {
    { "dummy1",   PARSER_DISABLED },
    { "dummy2",   PARSER_DISABLED },
    { "dummy3",   PARSER_DISABLED },
    { "dummy4",   PARSER_DISABLED },
    { "download",     0 },
    { "ack-seq",      0 },
    { "session-pcap", 0 },
    { "session-text", 0 },
    { "keep-traces",  0 },
    { "date-time",    0 },
    { "threads",      0 },
    { "adapter",      0 },
    { "nethealth",    0 },
    { "econ-packets", 0 },
    { NULL,           0 }
};

Arg debug_args[] = {
 { "flags", BITFLAGS(debug_bit_defs), 0 },
 { "level", INT(0, 3),    0 },
 { NULL,    END_ARGS,     0 }
};

cmd_ret_t
debug_cmd(Argument_List *a, ucio_session *s)
{
    char *tmp;

    tmp = parser_get_value(a, "flags");
    if (tmp) debug_flags = parse_bitmask(tmp, debug_bit_defs);

    tmp = parser_get_value(a, "level");
    if (tmp) debug_level = atoi(tmp);

    printf("  flags=%s\n  level=%d\n",
                     parser_format_bitflags(debug_flags, debug_bit_defs),
                     debug_level );
    return CMD_SUCCESS;
}

int  loss_pct_recv = 0;
int  loss_pct_xmit = 0;

Arg loss_args[] = {
 { "transmit", INT(0, 50),   0 },
 { "receive",  INT(0, 50),   0 },
 { NULL,       END_ARGS,     0 }
};

cmd_ret_t
loss_cmd(Argument_List *a, ucio_session *s)
{
    char *tmp = parser_get_value(a, "transmit");
    if (tmp) loss_pct_xmit = atoi(tmp);

    tmp = parser_get_value(a, "receive");
    if (tmp) loss_pct_recv = atoi(tmp);

    srand(0);

    return CMD_SUCCESS;
}

Arg adapter_args[] = {
    { "index", INT(0,5), 0 },
    { NULL,    END_ARGS, 0 }
};

cmd_ret_t
econ_adapter(Argument_List *a, ucio_session *s)
{
    char *tmp = parser_get_value(a, "index");
    int   new_index;

    if (tmp) {
        new_index = atoi(tmp);

        if ((ethernet_adapters[new_index].flags & EA_USABLE) == 0) {
             printf("Invalid selection\n");
             return CMD_BAD_ARG_VALUE;
        }
        if (debug_flags & DBFLG_ADAPTER) printf("Switching adapters\n");
        close_all_adapters();
        if (debug_flags & DBFLG_ADAPTER) printf("Old adapter closed\n");

        option_C = open_adapter(new_index);
        if (debug_flags & DBFLG_ADAPTER) printf("New adapter %d opened\n", option_C);

        clear_device_table();
#if 0
        numOfRadiosFound = discover_radios(false, 3);

        if (numOfRadiosFound == 0) {
            printf("No devices were found.\n");
        } else {
            sort_device_table(0);
            show_radios(false, 0, 1, 45);
            printf("\r\n");
            printf("%d devices were found.\n", numOfRadiosFound);
        }
#else
        econ_discover(a,s);
#endif
    }
    return CMD_SUCCESS;
}

Arg set_args[] = {
    { "output-file", STRING,    0 },
    { NULL,          END_ARGS,  0 }
};

cmd_ret_t
econ_set(Argument_List *a, ucio_session *s)
{
    char *tmp;

    tmp = parser_get_value(a, "output-file");
    if (tmp) {
        if (option_O) free(option_O);

        if ((strlen(tmp) == 0) || (strcmp(tmp, "none") == 0))
            option_O = NULL;
        else {
            option_O = malloc(strlen(tmp)+1);
            strcpy(option_O, tmp);
        }
    }
    if (parser_empty(a)) {
        printf("Output-file: %s\n", (option_O ? option_O
                                              : "(direct to console)"));
    }
    return CMD_SUCCESS;
};

// End
