#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <termios.h>
#include <stdlib.h>
#include <netdb.h>


#include "osp.h"


#define MAX_CMD_LEN       (150)        /*the max length of a shell command */

typedef struct tag_Osp_Net_Shell_Head
{
        uint32_t   ip;                                                        
        uint32_t   port;   /*is just msgdata len, not include Osp_Msg_Head*/                                                      
        uint32_t   res;                                                     
        uint32_t   res1;
}Osp_Net_Shell_Head;

#define NET_SHELL_HEAD_SIZE sizeof(Osp_Net_Shell_Head)


extern struct termios saveterm;
extern char **arg;

extern int32_t nCmdField;
extern int32_t maxCmdField;

int32_t sockser;
struct sockaddr_in addrser, addrcli;
socklen_t addrlen;

#define OSP_MAX_SHELL_NUM 32

int32_t net_shell_txudp_id = -1;
uint32_t net_shell_res = 0;

OSP_UDP_TASK_DATA udp_shell_rx_task = {OSP_NETSHELL_RX_PORT, 1, };




int32_t osp_local_shell_main(char *szCmdNow)
{
    struct termios nt;
    int32_t ret;
    char shellbuf[MAX_CMD_LEN] = {0};
    char buf[4096] = {0};

    tcgetattr(STDIN_FILENO, &saveterm);
    nt = saveterm;
    nt.c_lflag &= (~ICANON);
    nt.c_lflag &= (~ECHO);
    nt.c_cc[VMIN] = 1;
    nt.c_cc[VTIME] = 0;
    tcsetattr(STDIN_FILENO, TCSANOW, &nt);

    arg = (char **)malloc(maxCmdField *sizeof(arg[0]));

    osp_set_prompt();
    {

        memcpy(shellbuf, szCmdNow, strlen(szCmdNow)); 
        shellbuf[strlen(szCmdNow)] = '\0';

        osp_getcmdarg(szCmdNow); 
        ret = osp_execcmd();
        
        if (OSP_ERROR == ret)
        {
            sprintf(shellbuf + strlen(shellbuf), "%s", " > remeotelocalfile");
            system(shellbuf);
            {
                /*just simple cmd is supported*/
                FILE *file;
                file = fopen("./remeotelocalfile", "rb");
                fread(buf, 4096, 1, file);
                //printf("osp_local_shell_main:buf = %s;\n" , buf);
                osp_debug_out(CMD_DEBUG_LEVEL, "%s", buf);
                fclose(file);
            }
            
        }
    }
    free(arg);
    return ret;    
}



int32_t osp_enable_net_shell(void)
{

    osp_resume_task(ospnetshellrx);
    return 0;
}



int32_t osp_disable_net_shell(void)
{
    int32_t udpid;

    udpid= osp_get_rxudp("127.0.0.1", OSP_NETSHELL_RX_PORT);
    osp_del_udp(udpid);

    udpid= osp_get_txudp("127.0.0.1", OSP_NETSHELL_RX_PORT);
    osp_del_udp(udpid);

    return 0;
}

int32_t osp_enable_net_shell_with_port(int32_t port)
{
    int32_t txudpid;
    int32_t rxudpid;
    
    if (port < 0)
    {
        return -1;
    }

    osp_disable_net_shell();
    
    txudpid = osp_create_txucp(port, "127.0.0.1");
    rxudpid = osp_create_rxucp(port);
    
    osp_set_net_task_msg_que(ospnetshellrx, txudpid, rxudpid);
    osp_resume_task(ospnetshellrx);
    return 0;
}


int32_t osp_net_shell_init(void)
{
    osp_suspend_task(CURRENT_TASKID);
    return 0;
}

