/*
 *  CHOICE.C - internal command.
 *
 *
 *  History:
 *
 *    12 Aug 1999 (Eric Kohl)
 *        started.
 *
 *    01 Sep 1999 (Eric Kohl)
 *        Fixed help text.
 *
 *    26 Sep 1999 (Paolo Pantaleo)
 *        Fixed timeout.
 *
 *    02 Apr 2005 (Magnus Olsen)
 *        Remove hardcoded strings so that they can be translated.
 *
 */

#include "precomp.h"

#ifdef INCLUDE_CMD_CHOICE


#define GC_TIMEOUT  -1
#define GC_NOKEY    0   //an event occurred but it wasn't a key pressed
#define GC_KEYREAD  1   //a key has been read


static INT
GetCharacterTimeout (LPTCH ch, DWORD dwMilliseconds)
{
//--------------------------------------------
//  Get a character from standard input but with a timeout.
//  The function will wait a limited amount
//  of time, then the function returns GC_TIMEOUT.
//
//  dwMilliseconds is the timeout value, that can
//  be set to INFINITE, so the function works like
//  stdio.h's getchar()

    HANDLE hInput;
    DWORD  dwRead;

    INPUT_RECORD lpBuffer;

    hInput = GetStdHandle (STD_INPUT_HANDLE);

    //if the timeout expired return GC_TIMEOUT
    if (WaitForSingleObject (hInput, dwMilliseconds) == WAIT_TIMEOUT)
        return GC_TIMEOUT;

    //otherwise get the event
    ReadConsoleInput (hInput, &lpBuffer, 1, &dwRead);

    //if the event is a key pressed
    if ((lpBuffer.EventType == KEY_EVENT) &&
        (lpBuffer.Event.KeyEvent.bKeyDown != FALSE))
    {
        //read the key
#ifdef _UNICODE
        *ch = lpBuffer.Event.KeyEvent.uChar.UnicodeChar;
#else
        *ch = lpBuffer.Event.KeyEvent.uChar.AsciiChar;
#endif
        return GC_KEYREAD;
    }

    //else return no key
    return GC_NOKEY;
}

static INT
IsKeyInString (LPTSTR lpString, TCHAR cKey, BOOL bCaseSensitive)
{
    LPTCH p = lpString;
    INT val = 0;

    while (*p)
    {
        if (bCaseSensitive)
        {
            if (*p == cKey)
                return val;
        }
        else
        {
            if (_totlower (*p) == _totlower (cKey))
                return val;
        }

        val++;
        p++;
    }

    return -1;
}


