// 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.

///////////////////////////////////////////////////////////////////////////////

// SystemBase.h

///////////////////////////////////////////////////////////////////////////////

#ifndef SYSTEMBASE_H_
#define SYSTEMBASE_H_

// 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 "Basic2D.h"
// #include "Scale.h"
// #include "Scale2D.h"

#include "ConsoleBase.h"
#include "GraphicsState.h"
#include "GraphicsObject.h"
#include "GraphicsWidget.h"

// global function to get the area of the screen available for windows

RectData GetScreenRect();


// minimum and default client size for graphics windows

const short MinimumClientSize = 120;
const short DefaultClientSize = 300;


class EXPORT GraphicsWindow {

	friend class GraphicsObject;
	friend class IndirectObject;

	friend class PolygonWidget;

	friend class PixelWidget;

	friend class MoveToWidget;
	friend class LineWidget;
	friend class LineToWidget;
	friend class DeltaLineWidget;
	friend class DeltaMoveWidget;

	friend class RectWidget;
	friend class OvalWidget;

	friend class ClipRectWidget;

	friend class TransformWidget;

	friend class PolygonWidget2D;

	friend class LineWidget2D;
	friend class LineToWidget2D;
	friend class MoveToWidget2D;
	friend class DeltaLineWidget2D;
	friend class DeltaMoveWidget2D;

	friend class RectWidget2D;
	friend class OvalWidget2D;

	friend class PenSizeWidget;
	friend class PenModeWidget;
	friend class PenColorWidget;
	friend class FillColorWidget;

	friend class TextWidget;
	friend class TextAlignWidget;
	friend class TextColorWidget;

	friend class BackgroundModeWidget;
	friend class BackgroundColorWidget;


	// system dependent friends

#if defined(CORE_PLATFORM_WIN32)

	friend class WIN32_GraphicsState;

#endif	// end WIN32 specific


#if defined(CORE_PLATFORM_MACOS)

	friend class MacOS_GraphicsState;

#endif	// end MacOS specific


private:
	// Maintain knowledge of whether window is open
	// This is crucial since either program or the user can close the window!

	bool WindowIsOpen;

	// Maintain the index of this GraphicsWindow in the GraphicsWindowList

	int WindowIndex;

	// title bar window name
	// has the form "Graphics xxx" where xxx is WindowIndex as text

	char TitleBarName[32];

	// Each constructor should insert a pointer to the window in the GraphicsWindowList
	// Each destructor  should use WindowIndex to set that pointer to null


	// client rectangle information

	SizeData  ClientSize;		// size object: xsize, ysize
	RectData  ClientRect;		// rect object: 0, 0, xsize, ysize

	// full window information

	PointData WindowSpot;		// upper left corner coordinates of window
	RectData  WindowRect;		// rect object for entire window in screen coordinates

	
	// current graphics state

	GraphicsState WindowState;

	// current native graphics state

#if defined(CORE_PLATFORM_WIN32)

	WIN32_GraphicsState NativeState;

#endif	// end WIN32 specific

#if defined(CORE_PLATFORM_MACOS)

	MacOS_GraphicsState NativeState;

#endif	// end MacOS specific
	

	// current refresh draw list

	Array<GraphicsObject*> DrawList;


	// Initialize does the construction details
	// If successful, sets WindowIsOpen to true

	void Initialize(short xsize, short ysize, short xspot, short yspot);


	// PrepareToOpenWindow creates internal data structures
	// Sets WindowIsOpen to true

	void PrepareToOpenWindow();

	// PrepareToCloseWindow deletes internal data structures
	// Sets WindowIsOpen to false

	void PrepareToCloseWindow();

	// call ChangeWindowSpecs to do platform specific move or resize operations

	void ChangeWindowSpecs();


	// insert clone of a graphics object into the DrawList
	// caller must create clone by Clone() operation
	// see GraphicsObject::Draw for sample usage

	void DrawListInsert(GraphicsObject* clone);

	// clear the DrawList and delete its objects

	void DrawListClear();

	// lock the DrawList so no other thread can change it

	void DrawListLock();

	// unlock the DrawList so other threads may access it

	void DrawListUnlock();


	// PrepareClip does system dependent steps to clip images

