#include "console.h"

#include <stdlib.h>
#include <stdio.h>

#ifdef _WIN32
#include <windows.h>

static int get_console_info(HANDLE *h, COORD *pos, DWORD *size) {
    CONSOLE_SCREEN_BUFFER_INFO info;

    *h = GetStdHandle(STD_OUTPUT_HANDLE);
    if( *h == INVALID_HANDLE_VALUE || GetConsoleScreenBufferInfo(*h, &info) == FALSE )
      return -1;

    *pos = info.dwCursorPosition;
    *size = (DWORD)info.dwSize.X * info.dwSize.Y;
    return 0;
}
#endif /* _WIN32 */

void clear_screen() {
#ifdef _WIN32
  static COORD upper_left = {0, 0};
  COORD dummy1;
  DWORD dummy2, size;
  HANDLE hstd_out;

  if( (get_console_info(&hstd_out, &dummy1, &size)) == -1 )
    return;
  
  FillConsoleOutputCharacter(hstd_out, ' ', size, upper_left, &dummy2);
  SetConsoleCursorPosition(hstd_out, upper_left);
#else /* ANSI */
  fputs("\033[2J\033[;H", stdout);
#endif /* _WIN32 */
}

void up_cursor() {
#ifdef _WIN32
  COORD pos;
  DWORD dummy;
  HANDLE hstd_out;

  if( (get_console_info(&hstd_out, &pos, &dummy)) == -1 )
    return;

  --pos.Y;
  SetConsoleCursorPosition(hstd_out, pos);
#else /* ANSI */
  fputs("\033[A", stdout);
#endif /* _WIN32 */
}

void down_cursor() {
#ifdef _WIN32
  COORD pos;
  DWORD dummy;
  HANDLE hstd_out;

  if( (get_console_info(&hstd_out, &pos, &dummy)) == -1 )
    return;

  ++pos.Y;
  SetConsoleCursorPosition(hstd_out, pos);
#else /* ANSI */
  fputs("\033[B", stdout);
#endif /* _WIN32 */
}

void left_cursor() {
#ifdef _WIN32
  COORD pos;
  DWORD dummy;
  HANDLE hstd_out;

  if( (get_console_info(&hstd_out, &pos, &dummy)) == -1 )
    return;

  --pos.X;
  SetConsoleCursorPosition(hstd_out, pos);
#else /* ANSI */
  fputs("\033[D", stdout);
#endif /* _WIN32 */
}

void right_cursor() {
#ifdef _WIN32
  COORD pos;
  DWORD dummy;
  HANDLE hstd_out;

  if( (get_console_info(&hstd_out, &pos, &dummy)) == -1 )
    return;

  ++pos.X;
  SetConsoleCursorPosition(hstd_out, pos);
#else /* ANSI */
  fputs("\033[C", stdout);
#endif /* _WIN32 */
}

void move_cursor(int x, int y) {
#ifdef _WIN32
  COORD dummy1;
  DWORD dummy2;
  HANDLE hstd_out;
  const COORD pos = {x-1, y-1};

    if( (get_console_info(&hstd_out, &dummy1, &dummy2)) == -1 )
    return;

  SetConsoleCursorPosition(hstd_out, pos);
#else /* ANSI */
  printf("\033[%d;%df", y, x);
#endif /* _WIN32 */
}

void get_cursor(int* x, int* y)
{
#ifdef _WIN32
  COORD pos;
  DWORD dummy;
  HANDLE hstd_out;

  if( (get_console_info(&hstd_out, &pos, &dummy)) == -1 )
  {
      *x = 0;
      *y = 0;
  }
  else
  {
      *x = pos.X;
      *y = pos.Y;
  }
#else /* ANSI */
  /* TODO we always return 0/0 as the cursor position */
  *x = 0;
  *y = 0;
#endif /* _WIN32 */
}

void reverse_screen(int c) {
#ifdef _WIN32
	/* No implementation for Windows yet */
#else /* ANSI */
   if (c == 1) {
     fputs("\033[7m", stdout);
   } else {
     fputs("\033[0m", stdout);
   }
	
#endif
}

void set_color(int c)
{
#ifdef _WIN32
    HANDLE h;
    CONSOLE_SCREEN_BUFFER_INFO info;
    WORD bg;

    h = GetStdHandle(STD_OUTPUT_HANDLE);
    if( h == INVALID_HANDLE_VALUE || GetConsoleScreenBufferInfo(h, &info) == FALSE )
        return;

    bg = info.wAttributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
    switch (c)
    {
    case COLOR_WHITE:
        info.wAttributes = bg | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
        break;

    case COLOR_RED:
        info.wAttributes = bg | FOREGROUND_RED;
        break;

    case COLOR_GREEN:
        info.wAttributes = bg | FOREGROUND_GREEN;
        break;

    case COLOR_BLUE:
        info.wAttributes = bg | FOREGROUND_BLUE;
        break;

    case COLOR_BLACK:
        info.wAttributes = bg;
        break;

    case COLOR_PURPLE:
        info.wAttributes = bg | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
        break;

    case COLOR_YELLOW:
        info.wAttributes = bg | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
        break;

    case COLOR_CYAN:
        info.wAttributes = bg | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
        break;

    case COLOR_ORANGE:
        info.wAttributes = bg | FOREGROUND_GREEN | FOREGROUND_BLUE;
        break;

    case COLOR_BROWN:
        info.wAttributes = bg | FOREGROUND_RED | FOREGROUND_GREEN;
        break;

    case COLOR_LTRED:
        info.wAttributes = bg | FOREGROUND_RED | FOREGROUND_INTENSITY;
        break;

    case COLOR_GREY1:
        info.wAttributes = bg | FOREGROUND_RED | FOREGROUND_BLUE;
        break;

    case COLOR_GREY2:
        info.wAttributes = bg | FOREGROUND_INTENSITY;
        break;

    case COLOR_LTGREEN:
        info.wAttributes = bg | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
        break;

    case COLOR_LTBLUE:
        info.wAttributes = bg | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
        break;

    case COLOR_GREY3:
        info.wAttributes = bg | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
        break;
    }

    SetConsoleTextAttribute(h, info.wAttributes);

#else /* ANSI */
int fg,attr;
	fg=37;
	attr=0;
switch (c)
    {
    case COLOR_WHITE: /* Bold white */
        fg=37;
	attr=1;
        break;

    case COLOR_GREY1: /* Bold black is a dark grey */
    case COLOR_BROWN:
        fg=30;
	attr=1;
	break;

    case COLOR_GREY2:
    case COLOR_GREY3:
        fg=37;
	attr=0;
        break;

    case COLOR_RED:
        fg=31;
	attr=0;
        break;

    case COLOR_ORANGE:
    case COLOR_LTRED:
	attr=1;
        fg=31;
        break;

    case COLOR_GREEN:
        fg=32;
	attr=1;
        break;

    case COLOR_LTGREEN:
        fg=32;
	attr=0;
        break;

    case COLOR_BLUE:
	attr=1;
        fg=34;
        break;

    case COLOR_BLACK:
        fg=30;
	attr=0;
        break;

    case COLOR_PURPLE:
	attr=1;
        fg=35; /* Magenta */
        break;

    case COLOR_YELLOW:
	attr=1;
        fg=33;
        break;

    case COLOR_CYAN:
	attr=1;
        fg=36;
        break;

    case COLOR_LTBLUE:
	attr=0;
        fg=36;
        break;
}
printf("\033[%d;%d;40m", attr,fg);

#endif /* _WIN32 */
}
