//-------------------------------------------------- 
// Title:		NPendulum
// Author:		Tony Kim 
// Date:		2006 Nov 18 
// Description: The nonlinear pendulum
//-------------------------------------------------- 
#pragma once

//-------------------------------------------------- 
// Include files
//-------------------------------------------------- 
#include "FieldEngine.h"
#include "NPAux.h"

void Maximize( int sCoord );
void Minimize( int sCoord );

//-------------------------------------------------- 
// Global Variables
//-------------------------------------------------- 
FieldEngine* g_pEngine;

//-------------------------------------------------- 
// Title: Initialize
//-------------------------------------------------- 
BOOL Initialize( HINSTANCE hInstance )
{
	// Create engine
	g_pEngine = new FieldEngine( hInstance, TEXT("NPendulum"), TEXT("Nonlinear Pendulum"), NULL, NULL, 1024, 768);
	if( g_pEngine == NULL )
		return FALSE;

	// Set frame rate
	g_pEngine->SetFrameRate(60);

	g_pendulum.theta = rand()%2;
	g_pendulum.theta_dot = rand()%3;

	//-------------------------------------------------- 
	// Coordinate frames used in this program
	//-------------------------------------------------- 
	g_coord.push_back( MyCoord( 1000, -1000, 1000, -1000, 250, 250, 0, 0, 250, 250 ) );
	g_coord.push_back( MyCoord( 7, -7, 7, -7, 1024-(260+MARGIN), 768-2*MARGIN, 260, MARGIN, 200, 200, 20, 270 ) );
	g_coord.push_back( MyCoord( 7, -7, 7, -7, 1024-(260+MARGIN), 768-2*MARGIN, 260, MARGIN, 200, 200, 20, 530 ) );
	
	return TRUE;
}

void Start( HWND hWindow )
{
	srand( GetTickCount() );
}

void End()
{
	delete g_pEngine;
}

//-------------------------------------------------- 
// Title: Activate
//-------------------------------------------------- 
void Activate( HWND hWindow )
{
}

