// $Id: cio_windows.h,v 1.9 2011/03/22 00:26:10 lpoulsen Exp $
// Copyright (C) 2001 Wi_LAN Technologies, Inc
//
// $Log: cio_windows.h,v $
// Revision 1.9  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.8  2008/07/11 16:28:46  lpoulsen
// Econ 4.00 release candidate supports UPDATE and SELECT commands.
//
// Revision 1.7  2008/06/10 00:06:10  lpoulsen
// New -X option is now working
// Updated -I and -O implementation
//
// Revision 1.6  2008/05/10 01:17:37  lpoulsen
// Making econ -x filename work (not yet complete)
//
// Revision 1.5  2002/04/19 19:04:44  mourlouk
// Release 1.15 - It fixes a bug that was introduced in version 1.13 (econ unable to
// read properly multiple MAC addresses)
//
// Revision 1.3  2001/10/31 02:21:11  mourlouk
// Changed the clear_screen method
//
// Revision 1.2  2001/10/30 01:07:45  lpoulsen
// Add "module ID" statement, audit trail generator and copyright line
// Remove "win_or_linux.h" and use a -D in Linux makefile instead.
//
//
#include <windows.h>
#include <process.h>
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <windowsx.h>

void setNormalTextBackground();
void setReverseTextBackground();
void setBlackOnWhite(HANDLE hConsole);
void setWhiteOnBlack(HANDLE hConsole);
int moveCursor(int rows, int columns);
void clear_screen(HANDLE hConsole);

extern int kbhit_nolock(void);
extern int getch_nolock(void);

extern BOOL  isWinNT;
extern intptr_t _coninpfh;

int 
a_getch()
{
    int   keyPressed;

    while (!kbhit_nolock())
    {
        Sleep(5);
        if (econ_phase == ECON_CLOSE_THREADS)
            return EOF;
    }

    keyPressed = getch_nolock();

    switch (keyPressed)
    {
            case 0xE0:                 // -32
                keyPressed = getch_nolock();
                switch (keyPressed)
                {
                case 72:
                    keyPressed = ctrl('P');  // up arrow
                    break;
                case 80:
                    keyPressed = ctrl('N');  // down arrow
                    break;
                case 75:
                    keyPressed = ctrl('B');  // left arrow
                    break;
                case 77:
                    keyPressed = ctrl('F');  // right arrow
                    break;
                case 83:
                    keyPressed = ctrl('D');  // del
                    break;
                case 71:
                    keyPressed = ctrl('A');  // home
                    break;
                case 79:
                    keyPressed = ctrl('E');  // end
                default:
                    keyPressed = 0;     // unsupported function key
                }
                break;
            case 0:
                keyPressed = getch_nolock();
                switch (keyPressed)
                {
                case 59:               // F1
                    return F1_KEY;
                    break;
                case 60:               // F2
                    return F2_KEY;
                    break;
                case 61:               // F3
                    return F3_KEY;
                    break;
                case 62:               // F4
                    return F4_KEY;
                    break;
                case 63:               // F5
                    return F5_KEY;
                    break;
                case 64:               // F6
                    return F6_KEY;
                    break;
                case 65:
                    return F7_KEY;
                    break;
                default:
                    return UNKNOWN_KEY;
                    break;
                }
                break;
            case 18:
                keyPressed = ctrl('R');
                break;
            case 27:                   // ESC
                return ESC_KEY;
                break;
            default:
                ;                // all other characters stand for themselves
    }
    return keyPressed;
}

void 
initCIOSettings()
{
    static BOOL firstTime = FALSE;

    if (firstTime)
    {
        HANDLE cur_screen;
        COORD sbufsize;
        char ucon_title[128];

        cur_screen = GetStdHandle(STD_OUTPUT_HANDLE);

        sbufsize.X = 80;
        sbufsize.Y = 256;
        SetConsoleScreenBufferSize(cur_screen, sbufsize);
        strcpy(ucon_title, "UConsole");
        SetConsoleTitle(ucon_title);

        firstTime = FALSE;
    }
}

