/* ---------------------------------------------------------------------------
 * menu.c                                               (c) 2008 Micro-key bv
 * ---------------------------------------------------------------------------
 * Micro-key bv
 * Industrieweg 28, 9804 TG Noordhorn
 * Postbus 92, 9800 AB Zuidhorn
 * The Netherlands
 * Tel: +31 594 503020
 * Fax: +31 594 505825
 * Email: support@microkey.nl  
 * Web: www.microkey.nl
 * ---------------------------------------------------------------------------
 * Description: 
 * ---------------------------------------------------------------------------
 * Version(s):  0.1, Apr 01, 2008, MMi
 *                   Creation.
 * ---------------------------------------------------------------------------
 */

/* ---------------------------------------------------------------------------
 * System include files
 * ---------------------------------------------------------------------------
 */
/* Compiler includes */
#include <string.h>
#include <stdlib.h>

/* Hardware includes */
#include "lpc23xx.h"
#include "types.h"

/* FreeRTOS includes */
#include "FreeRTOS.h"
#include "Task.h"
#include "semphr.h"

/* ---------------------------------------------------------------------------
 * Application include files
 * ---------------------------------------------------------------------------
 */
#include "topoftest.h"
#include "menu.h"
#include "menufunctions.h"
#include "menuargs.h"
#include "dac.h"
#include "adc.h"
#include "dio.h"
#include "logging.h"
#include "SerOut.h"

#include "ledfunctions.h"
#include "taskfunctions.h"
#include "BusProtocol.h"

#include "remote_tests.h"
#include "remote_misc.h"

/* ---------------------------------------------------------------------------
 * Local constant and macro definitions
 * ---------------------------------------------------------------------------
 */

/* ---------------------------------------------------------------------------
 * Global variable definitions
 * ---------------------------------------------------------------------------
 */


extern const char *command_table[NUMBER_OF_COMMANDS];
extern const fpointer command_pointer[NUMBER_OF_COMMANDS];
extern UINT8 cmd_table_offset[ALPHABET_DIGITS];
extern const char * menuHelptextArray [NUMBER_OF_COMMANDS];
/* ---------------------------------------------------------------------------
 * Local variable definitions
 * ---------------------------------------------------------------------------
 */
UINT32 arg1 = 0;
UINT32 arg2 = 0;
UINT32 arg3 = 0;

BOOLEAN quit = FALSE;
/* ---------------------------------------------------------------------------
 * Local function definitions
 * ---------------------------------------------------------------------------
 */
void TABfunction (char * command);



