#include "..\global.hpp"

#include "..\ErrorControlObj\ErrorControlObj.hpp"
#include "WindowObj.hpp"



// --------------------------------------------------------------------------------------------
// BEGIN window details
// --------------------------------------------------------------------------------------------


// This array determines which of the vmodes tested ok 0=fail 1=pass
int	validres[12];


// --------------------------------------------------------------------------------------------
// END window details
// --------------------------------------------------------------------------------------------

  



/*	Some of the things that can be done with the window
			        Tytle,          Win width_height      PFD > 0

	// Open the window first
	ge.openWindow( " Window Title Bar", v640_480, FULLSCREEN, 1 );
	ge.openWindow( " THE MONSTER GAME ", v640_480, WINDOWED, 1 );
	 
	// after that change the resolution to anything you like as much as you like
	ge.changeResolution ( v1024_768 );
	ge.changeResolution ( v800_600 );

	// make the window smaller than the resolution ( makes it appear windowed )
	// as much as you like
	ge.changeWindow ( ((640-300)/2), ((480-200)/2), 300, 200, v640_480 );
*/

 win::win ( void ) {
	 // Definition of all the video modes
	 struct vmode_t v[NUMRES] =	{
			{  320, 200   },		{  320, 240   },
			{  400, 300   },		{  480, 360   },
			{  512, 384   },		{  640, 480   },
			{  800, 600   },		{  960, 720   },
			{  1024, 768  },		{  1152, 864  },
			{  1280, 960  },		{  1280, 1024 }
		};

	 this->vmodes =  new struct vmode_t[NUMRES];

	 for ( int i=0; i< NUMRES; i++ )
		 this->vmodes[i] = v[i];

}



// --------------------------------------------------------------------------------------------
// BEGIN Window Class Registration
//
// this only happens once during the programs execution
// Created:		Friday 3rd November 2000
// Last Change: Sunday 5th November 2000
// --------------------------------------------------------------------------------------------
int win::regClass ( WNDPROC MainWndProc , HINSTANCE hInst, char *className) {
	WNDCLASS	wc;


	// If a class had been registered, then dont register any more classes
	if ( this->classActive ) {
		return CLASS_ALREADY_REGISTERED;
	}

	// WNDCLASS is the class definition structure
	memset( &wc, 0, sizeof(WNDCLASS) );

	// populate our class, no special features needed
	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wc.lpfnWndProc		= (WNDPROC)MainWndProc;
	wc.cbClsExtra		= 0;
	wc.cbWndExtra		= 0;
	wc.hInstance		= hInst;
	wc.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground	= NULL;
	wc.lpszMenuName	= NULL;
	wc.lpszClassName	= className;

	// Register the class with the operating system
	if (!RegisterClass ( &wc ) ) {
		this->hInst = NULL;
		this->classActive = 0;
		this->className = NULL;
		return REGISTER_CLASS_FAILED;
	}

	// If all went well
	this->classActive = true;
	this->className = className;
	this->hInst = hInst;
	return CLASS_REGISTER_SUCCESS;
}
// --------------------------------------------------------------------------------------------
// END Window Class Registration
// --------------------------------------------------------------------------------------------

  














// --------------------------------------------------------------------------------------------
// BEGIN Change monitor resolution
//
// Created:		Friday 3rd November 2000
// Last Change: Sunday 5th November 2000
// --------------------------------------------------------------------------------------------