void 
restoreCIOSettings()
{

}

char
ctrl(char control_key)
{
    return control_key & 0x1F;
}

void
e_print(char c)
{
    static char p1 = 0, p2 = 0;
    static BOOL isEscSequence = FALSE;

    if (isEscSequence)
    {
        if (p1)
        {
            p2 = c;

            if ((p1 == '[') && (p2 == 'A'))  // up arrow

                moveCursor(-1, 0);
            if ((p1 == 0x5B) && (p2 == 0x44))  // left arrow

                moveCursor(0, 1);
            if ((p1 == '[') && (p2 == 'H'))  // home

                moveCursor(0, -80);
            if ((p1 == '[') && (p2 == 'J'))  // clear_to_end_of_screen

            {
                clear_screen(GetStdHandle(STD_OUTPUT_HANDLE));
            }
            p1 = p2 = 0;
            isEscSequence = FALSE;
        }
        else
            p1 = c;
    }
    else if (c == 27)
    {
        isEscSequence = TRUE;
    }
    else
    {
        putchar(c);
        fflush(stdout);
    }
}

void
reverseScreenSettings()
{
    /* important note:
       It seems that there is a problem with the scroll capability
       under Win9X platform. Even though with WinNT it behaves as
       expected, under Win9x the screen will halt for no particular
       reason when the side scroll bar reaches the bottom
     */

    static int NoScrollScreen = TRUE;
    COORD sbufsize;
    HANDLE cur_screen;

    if (!isWinNT)
        return;

    if (NoScrollScreen)
    {
        cur_screen = GetStdHandle(STD_OUTPUT_HANDLE);
        sbufsize.X = 80;
        sbufsize.Y = 128;
        SetConsoleScreenBufferSize(cur_screen, sbufsize);
    }
    else
    {
        cur_screen = GetStdHandle(STD_OUTPUT_HANDLE);
        sbufsize.X = 80;
        sbufsize.Y = 50;
        SetConsoleScreenBufferSize(cur_screen, sbufsize);
    }
}

void
reverseColorSettings()
{
    static int WhiteOnBlack = TRUE;
    if (WhiteOnBlack)
    {
        setReverseTextBackground();
        WhiteOnBlack = FALSE;
    }
    else
    {
        setNormalTextBackground();
        WhiteOnBlack = TRUE;
    }
}

void
setNormalTextBackground()
{
    // white on black
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    setWhiteOnBlack(hConsole);
    SetConsoleTextAttribute(hConsole,
                            FOREGROUND_RED | FOREGROUND_GREEN |
                            FOREGROUND_BLUE | FOREGROUND_INTENSITY);
}

void
setReverseTextBackground()
{
    // black on white
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    setBlackOnWhite(hConsole);
    SetConsoleTextAttribute(hConsole,
                            BACKGROUND_RED | BACKGROUND_GREEN |
                            BACKGROUND_BLUE | BACKGROUND_INTENSITY);
}

void 
setBlackOnWhite(HANDLE hConsole)
{
    COORD coordScreen =
    {0, 0};                     /* here's where we'll home the
                                   cursor */
    BOOL bSuccess;
    DWORD cCharsWritten;
    CONSOLE_SCREEN_BUFFER_INFO csbi;  /* to get buffer info */
    DWORD dwConSize;            /* number of character cells in
                                   the current buffer */

    /* get the number of character cells in the current buffer */

    bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi);
    dwConSize = csbi.dwSize.X * csbi.dwSize.Y;

    /* get the current text attribute */

    bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi);

    /* now set the buffer's attributes accordingly */

    csbi.wAttributes = BACKGROUND_RED | BACKGROUND_GREEN |
        BACKGROUND_BLUE | BACKGROUND_INTENSITY;

    bSuccess = FillConsoleOutputAttribute(hConsole, csbi.wAttributes,
                                    dwConSize, coordScreen, &cCharsWritten);

    return;
}

