// ConsoleDisplay.cpp: implementation of the ConsoleDisplay class.
//
//////////////////////////////////////////////////////////////////////

#include "ConsoleDisplay.h"
#include <stdio.h>

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////


//Default Constructor
ConsoleDisplay::ConsoleDisplay()
{
	width = def_display_width;
	height = def_display_height;

	screen = GetStdHandle( STD_OUTPUT_HANDLE );
	input = GetStdHandle( STD_INPUT_HANDLE );
    COORD window_size = { width + 2, height + 1 };
    SetConsoleScreenBufferSize( screen, window_size );
}

//Default Destructor
ConsoleDisplay::~ConsoleDisplay()
{
	CloseHandle( screen );
	CloseHandle( input );
}

//  Function receives coordinates and sprite_id, and draws
//	appropriate ascii character at the x,y
void ConsoleDisplay::DrawSprite(int bx, int by, int sprite_id)
{
	char ch;
	WORD col = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;

	switch (sprite_id)
	{
		case SPRITE_PACMAN_UP:
		case SPRITE_PACMAN_DOWN:
		case SPRITE_PACMAN_LEFT:
		case SPRITE_PACMAN_RIGHT:
			col = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
			ch = 'c';
			break;

		case SPRITE_PACMAN_DEAD:
			col = FOREGROUND_RED | FOREGROUND_INTENSITY;
			ch = 'c';
			break;

		case SPRITE_PACMAN_UP_FLASH:
		case SPRITE_PACMAN_DOWN_FLASH:
		case SPRITE_PACMAN_LEFT_FLASH:
		case SPRITE_PACMAN_RIGHT_FLASH:
			col = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
			ch = 'C';
			break;

		case SPRITE_WALL:
			col = FOREGROUND_BLUE;
			ch = (char)178;
			break;

		case SPRITE_GHOST_1:
		case SPRITE_GHOST_2:
		case SPRITE_GHOST_3:
		case SPRITE_GHOST_4:
			col = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
			ch = (char)239;
			break;

		case SPRITE_PELLET:
			col = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
			ch = (char)250;
			break;

		case SPRITE_PELLET_SUPER:
			col = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
			ch = (char)233; //'o';  249
			break;

		case SPRITE_EMPTY:
		default:
			ch = ' ';
			break;
	}
	writexy(bx, by+2, ch, col);
}

//  Function updates menu section at top of screen
void ConsoleDisplay::UpdateScoreStatus(int score) const
{
	writexy(1, 0, "Score: ");
	writexy(8, 0, score);
}

//  Function updates menu section at top of screen
void ConsoleDisplay::UpdateLivesStatus(int lives) const
{
	writexy(13, 0, "Lives: ");
	for (int i=0; i<=lives; i++)
		writexy(20+i, 0, i==lives ? ' ' : 'C', 
			FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
}

//  Function updates menu section at top of screen
void ConsoleDisplay::UpdateLevelStatus(int level) const
{
	char status[12];
	sprintf(status, "Level: %d ", level);
	writexy(30, 0, status);
}

//	Function enables user to write strings directly to the screen
void ConsoleDisplay::DrawString (int bx, int by, const char *s)
{
	writexy(bx, by, s);
}

//	Funtion simply writes blank lines over entire visible screen
void ConsoleDisplay::clear()
{
	char space[79];
	for (int i = 0; i < 80; i++)
		space[i] = ' ';

	DWORD word;
	for( int j = 0; j < height; j++ ) 
	{
		COORD position = { 0, j };
		WriteConsoleOutputCharacter( screen, (char *)&space, 79, position, &word );
	}
}

//	Function handles user input
bool ConsoleDisplay::readchar( char &c, bool &quit )
{
	quit = false;
	unsigned long eventsread;
	int err = GetNumberOfConsoleInputEvents( input, &eventsread );
	if( err == 0 || eventsread == 0 )
		return false;
	err = ReadConsoleInput( input, &ir, 1, &eventsread );
	if( err == 0 || eventsread != 1 || ir.EventType != KEY_EVENT ||
		ir.Event.KeyEvent.bKeyDown == false )
		return false;
	c = ir.Event.KeyEvent.uChar.AsciiChar;
	quit = (c=='q' || c=='Q' || c==27);
	return true;
}

// Returns the display width
int ConsoleDisplay::get_width( )
{
	return width;
}

// Returns the display height
int ConsoleDisplay::get_height( )
{
	return height;
}


//// PRIVATE

// Write a character at a given x and y coordinate, default white color
void ConsoleDisplay::writexy( int x, int y, char c ) const
{
	writexy(x, y, c, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);

//	COORD position = { x, y };
//	DWORD word;
//	WriteConsoleOutputCharacter( screen, &c, 1, position, &word );

}

void ConsoleDisplay::writexy( int x, int y, char c, WORD att) const
{
	COORD position = { x, y };
	DWORD written;  // return spacce for WriteConsole

	SetConsoleTextAttribute(screen, att);
	SetConsoleCursorPosition( screen, position );
	WriteConsole( screen, &c, 1, &written, NULL);
} 


// Write a string at a given x and y coordinate
// if the string does not fit on the line, it will wrap around the screen
void ConsoleDisplay::writexy( int x, int y, const char *s ) const
{
	if( !( s == 0 || *s == '\0' ) ) {
		writexy( x, y, *s );
		if( x < width ) {
			writexy( x + 1, y, &s[1] );
		}
		else if( y < height ) {
			writexy( 1, y + 1, &s[1] );
		}
		else writexy( 1, 1, &s[1] );
	}
}

// Write an integer at a given x and y coordinate
void ConsoleDisplay::writexy( int x, int y, int i ) const
{
	char intstring[10];
	sprintf( intstring, "%d", i );
	writexy( x, y, intstring );
}

void ConsoleDisplay::pause( int time ) const
{
	COORD topleft = { 0, 0 };

	//move cursor to upper-left part of screen
	SetConsoleCursorPosition( screen, topleft );
	Sleep( time );
}