int32_t osp_net_msg_main(Osp_Msg_Head *pMsg)
{
    struct in_addr addr1;
    uint32_t ip;
    int32_t port;
    Osp_Net_Shell_Head *pShell;
    int32_t udpid;
        
    pShell = (Osp_Net_Shell_Head *)(pMsg + 1);
    ip = pShell->ip;
    port = pShell->port;
    memcpy(&addr1, &ip, 4);

    if (!osp_check_udpid(net_shell_txudp_id))
    {
        udpid = osp_get_txudp(inet_ntoa(addr1), port);
        if (osp_check_udpid(udpid))
        {
            net_shell_txudp_id = udpid;
        }
        else
        {
            net_shell_txudp_id = osp_create_txucp(port, inet_ntoa(addr1));
        }
    }
    else if (net_shell_txudp_id != osp_get_txudp(inet_ntoa(addr1), port))
    {
        osp_del_udp(net_shell_txudp_id);        
        net_shell_txudp_id = osp_create_txucp(port, inet_ntoa(addr1));
    }

    int32_t len = pMsg->MsgSize + MSG_HEAD_SIZE + NET_SHELL_HEAD_SIZE;

    printf("ip:port:res:res1   %d:%d:%d:%d", pShell->ip,
                pShell->port, pShell->res, pShell->res1);
    
    osp_udp_send((char *)(pMsg), len, net_shell_txudp_id);
    osp_free_msg(pMsg);
    return 0;
    
}
int32_t osp_net_shell_main(Osp_Msg_Head *pMsg)
{
    struct in_addr addr1;
    uint32_t ip;
    int32_t port;
    Osp_Net_Shell_Head *pShell;
    int32_t udpid;
        
    pShell = (Osp_Net_Shell_Head *)(pMsg + 1);
    ip = pShell->ip;
    port = pShell->port;
    memcpy(&addr1, &ip, 4);

    if (!osp_check_udpid(net_shell_txudp_id))
    {
        udpid = osp_get_txudp(inet_ntoa(addr1), port);
        if (osp_check_udpid(udpid))
        {
            net_shell_txudp_id = udpid;
        }
        else
        {
            net_shell_txudp_id = osp_create_txucp(port, inet_ntoa(addr1));
        }
    }
    else if (net_shell_txudp_id != osp_get_txudp(inet_ntoa(addr1), port))
    {
        osp_del_udp(net_shell_txudp_id);
        
        net_shell_txudp_id = osp_create_txucp(port, inet_ntoa(addr1));

    }

//    memcpy(&addr1, &(pMsg->SrcId), 4); 

    osp_local_shell_main((char *)(pMsg) + MSG_HEAD_SIZE + NET_SHELL_HEAD_SIZE);
    osp_free_msg(pMsg);
    return 0;
    
}

void osp_set_net_shell_rev(uint32_t data)
{
    net_shell_res = data;
    
}

uint32_t osp_get_net_shell_rev(void)
{
    return net_shell_res;

}


int32_t osp_net_shell_out(Osp_Msg_Head *pMsg)
{
    Osp_Msg_Head *pMsgN;
    int32_t len;
    Osp_Net_Shell_Head *pShell;
    
    if ((NULL == pMsg) || (-1 == net_shell_txudp_id))
    {
        return -1;
    }
    
    len = pMsg->MsgSize + MSG_HEAD_SIZE + NET_SHELL_HEAD_SIZE;
    
    pMsgN = osp_alloc_msg(len);
    if (NULL != pMsgN)
    {
        memcpy((char *)pMsgN, (char *)pMsg, MSG_HEAD_SIZE);
        pMsgN->MsgType = OSP_SHELL_TYPE;
        
        pShell = (Osp_Net_Shell_Head *)(pMsgN+1);
        pShell->ip =  0;
        pShell->port =0;
        pShell->res = osp_get_net_shell_rev();
        
        memcpy((char *)pMsgN + MSG_HEAD_SIZE + NET_SHELL_HEAD_SIZE, (char *)pMsg + MSG_HEAD_SIZE, len);
        
        osp_udp_send((char *)(pMsgN), len, net_shell_txudp_id);
        osp_free_msg(pMsgN);
        
        return 0;
    }
    return -1;
}