int win::changeResolution (int resId ) {
	DEVMODE devmode;
	int val;


	memset ( &devmode, 0, sizeof (DEVMODE) );

	devmode.dmSize = sizeof (DEVMODE);

	// Grab a copy of current video configuration
	EnumDisplaySettings (NULL, 0, &devmode);

	// Insert new resolution parameters
	devmode.dmPelsWidth = vmodes[resId].w;
	devmode.dmPelsHeight = vmodes[resId].h;
	devmode.dmBitsPerPel = 24;

	// Tell the system to Only apply the new width and height
	devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;

	// Ask system to change monitor resolution on the fly, CDS_FULLSCREEN = temporary reversable change
	val = ChangeDisplaySettings(&devmode, CDS_FULLSCREEN);
	
	// See what went wrong, IF it went wrong at all
	switch ( val ) {
	case DISP_CHANGE_RESTART:
		fprintf(fp,"\nThe computer must be restarted in order for the graphics mode to work.\n");
		break;
	case DISP_CHANGE_BADFLAGS:
		fprintf(fp,"\nAn invalid set of flags was passed in.\n");
		break;
	case DISP_CHANGE_FAILED:
		fprintf(fp,"\nThe display driver failed the specified graphics mode.\n");
		break;
	case DISP_CHANGE_BADMODE:
	case DISP_CHANGE_BADPARAM:
		fprintf(fp,"\nThe graphics mode is not supported.\n");
		break;
	case DISP_CHANGE_NOTUPDATED:
		fprintf(fp,"\nUnable to write settings to the registry.\n");
		break;
	case DISP_CHANGE_SUCCESSFUL:
		fprintf(fp,"\n Change Resolution Success.\n");
		break;
	default:
		fprintf(fp,"Unknown error: %d\n", val);
		break;
	}

	// return a result
	if (val == DISP_CHANGE_SUCCESSFUL )
		return MONITOR_RESOLUTION_CHANGED_OK;
	else
		return MONITOR_RESOLUTION_FAILURE;
}
// --------------------------------------------------------------------------------------------
// END Change monitor resolution
// --------------------------------------------------------------------------------------------

  














// --------------------------------------------------------------------------------------------
// BEGIN Window Create
//
// Created:		Friday 3rd November 2000
// Last Change: Sunday 5th November 2000
// --------------------------------------------------------------------------------------------

int win::openWindow ( char *winTitle ,int resId, int resType) {

	int errCode;

	// this is the base opengl window styles
//	DWORD baseStyles	= WS_POPUP  | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
	DWORD baseStyles	= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
	// additional styles for windowed mode
//	DWORD windowStyles	= WS_BORDER | WS_CAPTION;
	DWORD windowStyles	= 0; //WS_BORDER | WS_CAPTION;

	this->activeResolution = resId;

	// Only one window alowed
	if ( this->hWnd )
		return WINDOW_EXISTS;

	// set the monitor hardware resolution to match the window size when goin full screen
	if ( resType == FULLSCREEN )
		errCode = changeResolution ( resId );

	// if any problems then return
	if ( errCode == MONITOR_RESOLUTION_FAILURE )
		return MONITOR_RESOLUTION_FAILURE;

	// if its not full screen mode then add window border and tytle bar
	if ( resType == WINDOWED )
		baseStyles = baseStyles | windowStyles;

	// create the window now
   this->hWnd = CreateWindow (
	   
		this->className,
		winTitle,
		baseStyles,
		0,
		0,
		vmodes[resId].w,
		vmodes[resId].h,
		NULL,
		NULL,
		this->hInst,
		NULL
		
		);
   

   // if we have the window up and running make it show
   if ( this->hWnd )
	{
		ShowWindow ( this->hWnd, SW_SHOW );
		UpdateWindow ( this->hWnd );

		// probe pixel formats and resolutions to see which are useful and valid
		errCode = probeVideo();
		if ( errCode != VIDEO_USABLE )
			return errCode;

		// set the apropriate pixel mode and enable opengl rendering
		// NOTE: there may be a number of goodpf[] available, just choose the first one
		errCode = setMode ( this->goodpf[0], resType );

		if ( errCode == RENDERING_CONTEXT_IS_LIVE )
			return CREATE_WINDOW_OK;
		else
			return errCode;
	}
   else
	{
		return CREATE_WINDOW_FAIL;
	}
};

// --------------------------------------------------------------------------------------------
// END Window Create
// --------------------------------------------------------------------------------------------

  