//-------------------------------------------------- 
// Title: Deactivate
//-------------------------------------------------- 
void Deactivate( HWND hWindow )
{
	HDC		hDC;
	RECT	rect;

	GetClientRect( hWindow, &rect );
	hDC = GetDC( hWindow );
	DrawText( hDC, TEXT("Nonlinear Pendulum: Click on window to resume"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER );
	ReleaseDC( hWindow, hDC );
}

//-------------------------------------------------- 
// Title: Paint
//-------------------------------------------------- 
void Paint(HDC hDC)
{
}

//-------------------------------------------------- 
// Title: Cycle
//-------------------------------------------------- 
void Cycle(bool noUpdate)
{
	HWND	hWindow = g_pEngine->GetWindow();
	HDC		hDC		= GetDC( hWindow );

	//-------------------------------------------------- 
	// Double-buffering to reduce flicker
	//-------------------------------------------------- 
	HDC		hOffscreenDC;
	HBITMAP hOffscreenBitmap;
	
	hOffscreenDC = CreateCompatibleDC( hDC );
	hOffscreenBitmap = CreateCompatibleBitmap( hDC, g_pEngine->GetWidth(), g_pEngine->GetHeight() );
	SelectObject( hOffscreenDC, hOffscreenBitmap );
	
	static int MyTime = 0;
	if( !noUpdate )
	{
		Update( MyTime );
		MyTime++;
	}
	DrawPoincare( hOffscreenDC );
	DrawPortrait( hOffscreenDC );
	DrawPendulum( hOffscreenDC );

	BitBlt(hDC, 0, 0, g_pEngine->GetWidth(), g_pEngine->GetHeight(), hOffscreenDC, 0, 0, SRCCOPY);
	
	ReleaseDC( hWindow, hDC );
	DeleteDC( hOffscreenDC );
	DeleteObject( hOffscreenBitmap );
	
}

//-------------------------------------------------- 
// Maximize/Minimize coordinates
//-------------------------------------------------- 
#define STEPS 50
void Minimize( int sCoord )
{
	double del_x = 0;
	double del_y = 0;
	double disp_x = 0;
	double disp_y = 0;

	// Check if we are maximized
	if( (g_coord[sCoord].GetWidth() > g_coord[sCoord].GetMinInfo().width) || 
		(g_coord[sCoord].GetHeight() > g_coord[sCoord].GetMinInfo().height) )
	{
		del_x = (double)(g_coord[sCoord].GetWidth() - g_coord[sCoord].GetMinInfo().width)/(double)STEPS;
		del_y = (double)(g_coord[sCoord].GetHeight() - g_coord[sCoord].GetMinInfo().height)/(double)STEPS;
		disp_x = (double)(g_coord[sCoord].GetAnchX() - g_coord[sCoord].GetMinInfo().anchor_x)/(double)STEPS;
		disp_y = (double)(g_coord[sCoord].GetAnchY() - g_coord[sCoord].GetMinInfo().anchor_y)/(double)STEPS;
	
		for(int i=0; i<STEPS; i++)
		{
			g_coord[sCoord].SetWidth( (int)(g_coord[sCoord].GetWidth() - del_x) );
			g_coord[sCoord].SetHeight( (int)(g_coord[sCoord].GetHeight() - del_y) );
			g_coord[sCoord].SetAnchorX( (int)(g_coord[sCoord].GetAnchX() - disp_x) );
			g_coord[sCoord].SetAnchorY( (int)(g_coord[sCoord].GetAnchY() - disp_y) );
			Cycle(true);
		}
		g_coord[sCoord].SetWidth( g_coord[sCoord].GetMinInfo().width );
		g_coord[sCoord].SetHeight( g_coord[sCoord].GetMinInfo().height );
		g_coord[sCoord].SetAnchorX( g_coord[sCoord].GetMinInfo().anchor_x );
		g_coord[sCoord].SetAnchorY( g_coord[sCoord].GetMinInfo().anchor_y );
	}
}

void Maximize( int sCoord )
{
	double del_x = 0;
	double del_y = 0;
	double disp_x = 0;
	double disp_y = 0;
	
	// Check if we are minimized
	if( (g_coord[sCoord].GetWidth() < g_coord[sCoord].GetMaxInfo().width) ||
		(g_coord[sCoord].GetHeight() < g_coord[sCoord].GetMaxInfo().height) )
	{
		del_x = (double)(g_coord[sCoord].GetMaxInfo().width - g_coord[sCoord].GetWidth())/(double)STEPS;
		del_y = (double)(g_coord[sCoord].GetMaxInfo().height - g_coord[sCoord].GetHeight())/(double)STEPS;
		disp_x = (double)(g_coord[sCoord].GetMaxInfo().anchor_x - g_coord[sCoord].GetAnchX())/(double)STEPS;
		disp_y = (double)(g_coord[sCoord].GetMaxInfo().anchor_y - g_coord[sCoord].GetAnchY())/(double)STEPS;
	
		for(int i=0; i<STEPS; i++)
		{
			g_coord[sCoord].SetWidth( (int)(g_coord[sCoord].GetWidth() + del_x) );
			g_coord[sCoord].SetHeight( (int)(g_coord[sCoord].GetHeight() + del_y) );
			g_coord[sCoord].SetAnchorX( (int)(g_coord[sCoord].GetAnchX() + disp_x) );
			g_coord[sCoord].SetAnchorY( (int)(g_coord[sCoord].GetAnchY() + disp_y) );
			Cycle(true);
		}
		g_coord[sCoord].SetWidth( g_coord[sCoord].GetMaxInfo().width );
		g_coord[sCoord].SetHeight( g_coord[sCoord].GetMaxInfo().height );
		g_coord[sCoord].SetAnchorX( g_coord[sCoord].GetMaxInfo().anchor_x );
		g_coord[sCoord].SetAnchorY( g_coord[sCoord].GetMaxInfo().anchor_y );
	}
}

//-------------------------------------------------- 
// Mouse event handlers
//-------------------------------------------------- 
void MouseButtonDown(int x, int y, BOOL bLeft)
{
	int sCoord = ClickedCoord(x, y);
	
	if( sCoord >= 0 )
	{
		if( bLeft )
		{
			for(int i=0; i<(int)g_coord.size(); i++)
			{
				if(i != sCoord)
					Minimize(i);
			}
			Maximize( sCoord );
		}
		else
		{
			Minimize( sCoord );
		}
	}
}
void MouseButtonUp(int x, int y, BOOL bLeft)
{
}
void MouseMove(int x, int y)
{
}