INT
CommandChoice (LPTSTR param)
{
    LPTSTR lpOptions;
    TCHAR Options[6];
    LPTSTR lpText    = NULL;
    BOOL   bNoPrompt = FALSE;
    BOOL   bCaseSensitive = FALSE;
    BOOL   bTimeout = FALSE;
    INT    nTimeout = 0;
    TCHAR  cDefault = _T('\0');
    INPUT_RECORD ir;
    LPTSTR p, np;
    LPTSTR *arg;
    INT    argc;
    INT    i;
    INT    val;

    INT GCret;
    TCHAR Ch;
    DWORD amount,clk;

    LoadString(CMD_ModuleHandle, STRING_CHOICE_OPTION, Options, 4);
    lpOptions = Options;

    if (_tcsncmp (param, _T("/?"), 2) == 0)
    {
        ConOutResPaging(TRUE,STRING_CHOICE_HELP);
        return 0;
    }

    /* retrieve text */
    p = param;

    while (TRUE)
    {
        if (*p == _T('\0'))
            break;

        if (*p != _T('/'))
        {
            lpText = p;
                break;
        }
        np = _tcschr (p, _T(' '));
        if (!np)
            break;
        p = np + 1;
    }

    /* build parameter array */
    arg = split (param, &argc, FALSE, FALSE);

    /* evaluate arguments */
    if (argc > 0)
    {
        for (i = 0; i < argc; i++)
        {
            if (_tcsnicmp (arg[i], _T("/c"), 2) == 0)
            {
                if (arg[i][2] == _T(':'))
                    lpOptions = &arg[i][3];
                else
                    lpOptions = &arg[i][2];

                if (_tcslen (lpOptions) == 0)
                {
                    ConErrResPuts(STRING_CHOICE_ERROR);
                    freep (arg);
                    return 1;
                }
            }
            else if (_tcsnicmp (arg[i], _T("/n"), 2) == 0)
            {
                bNoPrompt = TRUE;
            }
            else if (_tcsnicmp (arg[i], _T("/s"), 2) == 0)
            {
                bCaseSensitive = TRUE;
            }
            else if (_tcsnicmp (arg[i], _T("/t"), 2) == 0)
            {
                LPTSTR s;

                if (arg[i][2] == _T(':'))
                {
                    cDefault = arg[i][3];
                    s = &arg[i][4];
                }
                else
                {
                    cDefault = arg[i][2];
                    s = &arg[i][3];
                }

                if (*s != _T(','))
                {
                    ConErrResPuts(STRING_CHOICE_ERROR_TXT);
                    freep (arg);
                    return 1;
                }

                s++;
                nTimeout = _ttoi(s);
                bTimeout = TRUE;
            }
            else if (arg[i][0] == _T('/'))
            {
                ConErrResPrintf(STRING_CHOICE_ERROR_OPTION, arg[i]);
                freep (arg);
                return 1;
            }
        }
    }

    /* print text */
    if (lpText)
        ConOutPrintf (_T("%s"), lpText);

    /* print options */
    if (bNoPrompt == FALSE)
    {
        ConOutPrintf (_T("[%c"), lpOptions[0]);

        for (i = 1; (unsigned)i < _tcslen (lpOptions); i++)
            ConOutPrintf (_T(",%c"), lpOptions[i]);

        ConOutPrintf (_T("]?"));
    }

    ConInFlush ();

    if (!bTimeout)
    {
        while (TRUE)
        {
            ConInKey (&ir);

            val = IsKeyInString (lpOptions,
#ifdef _UNICODE
                                 ir.Event.KeyEvent.uChar.UnicodeChar,
#else
                                 ir.Event.KeyEvent.uChar.AsciiChar,
#endif
                                 bCaseSensitive);

            if (val >= 0)
            {
                ConOutPrintf (_T("%c\n"), lpOptions[val]);

                nErrorLevel = val + 1;

                break;
            }

            Beep (440, 50);
        }

        freep (arg);
        TRACE ("ErrorLevel: %d\n", nErrorLevel);
        return 0;
    }

    clk = GetTickCount ();
    amount = nTimeout*1000;

loop:
    GCret = GetCharacterTimeout (&Ch, amount - (GetTickCount () - clk));

    switch (GCret)
    {
        case GC_TIMEOUT:
            TRACE ("GC_TIMEOUT\n");
            TRACE ("elapsed %d msecs\n", GetTickCount () - clk);
            break;

        case GC_NOKEY:
            TRACE ("GC_NOKEY\n");
            TRACE ("elapsed %d msecs\n", GetTickCount () - clk);
            goto loop;

        case GC_KEYREAD:
            TRACE ("GC_KEYREAD\n");
            TRACE ("elapsed %d msecs\n", GetTickCount () - clk);
            TRACE ("read %c", Ch);
            if ((val=IsKeyInString(lpOptions,Ch,bCaseSensitive))==-1)
            {
                Beep (440, 50);
                goto loop;
            }
            cDefault=Ch;
            break;
    }

    TRACE ("exiting wait loop after %d msecs\n",
                GetTickCount () - clk);

    val = IsKeyInString (lpOptions, cDefault, bCaseSensitive);
    ConOutPrintf(_T("%c\n"), lpOptions[val]);

    nErrorLevel = val + 1;

    freep (arg);

    TRACE ("ErrorLevel: %d\n", nErrorLevel);

    return 0;
}
#endif /* INCLUDE_CMD_CHOICE */

/* EOF */