// --------------------------------------------------------------------------------------------
// BEGIN Probe video pixelformats and resolutions applicable for OPENGL
//
// Created:		Friday 3rd November 2000
// Last Change: Sunday 5th November 2000
// --------------------------------------------------------------------------------------------

	int win::probeVideo ( void ) {

		int usableResCount=0;
		DEVMODE devmode;
		int i,n;
		int count;
		int iPF;
		int maxPF;
		PIXELFORMATDESCRIPTOR pfray;
	

		// Need to get the Device Context of this window
		this->hDc = GetDC(this->hWnd);
	
		if ( this->hDc == NULL ) return FAILED_TO_GETDC;

		fprintf (fp, "\n Detecting Pixel Formats Available \n\n\n");


		// detect how many pix formats available that suit our purpose
		maxPF = DescribePixelFormat(hDc, 1, 0, NULL);
		
		if ( maxPF == 0 ) return NO_PIXEL_FORMATS;

		this->goodpfCount=0;

		// scan all pixel formats for suitability
		for ( iPF = 0, count = 0; iPF <= maxPF; iPF++ ) {

			DescribePixelFormat(hDc, iPF, sizeof(PIXELFORMATDESCRIPTOR), &pfray );

			// make sure it meets a few requirements for our opengl usage
			if(pfray.cColorBits < 16)						continue;
			if( !(pfray.dwFlags & PFD_DRAW_TO_WINDOW) )		continue;
			if( !(pfray.dwFlags & PFD_DOUBLEBUFFER) )		continue;
			if( !(pfray.dwFlags & PFD_SUPPORT_OPENGL) )		continue;
			if( !(pfray.iPixelType == PFD_TYPE_RGBA ) )		continue;

			fprintf (fp, "%d %d DBLBUFFER    OPENGL    ", iPF, count);
			fprintf (fp,"ColorBits: %d    DepthBits: %d    " , pfray.cColorBits , pfray.cDepthBits );
			if (pfray.iPixelType == PFD_TYPE_RGBA) fprintf (fp,"PixelType: PFD_TYPE_RGBA \n");
			if (pfray.iPixelType == PFD_TYPE_COLORINDEX) fprintf (fp,"PixelType: PFD_TYPE_COLORINDEX \n");

			// remember the system offset for these good pixel formats
			goodpf[goodpfCount] = iPF;
			goodpfCount++;

			count++;
		}

		// make sure we get atleast one suitable pixel format
		if ( goodpfCount == 0 )
			return NO_SUITABLE_PIXEL_FORMATS;

		fprintf (fp, "\n\n\n Testing Resolutions \n");


		// go test to see what resolutions are available
		for ( i=0; i<NUMRES; i++ ) {


			memset ( &devmode, 0, sizeof ( DEVMODE ) );
			devmode.dmSize = sizeof ( DEVMODE );

			// grab curent view settings
			EnumDisplaySettings ( NULL, 0, &devmode );
			devmode.dmPelsWidth = this->vmodes[i].w;
			devmode.dmPelsHeight = this->vmodes[i].h;
			devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;

			// use the test mode to see if it may work
			n = ChangeDisplaySettings ( &devmode, CDS_TEST );
		

			// mark the resolutions that seem to be ok
			if ( n == DISP_CHANGE_SUCCESSFUL ) {
				validres[i] = 1;
				usableResCount++;			
				fprintf (fp, "PASSED  %d  X  %d \n", vmodes[i].w, vmodes[i].h );
			}
			else {
				validres[i] = 0;
				fprintf (fp, "FAILED  %d  X  %d \n", vmodes[i].w, vmodes[i].h );

			}
		}

		if ( usableResCount == 0 )
			return LACK_OF_RESOLUTIONS;

		return VIDEO_USABLE;
	}
// --------------------------------------------------------------------------------------------
// END Probe video pixelformats and resolutions applicable for OPENGL
// --------------------------------------------------------------------------------------------

  














// --------------------------------------------------------------------------------------------
// BEGIN Print error code
//
// Created:		Monday 6th November 2000
// Last Change: Monday 6th November 2000
// --------------------------------------------------------------------------------------------
void win::print ( char *format, ... ) {
	va_list ap;
	static char strtmp[1024];

	va_start(ap, format);
		_vsnprintf(strtmp, sizeof(strtmp), format, ap);
	va_end(ap);

	fwrite(strtmp, 1, strlen(strtmp), fp);
	fflush(fp);

}
// --------------------------------------------------------------------------------------------
// END Print
// --------------------------------------------------------------------------------------------
















