// Copyright 1999
// College of Computer Science
// Northeastern University Boston MA 02115

// This software may be used for educational purposes as long as this copyright
// notice is retained at the top of all files

// Should this software be modified, the words "Modified from Original" must be
// included as a comment below this notice

// All publication rights are retained.  This software or its documentation may
// not be published in any media either in whole or in part.

///////////////////////////////////////////////////////////////////////////////

// ConsoleBase.cpp

///////////////////////////////////////////////////////////////////////////////

// The commented include files are brought in by later include directives

// #include "Platform.h"
// #include "CHeaders.h"
// #include "MathUtil.h"
// #include "GeoTypes.h"
// #include "RGB.h"
// #include "ConsoleBase.h"
// #include "GraphicsObject.h"

#include "CoreTools.h"
#include "SystemBase.h"


bool InitializeConsoleDone = false;


#if defined(CORE_PLATFORM_WIN32)

HWND console_hwnd;

#endif	// end WIN32 specific


#if defined(CORE_PLATFORM_MACOS)

#endif	// end MacOS specific


void InitializeConsole() {

	// InitializeConsole will only act once

	if (InitializeConsoleDone)
		return;

	InitializeConsoleDone = true;


#if defined(CORE_PLATFORM_WIN32)

	// this code depends on the fact that graphics windows cannot open
	// without calling InitializeConsole
	//
	// therefore at this stage the console window is in the foreground
	//
	// we must make sure that the thread opening the console window is
	// done with its work

	const clock_t smalllimit = CLOCKS_PER_SEC;			// 1 second
	const clock_t largelimit = 2 * 60 * CLOCKS_PER_SEC;	// 2 minutes

	clock_t initial = clock();	// initial time
	clock_t current = initial;	// current time

	// delay 1 second

	while((current - initial) < smalllimit)
		current = clock();

	// now try to get console hwnd
	// exit program if unsuccessful

	initial = current;

	while (! (console_hwnd = GetForegroundWindow())) {
		current = clock();

		if ((current - initial) > largelimit)
			exit(EXIT_FAILURE);
	};

#endif	// end WIN32 specific


#if defined(CORE_PLATFORM_MACOS)

#endif	// end MacOS specific


	// make the default console location the upper left of the screen

	SetConsoleWindowSpot(0, 0);
}


NativeWindowPtr GetConsoleNativeWindowPtr(){

InitializeConsole();


#if defined(CORE_PLATFORM_WIN32)

	return console_hwnd;

#endif	// end WIN32 specific


#if defined(CORE_PLATFORM_MACOS)

	// not yet defined

#endif	// end MacOS specific
}


void MakeConsoleForeground() {
	InitializeConsole();


#if defined(CORE_PLATFORM_WIN32)

	SetForegroundWindow(console_hwnd);

#endif	// end WIN32 specific


#if defined(CORE_PLATFORM_MACOS)

#endif	// end MacOS specific

}


void SetConsoleClientSize(short xsize, short ysize) {
	InitializeConsole();

	// find current client size
	// if no change then return

	short xcs, ycs;

	GetConsoleClientSize(xcs, ycs);

	if ((xsize == xcs) && (ysize == ycs))
		return;


	// enforce minimum console size

	SizeData ConsoleSize(xsize, ysize, MinimumClientSize, MinimumClientSize);
	ConsoleSize.Get(xsize, ysize);


#if defined(CORE_PLATFORM_WIN32)

	// find current window rect and its specs

	RectData Entire;
	short x1, y1, x2, y2, xExtra, yExtra;

	Entire = GetConsoleWindowRect();
	Entire.Get(x1, y1, x2, y2);

	// find extras needed for border

	xExtra = (x2 - x1) - xcs;
	yExtra = (y2 - y1) - ycs;

	// change the entire window size

	xsize += xExtra;
	ysize += yExtra;

	SetWindowPos(console_hwnd, HWND_TOP, 0, 0, xsize, ysize, SWP_NOMOVE);

#endif	// end WIN32 specific


#if defined(CORE_PLATFORM_MACOS)

#endif	// end MacOS specific

}


