// project01View.cpp : implementation of the CProject01View class
//

//Memory leak seems to have to do with face objects.  with only control group
// and 9 faces it leaks 18 blocks.

#include "stdAfx.h"
#include "project01.h"

#include "project01Doc.h"
#include "project01View.h"

#include "vector3D.h"
#include "vector3dgroup.h"
#include "face.h"
#include "facegroup.h"
#include "mesh.h"
#include "off_loader.h"
#include "_M_N_Changer.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif



/*************************************/
#define LEFT 0
#define RIGHT 1
#define CURVEMESH 0
#define CONTROLMESH 1
#define DEGREES 57.6

Mesh *pControlMesh;
Mesh *pCurveMesh;
Vector3DGroup *pControlScreen;
Vector3DGroup *pCurveScreen;
Vector3D vView;
CRect screenRect;
CPoint iRButtonDown;
CPoint iLButtonDown;
bool objectLoaded = false;
bool bChangePoint = false;
bool bDisplayMsg = true;
float fNumXPoints = 20;
float fNumZPoints = 20;
float zoom = 0;

int iChangeControl = 0; //Used by lbutton down



/*************************************/

void DrawObject(CDC *pDC, Mesh *inMesh, Vector3DGroup *vScreenVectors);
void ObjectToScreen(Mesh *pMesh,/*out*/Vector3DGroup *pControlScreen, Vector3D vView, CRect screenRect, int side);
void initializer(Mesh **ppInMesh, float m, float n);
void curveGenerator(Mesh *pCurveMesh, Mesh *pControlMesh, float fNumXPoints, float fNumZPoints);

/////////////////////////////////////////////////////////////////////////////
// CProject01View

IMPLEMENT_DYNCREATE(CProject01View, CView)

BEGIN_MESSAGE_MAP(CProject01View, CView)
	//{{AFX_MSG_MAP(CProject01View)
	ON_WM_MOUSEMOVE()
	ON_WM_KEYDOWN()
	ON_WM_RBUTTONDOWN()
	ON_WM_LBUTTONDOWN()
	ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
	ON_COMMAND(ID_CHANGE_M_N, OnChangeMN)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CProject01View construction/destruction

CProject01View::CProject01View()
{
	// TODO: add construction code here
//	OFFLoader ObjectLoader;

	pControlMesh = NULL;
	pControlScreen = NULL;
//	oObjectLoader.load( "c:\\temp\\dragon2.off", &pControlMesh );
//	objectLoaded = true;

	vView = Vector3D(0.f, 0.f, -2.f);
	//vView = Vector3D( 1.f, 0.f, -2.f );
	initializer(&pControlMesh, 4.0, 4.0);
	initializer(&pCurveMesh, fNumXPoints , fNumZPoints);
	objectLoaded = true;

	pControlMesh->normalize();
	pCurveMesh->normalize();

	pControlScreen = new Vector3DGroup( pControlMesh->getVector3DGroupPtr()->getNumElements() );
	pControlScreen->setNumElements( pControlMesh->getVector3DGroupPtr()->getNumElements() );

	pCurveScreen = new Vector3DGroup( pCurveMesh->getVector3DGroupPtr()->getNumElements() );
	pCurveScreen->setNumElements( pCurveMesh->getVector3DGroupPtr()->getNumElements() );


}

CProject01View::~CProject01View()
{
	objectLoaded = false;

	delete pControlMesh;
	delete pControlScreen;

	delete pCurveMesh;
	delete pCurveScreen;
}

BOOL CProject01View::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CProject01View drawing