void CallMenu(void)
    {
    /* local Variable Declaration                                           */
    UINT32 bytesreceived = 0;
    static UINT8 receiveString[60];
    static UINT8 backupString[60];
    UINT8 buffer;
    BOOLEAN receive;
    
    char separator[] = " ";
    char *commandt;
    char *pcmd;
    char *arg1t;
    char *arg2t;
    char *arg3t;
    UINT8 command[15];
    UINT8 cmd_len;
    
    UINT8 loopcnt;
    BOOLEAN callhelp = FALSE;

    
    do                                  /* do-while loop for Main Menu      */
        {
        /* Display PROMPT to Console                                        */
        serWrite(MenuPort, strlen("\n\r\n\rCMD> "), (UINT8 *)"\n\r\n\rCMD> ");

        /* Reset String input Variables                                     */
        buffer = 0;
        bytesreceived = 0;
        
        commandt = 0;
        cmd_len = 0;
        arg1 = 0;
        arg2 = 0;
        arg3 = 0;
        
        do                              /* do-while loop for String input   */
            {
            if ((receive = serGet(MenuPort, &buffer) == TRUE))
                {
                if (buffer == '\t')
                    {
                    receiveString[bytesreceived] = '\0';
                    TABfunction((char *) receiveString);
                    }
                
                /* Detection of Escape characters. VT100 Commands are 4 Bytes,
                 * so software takes out three more bytes from the buffer.
                 */
                else if (buffer == 27)
                    {
                    serGet(MenuPort, &buffer);                        
                    serGet(MenuPort, &buffer);
//                    serGet(MenuPort, &buffer);
                    
                    /* Detection for LEFT and RIGHT Arrow keys. 
                     * Future implementation may be done for advanced shell
                     */
                    if (buffer =='A')
                        {
                        serWrite(MenuPort, strlen("\x1B[1B"), (UINT8 *)"\x1B[1B");
                        /* UP arrow Key detected                            */
                        if (bytesreceived == 0)
                            {
                            /* If Cursor is on the beginning position       */
                            strcpy ((char *)receiveString, (char *)backupString);
                            bytesreceived = strlen((char *)backupString);
                            serWrite(MenuPort, bytesreceived, backupString);
                            }
                        }
//                    else if (buffer == 'B')
//                        {
//                        /* DOWN arrow Key detected                          */
//                        }
//                        
//                    else if (buffer == 'C')
//                        {
//                        /* RIGHT arrow Key detected                         */
//                        bytesreceived++;
//                        }
//                    else if (buffer == 'D')
//                        {
//                        /* LEFT arrow Key detected                          */
//                        if (bytesreceived > 0)
//                            {
//                            /* If cursor is not on first position           */
//                            bytesreceived--;
//                            }
//                        else
//                            {
//                            /* Move Cursor one position to right (VT100)    */
//                            serWrite(SerOutPort, sizeof("\x1B[1C"), "\x1B[1C");
//                            }
//                        }
                    else
                        {
                        /* Any other Control Key detected. Read and ignore  */
                        serGet(MenuPort, &buffer);
                        }
                    }

                else if (buffer == 127)
                    {
                    /* If pressed key was BackSpace (NOTE KEYCODE, NOT 0x08)*/
                    if (bytesreceived > 0)
                        {
                        /* Cursor is not first position, step back in array */                        
                        receiveString[bytesreceived--] = 0;
                        }
                    else
                        {
                        /* Cursor ist on first position, do not step back   */
                        /* Move Cursor one position to right (VT100)        */
                        serWrite(SerOutPort, strlen("\x1B[1C"), (UINT8 *)"\x1B[1C");
                        }
                    }
                else if (buffer == 13)
                    {
                    receiveString[bytesreceived] = '\0';
                    }
                else
                    {
                    /* Write Byte in String and increase String index       */
                    receiveString[bytesreceived] = buffer;
                    bytesreceived++;
                    }
                vTaskDelay(10);         /* Share Calculation Time           */
                }
            }while (buffer != 13);      /*Read input until ENTER-Key        */
        
        writeLog(LogInput, MenuPort, menuMessage, (char *)receiveString);
        
        /* Copy actual received command string to a backup string           */
        strcpy ((char *)backupString, (char *)receiveString);
        sendString (MenuPort, GotoNewLine, menuMessage,
                "receiveString: ", (char *)receiveString, Dummy);
        sendString (MenuPort, GotoNewLine, menuMessage,
                "backupString:  ", (char *)backupString, Dummy);
        
        /* Split command and arguments with strtok() function, where a
         * SPACE letter is used as devider.
         */
        commandt = strtok ((char *)receiveString, (char *)separator); 
        arg1t = strtok (NULL, (char *)separator);
        arg2t = strtok (NULL, (char *)separator);
        arg3t = strtok (NULL, (char *)separator);
        
        if ((pcmd = strstr ((char *)commandt, "_help")) != NULL)
            {
            callhelp = TRUE;
            sendString (MenuPort, GotoNewLine, menuMessage,
                    "Help Stat recognised ", Dummy, Dummy);
            
            /* Copy command to an own string                                    */
            cmd_len = strlen (commandt);
            strncpy ((char *)command, commandt, (cmd_len - 5));
            command[cmd_len - 5] = '\0';
            }
        else
            {
            callhelp = FALSE;
            
            /* Copy command to an own string                                    */
            strcpy ((char *)command, commandt);

            /* Detect if arguments are given dezimal or hexadezimal. Detection
             * looks for a leading "0x" on the string. Afterwards, the given
             * Value is transformed to an integer value with sscanf. No Error
             * checking. The value is transformed step by step until the string-
             * end token or the first not-hex symbol.
             */
            if ((arg1t[0] == 48) && (arg1t[1] == 120))
                {
                /* First Argument is given in Hex, transform value          */
                sscanf((char *)(arg1t), "%x", &arg1);
                } 
            else
                {
                /* First argument is given dezimal, cast to integer         */
                arg1 = (UINT32) atoi((char *) (arg1t));
                }
            
            if ((arg2t[0] == 48) && (arg2t[1] == 120))
                {
                /* Second Argument is given in Hex, transform value         */
                sscanf((char *)(arg2t), "%x", &arg2);
                } 
            else
                {
                /* Second argument is given dezimal, cast to integer        */
                arg2 = (UINT32) atoi((char *) (arg2t));
                }
            
            if ((arg3t[0] == 48) && (arg3t[1] == 120))
                {
                /* Third Argument is given in Hex, transform value          */
                sscanf((char *)(arg3t), "%x", &arg3);
                } 
            else
                {
                /* Third argument is given dezimal, cast to integer         */
                arg3 = (UINT32) atoi((char *) (arg3t));

                }
            }
        
        sendString (MenuPort, GotoNewLine, menuMessage,
                "commandt: ", (char *)commandt, Dummy);
        sendString (MenuPort, FALSE, menuMessage,
                "\tcommand: ", (char *)command, Dummy);
        sendString (MenuPort, GotoNewLine, menuMessage,
                "arg1t: ", (char *)arg1t, Dummy);
        sendString (MenuPort, FALSE, menuMessage,
                "\targ1: ", ItoDStr(arg1), Dummy);
        sendString (MenuPort, GotoNewLine, menuMessage,
                "arg2t: ", (char *)arg2t, Dummy);
        sendString (MenuPort, FALSE, menuMessage,
                "\targ2: ", ItoDStr(arg2), Dummy);
        sendString (MenuPort, GotoNewLine, menuMessage,
                "arg3t: ", (char *)arg3t, Dummy);
        sendString (MenuPort, FALSE, menuMessage,
                "\targ3: ", ItoDStr(arg3), Dummy);
        

        /* Advanced Search algorithm for commands                           */
        /* Menu structure is based on 2 tables for the commands and one more
         * as offset.
         * The given command is first checked on a valid first letter. If 
         * valid, this letter is compared with the offset table. If an offset
         * is defines for the first letter, at least commands with this first
         * letter exist. Do a string compare starting at the address in the
         * command array given by the offset for the first letter. This 
         * prevents of scanning all commands beginning with a different letter
         */
        
        if ((command[0] >= 97) && (command[0] <= 122))
            {
            /* First sign of command is within specified Range              */
            if (cmd_table_offset[(command[0] - 97)] != 0xFF)
                {
                /* If Offset for specified letter is available              */
                for (loopcnt = (cmd_table_offset[(command[0] - 97)]); 
                     loopcnt < NUMBER_OF_COMMANDS; 
                     loopcnt++)
                    {
                    /* Try to find the typed in command starting on the
                     * offset position given with the first letter.
                     */
                    if (strcmp ((char *)command, command_table[loopcnt]) == 0)
                        {
                        /* Found a valid command!
                         * Use the found array-index to grip the corresponding
                         * function pointer from pointer-array
                         */
                        if (callhelp == FALSE)
                            {
                            (*command_pointer[loopcnt])();
                            }
                        else
                            {
                            sendString (MenuPort, TRUE, importantMessage,
                                    (char *) menuHelptextArray[loopcnt], Dummy, Dummy);
//                            debugPrint((char *)menuHelptextArray[loopcnt]);
                            }
                        break;
                        }
                    if (loopcnt == (NUMBER_OF_COMMANDS - 1))
                        {
                        /* No valid command was found. give Error Emssage   */
                        sendString (MenuPort, TRUE, importantMessage,
                                (char *) command," - No such command!", Dummy);
                        }
                    }
                }
            else
                {
                /* No Offset available for the specified letter             */
                sendString (MenuPort, TRUE, importantMessage,
                        (char *) command," - No such command!", Dummy);
                }
            }
        else
            {
            /* First letter is out of the specified Range                   */
            sendString (MenuPort, TRUE, importantMessage,
                    (char *) command," - No such command!", Dummy);
            }


        receiveString[0] = '\0';
         
        vTaskDelay(100);
        } while (quit == FALSE);
}


void TABfunction (char * command)
{
    UINT32 loopcnt;
    UINT32 commandlength;
    
    commandlength = strlen (command);
    serWrite (MenuPort, strlen ("\n\r\t\t"), (UINT8 *)"\n\r\t\t");
    
    if ((command[0] >= 97) && (command[0] <= 122))
        {
        /* First sign of command is within specified Range              */
        if (cmd_table_offset[(command[0] - 97)] != 0xFF)
            {
            /* If Offset for specified letter is available              */
            for (loopcnt = (cmd_table_offset[(command[0] - 97)]); 
                 loopcnt < NUMBER_OF_COMMANDS; 
                 loopcnt++)
                {
                if (strncmp ((char *)command, command_table[loopcnt], commandlength) == 0)
                    {
                    sendString (MenuPort, FALSE, importantMessage,
                            "  ", (char *)command_table[loopcnt], Dummy);
                    }
                }
            }
        else
            {
            
            }
        }
    
    /* Display PROMPT to Console                                            */
    serWrite(MenuPort, strlen("\n\r\n\rCMD> "), (UINT8 *)"\n\r\n\rCMD> ");
    serWrite (MenuPort, strlen (command), (UINT8 *)command);
    
}