void SetConsoleWindowSpot(short xspot, short yspot) {
	InitializeConsole();

	// find current window spot
	// if no change then return

	short xsp, ysp;

	GetConsoleWindowSpot(xsp, ysp);

	if ((xspot == xsp) && (yspot == ysp))
		return;


	// make sure that window spot is reasonable

	AdjustWindowSpot(xspot, yspot);


#if defined(CORE_PLATFORM_WIN32)

	SetWindowPos(console_hwnd, HWND_TOP, xspot, yspot, 0, 0, SWP_NOSIZE);

#endif	// end WIN32 specific


#if defined(CORE_PLATFORM_MACOS)

#endif	// end MacOS specific

}


void SetConsoleWindowSpecs(short xsize, short ysize, short xspot, short yspot) {
	SetConsoleClientSize(xsize, ysize);
	SetConsoleWindowSpot(xspot, yspot);
}

	
void GetConsoleClientSize(short& xsize, short& ysize)  {
	InitializeConsole();

	RectData Client;
	short x1, y1, x2, y2;

	Client = GetConsoleClientRect();
	Client.Get(x1, y1, x2, y2);

	xsize = x2 - x1;
	ysize = y2 - y1;
}


void GetConsoleWindowSpot(short& xspot, short& yspot) {
	InitializeConsole();

	short x2, y2;	// need only for call below

	GetConsoleCoordinates(xspot, yspot, x2, y2);
}


void GetConsoleWindowSpecs(short& xsize, short& ysize, short& xspot, short& yspot) {
	GetConsoleClientSize(xsize, ysize);
	GetConsoleWindowSpot(xspot, yspot);
}


RectData GetConsoleClientRect() {
	InitializeConsole();

	RectData Client;
	NativeRectData NativeClient;


#if defined(CORE_PLATFORM_WIN32)
	
	::GetClientRect(console_hwnd, &NativeClient);

#endif	// end WIN32 specific


#if defined(CORE_PLATFORM_MACOS)

#endif	// end MacOS specific


	Client = NativeClient;
	return Client;
}


RectData GetConsoleWindowRect() {
	InitializeConsole();

	RectData Entire;
	NativeRectData NativeEntire;


#if defined(CORE_PLATFORM_WIN32)
	
	::GetWindowRect(console_hwnd, &NativeEntire);

#endif	// end WIN32 specific


#if defined(CORE_PLATFORM_MACOS)

#endif	// end MacOS specific


	Entire = NativeEntire;
	return Entire;
}


void GetConsoleCoordinates(short& x1, short&y1, short& x2, short& y2) {
	InitializeConsole();

	RectData Entire;

	Entire = GetConsoleWindowRect();
	Entire.Get(x1, y1, x2, y2);
}


void ConsolePlaceRight(const GraphicsWindow& G) {
	InitializeConsole();

	short x1, y1, x2, y2;
	
	G.GetCoordinates(x1, y1, x2, y2);

	SetConsoleWindowSpot(x2, y1);
}


void ConsolePlaceBelow(const GraphicsWindow& G) {
	InitializeConsole();

	short x1, y1, x2, y2;
	
	G.GetCoordinates(x1, y1, x2, y2);

	SetConsoleWindowSpot(x1, y2);
}


void ConsolePlaceRight(int index) {

	GraphicsWindow* gwp = GraphicsWindowPtr(index);

	if(gwp)
		ConsolePlaceRight(*gwp);
}


void ConsolePlaceBelow(int index) {

	GraphicsWindow* gwp = GraphicsWindowPtr(index);

	if(gwp)
		ConsolePlaceBelow(*gwp);
}


EXPORT void AdjustWindowSpot(short& xspot, short& yspot) {

	// get screen area

	RectData ScreenRect;
	short x1, y1, x2, y2;

	ScreenRect = GetScreenRect();
	ScreenRect.Get(x1, y1, x2, y2);

	// enforce minimum overlap of console window with screen area
	// but allow window to be partially off screen

	if (xspot > (x2 - MinimumClientSize))
		xspot = (x2 - MinimumClientSize);

	if (yspot > (y2 - MinimumClientSize))
		yspot = (y2 - MinimumClientSize);

	// do not allow window to move above or to the left of screen

	if (xspot < x1)
		xspot = x1;

	if (yspot < y1)
		yspot = y1;
}