void CProject01View::OnDraw(CDC* pDC)
{

	CProject01Doc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here

	//variable declarations
	CPen redPen(PS_SOLID,1,RGB(255,0,0));
	int iUpLeftEx = 0;
	int iLoRightEx = 0;
	int iUpLeftEy = 0;
	int iLoRightEy = 0;



	GetClientRect( &screenRect );

	if(objectLoaded == true) {
		ObjectToScreen(pCurveMesh,/*out*/pCurveScreen, vView, screenRect, 0);
		DrawObject(pDC, pCurveMesh, pCurveScreen);
		ObjectToScreen(pControlMesh,/*out*/pControlScreen, vView, screenRect, 1);
		DrawObject(pDC, pControlMesh, pControlScreen);

		if (bChangePoint == true) {
			
			iUpLeftEx = iLoRightEx = pControlScreen->getElementAt(iChangeControl).fX;
			iUpLeftEy = iLoRightEy = pControlScreen->getElementAt(iChangeControl).fY;
			
			//Get the old pen and save it.
			CPen* pPen = pDC->GetCurrentPen();
			CPen* oldPen = pPen;
			//Now change the pen color to BLUE
			pPen = pDC->SelectObject(&redPen);
			pDC->Ellipse(iUpLeftEx-2, iUpLeftEy-2,iLoRightEx+2,iLoRightEy+2);

			//Return the old pen to it's owner (will crash if this is not done)
			pDC->SelectObject( oldPen );
			
			pDC->TextOut(0, 0, "Point selected: "); 
			pDC->TextOut(100, 0, iChangeControl+48);
			pDC->TextOut(0, 15, "Press 'n' when finised");
		}

	}

	if(bDisplayMsg == true) {
		pDC->TextOut(0, 0, "To edit control Matrix click on point.");
		pDC->TextOut(0, 15, "Press 'n' when finised");
	}
}

/////////////////////////////////////////////////////////////////////////////
// CProject01View diagnostics

#ifdef _DEBUG
void CProject01View::AssertValid() const
{
	CView::AssertValid();
}

void CProject01View::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CProject01Doc* CProject01View::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CProject01Doc)));
	return (CProject01Doc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CProject01View message handlers

void CProject01View::OnMouseMove(UINT nFlags, CPoint point) 
{
	float holdThetaX;
	float holdThetaY;
	// TODO: Add your message handler code here and/or call default

	if((nFlags == MK_RBUTTON) && (nFlags != MK_LBUTTON)) {
		
		holdThetaX = (point.x - iRButtonDown.x)/(DEGREES);
		holdThetaY = (point.y - iRButtonDown.y)/(DEGREES);
		
		vView.add( Vector3D( holdThetaY, holdThetaX, 0.f ));
		iRButtonDown = point;

		Invalidate();
	}

	if((nFlags == MK_LBUTTON) && (nFlags != MK_RBUTTON)) {
		zoom = (float)(iLButtonDown.y - point.y)/20.f;
		vView.add( Vector3D(0, 0, zoom));
		iLButtonDown = point;

		Invalidate();
	}

	//vView.add( Vector3D( 0.f, 0.03f, 0.f ));
	
	CView::OnMouseMove(nFlags, point);
}

void CProject01View::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
	CDC* pDC = GetDC();

	Vector3DGroup *pV3DGroup;
	float iTempX = 0;
	float iTempY = 0;
	float iTempZ = 0;

	pV3DGroup = pControlMesh->getVector3DGroupPtr();

	if(bChangePoint == true) {
				
		iTempX = pV3DGroup->getElementAt(iChangeControl).fX;
		iTempY = pV3DGroup->getElementAt(iChangeControl).fY;
		iTempZ = pV3DGroup->getElementAt(iChangeControl).fZ;
	
		switch (nChar) {
		case VK_ADD :
			pV3DGroup = pControlMesh->getVector3DGroupPtr();
			pV3DGroup->setElementAt(iChangeControl, iTempX, iTempY, (iTempZ + .05));
			curveGenerator(pCurveMesh, pControlMesh, fNumXPoints, fNumZPoints);
			break;

		case VK_SUBTRACT :
			pV3DGroup = pControlMesh->getVector3DGroupPtr();
			pV3DGroup->setElementAt(iChangeControl, iTempX, iTempY, (iTempZ - .05));
			curveGenerator(pCurveMesh, pControlMesh, fNumXPoints, fNumZPoints);
			break;

		case VK_UP :
			pV3DGroup = pControlMesh->getVector3DGroupPtr();
			pV3DGroup->setElementAt(iChangeControl, iTempX, (iTempY + .05), iTempZ);
			curveGenerator(pCurveMesh, pControlMesh, fNumXPoints, fNumZPoints);
			break;

		case VK_DOWN:
			pV3DGroup = pControlMesh->getVector3DGroupPtr();
			pV3DGroup->setElementAt(iChangeControl, iTempX, (iTempY - .05), iTempZ);
			curveGenerator(pCurveMesh, pControlMesh, fNumXPoints, fNumZPoints);
			break;

		case VK_RIGHT:
			pV3DGroup = pControlMesh->getVector3DGroupPtr();
			pV3DGroup->setElementAt(iChangeControl, (iTempX + .05), iTempY, iTempZ);
			curveGenerator(pCurveMesh, pControlMesh, fNumXPoints, fNumZPoints);
			break;

		case VK_LEFT:
			pV3DGroup = pControlMesh->getVector3DGroupPtr();
			pV3DGroup->setElementAt(iChangeControl, (iTempX - .05), iTempY, iTempZ);
			curveGenerator(pCurveMesh, pControlMesh, fNumXPoints, fNumZPoints);
			break;

		}
		Invalidate();
	}
	

	switch(nChar) {
	case 'n' :
	case 'N' :
		bChangePoint = false;
	}	

	CView::OnKeyDown(nChar, nRepCnt, nFlags);
}