// --------------------------------------------------------------------------------------------
// BEGIN Set rendering context
//
// Created:		Friday 3rd November 2000
// Last Change: Sunday 5th November 2000
// --------------------------------------------------------------------------------------------
int win::setMode ( int pfdId, int type ) {
	
	
static	PIXELFORMATDESCRIPTOR pfdx=				// pfd Tells Windows How We Want Things To Be
	{
		sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
		1,											// Version Number
		PFD_DRAW_TO_WINDOW |						// Format Must Support Window
		PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
		PFD_DOUBLEBUFFER,							// Must Support Double Buffering
		PFD_TYPE_RGBA,								// Request An RGBA Format
		24,										// Select Our Color Depth
		0, 0, 0, 0, 0, 0,							// Color Bits Ignored
		0,											// No Alpha Buffer
		0,											// Shift Bit Ignored
		0,											// No Accumulation Buffer
		0, 0, 0, 0,									// Accumulation Bits Ignored
		16,											// 16Bit Z-Buffer (Depth Buffer)  
		0,											// No Stencil Buffer
		0,											// No Auxiliary Buffer
		PFD_MAIN_PLANE,								// Main Drawing Layer
		0,											// Reserved
		0, 0, 0										// Layer Masks Ignored
	};

	
	PIXELFORMATDESCRIPTOR wpfd;
	int errCode=0;
	wpfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);				// Size Of This Pixel Format Descriptor


//	memset ( &wpfd, 0, sizeof (wpfd) );

	// grab current format
	errCode = DescribePixelFormat(this->hDc, pfdId, sizeof(PIXELFORMATDESCRIPTOR), &wpfd);
	int iii = ChoosePixelFormat(this->hDc,&wpfd);

//	if ( errCode == 0 )
//		return COULD_NOT_DESCRIBE_PIXEL_FORMAT;

	// try to apply a new format
	if (!SetPixelFormat(this->hDc, iii, &wpfd)) {
//	if (!dll._wglSetPixelFormat(this->hDc, goodpf[pfdId], &wpfd)) {
//	if (!dll._wglSetPixelFormat(this->hDc, iii, &pfdx)) {
		errCode = GetLastError();
		fprintf (fp, "\n\n Error applying pixel format %d", errCode );
		return COULD_NOT_SET_PIXEL_FORMAT;
	}

#pragma
	fprintf (fp, "\n\n Applied pixel format " );

	DWORD huh=0;
	char oh[20];

	// Create rendering context	
	this->hRc = wglCreateContext(this->hDc);
	if ( this->hRc == NULL ) {
		huh = GetLastError();
		_itoa (huh, oh, 10);
		fprintf (fp, "\n\n Error Creating Gl context\n");
		fprintf (fp, oh);
		fprintf (fp, "\n\n" );
		int a = GetLastError ();
		return COULD_NOT_CREATE_CONTEXT;
	} else {
		fprintf (fp, "\n\n Created Gl context");
	}

	// Make it usable
	if( !wglMakeCurrent (this->hDc, this->hRc) ) {
		fprintf (fp, "\n\n Error MakeCurrent ");
		return COULD_NOT_MAKE_RC_CURRENT;
	} else {
		fprintf (fp, "\n\n MakeCurrent succeded");
	}

		
	return RENDERING_CONTEXT_IS_LIVE;

}
// --------------------------------------------------------------------------------------------
// END rendering context
// --------------------------------------------------------------------------------------------


int win::changeWindow ( int x, int y, int width, int height, int resId ) {
	int errCode;

	// change to the new monitor resolution
	errCode = changeResolution ( resId );

		// return a result
	if ( errCode == DISP_CHANGE_SUCCESSFUL )
		return MONITOR_RESOLUTION_CHANGED_OK;
	else
		return MONITOR_RESOLUTION_FAILURE;


	// now update the window 
	errCode = SetWindowPos ( this->hWnd, HWND_TOP, x, y, width, height, SWP_SHOWWINDOW );

	// any errors
	if ( errCode == 0 )
		return COULD_NOT_CHANGE_WINDOW;

	return OK;
}