	void PrepareClip();

	// PrepareText does system dependent steps to show text

	void PrepareText();


	// PrepareGraphics does system dependent steps to prepare window for drawing
	// a single object

	void PrepareGraphics();

	// ReleaseGraphics undoes the steps of PrepareGraphics

	void ReleaseGraphics();


	// PreparePainting does system dependent steps to prepare window for drawing
	// the entire DrawList in a repaint operation

	void PreparePainting();

	// ReleasePainting finishes repaint operation

	void ReleasePainting();

	// paint the contents of the DrawList into the window
	// calls PreparePainting and ReleasePainting

	void DrawListPaint();

	// erase the graphics window and but keep its DrawList

	void EraseWindow();

///////////////////////////////////////////////////////////////////////
//                   BEGIN PLATFORM DEPENDENT CODE                   //

#if defined(CORE_PLATFORM_WIN32)

	friend LRESULT CALLBACK CoreTools_WndProc
		(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

	// variables for dealing with the separate thread for the window

	DWORD  ThreadID;
	HANDLE ThreadHandle;
	HANDLE eventWindowIsReady;	// used to pause application while window is constructed


	// window variables

	HWND hwnd;		// WIN32 handle to a window
	HDC  hdc;		// WIN32 handle to a device context
	PAINTSTRUCT ps;	// WIN32 paint structure for use in window repaint operations


	// critical section to enforce lock on the DrawList

	mutable CRITICAL_SECTION DrawListCS;


	// routine to find GraphicsWindow pointer given an hwnd

	static GraphicsWindow* GWPtr(HWND hwnd);


	// WIN32 specific actions in OpenWindow

	void OpenWindow_WIN32();


	// routine to create thread and window

	void CreateThreadAndWindow();


	// static routine to handle details of window creation and message loop
	// static is essential since thread cannot launch member function of class
	// lp  will hold  this  pointer so GraphicsWindow object data can be accessed

	static DWORD WINAPI CreateWindowAndLoop(LPVOID lp);


	// message loop routine called by CreateWindowAndLoop

	static DWORD WINAPI ThreadWindowMessageLoop();


	// member functions called by CreateWindowAndLoop

	void Create_CoreTools_Window_WIN32();

	void Adjust_CoreTools_Window_WIN32();

	void Update_Window_Data_WIN32();


	// WIN32 specific actions in CloseWindow

	void CloseWindow_WIN32();


	// replacement for the WIN32 line drawing code
	// supports rectangular pens of any size xpen, ypen
	// 
	// helper member function used to draw lines using the region method
	// creates line as a region of pixels

	HRGN WIN32_Line_Region(const PointData& P, const PointData& Q);


	// WIN32 code for displaying regions
	// NormalBrush is the brush to use if the current PenMode is normal

	void WIN32_Show_Region(HRGN Region, HBRUSH NormalBrush);


	// WIN32 test code for repaint operation
	// will not be called in production code

	void TestPaint_WIN32() const;


#endif	// end Win32 specific

///////////////////////////////////////////////////////////////////////

#if defined(CORE_PLATFORM_MACOS)

	CWindowPtr MacWindowPtr;

	void OpenWindow_MACOS();

	void CloseWindow_MACOS();

	void Create_CoreTools_Window_MACOS();

	void Adjust_CoreTools_Window_MACOS();

	void Update_Window_Data_MACOS();

#endif  // end MACOS specific

//                    END PLATFORM DEPENDENT CODE                    //
///////////////////////////////////////////////////////////////////////

public:

	// function to return the index of the pointer to this window object
	// in the GraphicsWindowList

	int Index() const { return WindowIndex; };


	// function that will return the size of the GraphicsWindowList

	EXPORT friend int GraphicsWindowListSize();


	// function that will locate a window by its WindowIndex
	// default of -1 will utilize DefaultGraphicsWindowIndex

	EXPORT friend GraphicsWindow* GraphicsWindowPtr(int index = -1);


	// function that returns the index of current default graphics window

	EXPORT friend int GraphicsWindowIndex();


	// function that sets the index of current default graphics window

	EXPORT friend void SetGraphicsWindow(int index);


	// function that sets the index of current default graphics window
	// using the window index of G

	EXPORT friend void SetGraphicsWindow(const GraphicsWindow& G);


	// In the constructors
	//    xsize and ysize represent the initial size of the client region
	//    xspot and yspot represent coordinates of upper left corner
	//
	// Default values are:
	//    xsize = ysize = DefaultClientSize = 400
	//    xspot = yspot = 0

	GraphicsWindow(short xsize, short ysize, short xspot, short yspot)
		: DrawList(1)
		{ Initialize(xsize, ysize, xspot, yspot); };

	GraphicsWindow(short xsize, short ysize)
		: DrawList(1)
		{ Initialize(xsize, ysize, 0, 0); };

	GraphicsWindow()
		: DrawList(1)
		{ Initialize(DefaultClientSize, DefaultClientSize, 0, 0); };


	// Destructor

	virtual ~GraphicsWindow();


	// function to access native window ptr

	NativeWindowPtr GetNativeWindowPtr() {

#if defined(CORE_PLATFORM_WIN32)

		return hwnd;

#endif	// end Win32 specific


#if defined(CORE_PLATFORM_MACOS)

		return MacWindowPtr;

#endif  // end MACOS specific
	};

	// functions to open and close the window
	// if window is open   then OpenWindow  does nothing
	// if window is closed then CloseWindow does nothing

	void OpenWindow();

	void CloseWindow();

	// member function to determine if the window is open

	bool IsOpen() const { return WindowIsOpen; }

	// make this window foreground

	void MakeForeground() const;


	// the next functions to change the client size and window spot
	// will change the GraphicsWindow data structures
	// but will have a visible effect only if or when the window is open

	// change client size

	void SetClientSize(short xsize, short ysize);

	// change window spot

	void SetWindowSpot(short xspot, short yspot);

	// change client size and window spot

	void SetWindowSpecs(short xsize, short ysize, short xspot, short yspot);


	// get client size

	void GetClientSize(short& xsize, short& ysize) const
		{ ClientSize.Get(xsize, ysize); }

	// get window spot

	void GetWindowSpot(short& xspot, short& yspot) const
		{ WindowSpot.Get(xspot, yspot); };

	// get client size and window spot

	void GetWindowSpecs(short& xsize, short& ysize, short& xspot, short& yspot) const
	{
		ClientSize.Get(xsize, ysize);
		WindowSpot.Get(xspot, yspot);
	};


	// get client rectangle

	RectData GetClientRect() const
		{ return ClientRect; };

	// get entire window rectangle

	RectData GetWindowRect() const
		{ return WindowRect; };

	// get coordinates of entire window

	void GetCoordinates(short& x1, short&y1, short& x2, short& y2) const {
		WindowRect.Get(x1, y1, x2, y2);
	};


	// place this window to the right of console

	void PlaceRightConsole();
	
	// place this window below console
	
	void PlaceBelowConsole();


	// place this window to the right of another graphics window

	void PlaceRight(const GraphicsWindow& G);
	
	// place this window below another graphics window
	
	void PlaceBelow(const GraphicsWindow& G);


	// place this window to the right of another graphics window given by index

	void PlaceRight(int index);
	
	// place this window below another graphics window given by index
	
	void PlaceBelow(int index);


	// return TitleBar string as const char*

	const char* TitleBar() const { return TitleBarName; };


	// return the current graphics state by value

	GraphicsState GetState() const { return WindowState; };

	// clear the graphics window and release its DrawList

	void ClearWindow();

	// force refresh of the graphics window

	void Refresh();

}; // GraphicsWindow


// utility functions


// function to clear a graphics window

inline void ClearGraphicsWindow(GraphicsWindow& G)
	{ G.ClearWindow(); }


// function to clear a graphics window given its index

inline void ClearGraphicsWindow(int index = -1) {
	GraphicsWindow* gwp = GraphicsWindowPtr(index);

	if (gwp)
		gwp->ClearWindow();
}


// function to get the graphics state object given its index

inline GraphicsState GetGraphicsState(int index = -1) {
	GraphicsState   GS;
	GraphicsWindow* gwp = GraphicsWindowPtr(index);

	if(gwp)
		GS = gwp->GetState();

	return GS;
}


#endif // SYSTEMBASE_H_