void CProject01View::OnRButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	iRButtonDown = point;
	
	CView::OnRButtonDown(nFlags, point);
}

void CProject01View::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	iLButtonDown = point;

	Vector3D vModVector;

	GetClientRect( &screenRect );
	//CDC* pDC = GetDC(); //Debug code

	if(point.x > (screenRect.Width()/2) ) {
		for(int i = 0; i < pControlScreen->getNumElements(); i++) {
			vModVector = pControlScreen->getElementAt(i);
			if((vModVector.fX - 5) < point.x && (vModVector.fX + 5) > point.x) {
				if((vModVector.fY - 5) < point.y && (vModVector.fY + 5) > point.y) {
					
					iChangeControl = i;
				//	pDC->TextOut(point.x, point.y, iChangeControl+48); //debug code
					bChangePoint = true;
					bDisplayMsg = false;
				}
			}
		}
	}
	Invalidate();
		
	CView::OnLButtonDown(nFlags, point);
}

void CProject01View::OnFileOpen() 
{
//	OFFLoader oObjectLoader;
	// TODO: Add your command handler code here
	if(pControlMesh != NULL) {
		delete pControlMesh;
	}

	if(pControlScreen != NULL) {
		delete pControlScreen;
	}

	CFileDialog fd(true);
	if(fd.DoModal()==IDOK)
	{
	/*	vView.assign(Vector3D(0.f, 0.f, -2.f));
		
		CString sFileName = fd.GetFileName();
		int iLen = sFileName.GetLength();
		oObjectLoader.load( sFileName.GetBuffer(iLen), &pControlMesh );
		pControlMesh->normalize();
		objectLoaded = true;

		pControlScreen = new Vector3DGroup( pControlMesh->getVector3DGroupPtr()->getNumElements() );
		pControlScreen->setNumElements( pControlMesh->getVector3DGroupPtr()->getNumElements() );
	*/
		
//		initializer(&pControlMesh, 4, 4);
//		objectLoaded = true;

//		pControlScreen = new Vector3DGroup( pControlMesh->getVector3DGroupPtr()->getNumElements() );
//		pControlScreen->setNumElements( pControlMesh->getVector3DGroupPtr()->getNumElements() );


	}

		
}

void CProject01View::OnChangeMN() 
{
	// TODO: Add your command handler code here

	C_M_N_Changer change;

	if(change.DoModal() == IDOK) {
		delete pCurveMesh;
		initializer(&pCurveMesh, change.m_Xpoints , change.m_Zpoints);

		delete pCurveScreen;
		pCurveScreen = new Vector3DGroup( pCurveMesh->getVector3DGroupPtr()->getNumElements() );
		pCurveScreen->setNumElements( pCurveMesh->getVector3DGroupPtr()->getNumElements() );

		fNumXPoints = change.m_Xpoints;
		fNumZPoints = change.m_Zpoints;

		curveGenerator(pCurveMesh, pControlMesh, fNumXPoints, fNumZPoints);
		Invalidate();
	}	
}