void 
setWhiteOnBlack(HANDLE hConsole)
{
    COORD coordScreen =
    {0, 0};                     /* here's where we'll home the
                                   cursor */
    BOOL bSuccess;
    DWORD cCharsWritten;
    CONSOLE_SCREEN_BUFFER_INFO csbi;  /* to get buffer info */
    DWORD dwConSize;            /* number of character cells in
                                   the current buffer */

    /* get the number of character cells in the current buffer */

    bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi);
    dwConSize = csbi.dwSize.X * csbi.dwSize.Y;

    /* get the current text attribute */

    bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi);

    /* now set the buffer's attributes accordingly */

    csbi.wAttributes = FOREGROUND_RED | FOREGROUND_GREEN |
        FOREGROUND_BLUE | FOREGROUND_INTENSITY;

    bSuccess = FillConsoleOutputAttribute(hConsole, csbi.wAttributes,
                                    dwConSize, coordScreen, &cCharsWritten);

    return;
}

void 
clear_screen(HANDLE hConsole)
{
    COORD coordScreen =
    {0, 0};                     /* here's where we'll home the
                                   cursor */
    BOOL bSuccess;
    DWORD cCharsWritten;
    CONSOLE_SCREEN_BUFFER_INFO csbi;  /* to get buffer info */
    DWORD dwConSize;            /* number of character cells in
                                   the current buffer */

    /* get the number of character cells in the current buffer */

    bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi);
    dwConSize = csbi.dwSize.X * csbi.dwSize.Y;

    /* fill the entire screen with blanks */
    coordScreen.X = csbi.dwCursorPosition.X;
    coordScreen.Y = csbi.dwCursorPosition.Y;

    bSuccess = FillConsoleOutputCharacter(hConsole, (TCHAR) ' ',
                                    dwConSize, coordScreen, &cCharsWritten);

    /* get the current text attribute */

    bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi);

    /* now set the buffer's attributes accordingly */

    bSuccess = FillConsoleOutputAttribute(hConsole, csbi.wAttributes,
                                    dwConSize, coordScreen, &cCharsWritten);

    /* put the cursor at (0, 0) */

    bSuccess = SetConsoleCursorPosition(hConsole, coordScreen);
    return;
}

int
moveCursor(int rows, int columns)
{
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    if (INVALID_HANDLE_VALUE != hConsole)
    {
        COORD pos;
        CONSOLE_SCREEN_BUFFER_INFO bInfo;
        GetConsoleScreenBufferInfo(hConsole, &bInfo);

        if (columns == -80)     // this implies HOME

        {
            pos.X = 0;
            pos.Y = 0;
        }
        else
        {
            pos.X = bInfo.dwCursorPosition.X + columns;
            pos.Y = bInfo.dwCursorPosition.Y + rows;
        }

        SetConsoleCursorPosition(hConsole, pos);

    }

    return 0;
}

BOOL WINAPI 
CtrlHandler(DWORD dwEvent)
{
    switch (dwEvent)
    {
    case CTRL_C_EVENT:
        printf("Got CTRL_C_EVENT\n");
        break;

    case CTRL_BREAK_EVENT:
        printf("Got CTRL_BREAK_EVENT\n");
        break;

    case CTRL_LOGOFF_EVENT:
        printf("Got CTRL_LOGOFF_EVENT\n");
        break;

    case CTRL_SHUTDOWN_EVENT:
        printf("Got CTRL_SHUTDOWN_EVENT\n");
        break;

    case CTRL_CLOSE_EVENT:
        printf("Got CTRL_CLOSE_EVENT\n");
        break;

    default:
        // unknown type--better pass it on.
        return (FALSE);
    }
    // Handled all known events
    return (TRUE);
}

void 
handleConsoleEvents()
{
    SetConsoleCtrlHandler(CtrlHandler, TRUE);
}
