// AttitudeCtrl.cpp: implementation of the CAttitudeCtrl class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "AttitudeCtrl.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CAttitudeCtrl::CAttitudeCtrl()
{
	//DISPLAY ITEM COLORS
	crPlane			= RGB(255,255,255);
	crAxis			= RGB(0,0,0);
	
	m_crData1		= RGB(255,0,0);		//red
	m_crData2		= RGB(0,255,0);		//green
	m_crData3		= RGB(0,0,255);		//blue
	m_crData4		= RGB(0,0,0);		//black

	m_nDegreeScale	= 180;
	m_OffsetInc		= 4;
	m_pPolyLine1	= NULL;
	m_pPolyLine2	= NULL;
	m_pPolyLine3	= NULL;
	m_pPolyLine4	= NULL;

	updateCount = 0;
    
	m_nPoints1		= m_nPoints2 = m_nPoints3 = m_nPoints4 = 0;

	m_bLine1		= m_bLine2 = m_bLine3 = m_bLine4 = FALSE;

}
CAttitudeCtrl::~CAttitudeCtrl()
{
	if(m_pPolyLine1)
		delete [] m_pPolyLine1;
	m_pPolyLine1 = NULL;

	if(m_pPolyLine2)
		delete [] m_pPolyLine2;
	m_pPolyLine2 = NULL;

	if(m_pPolyLine3)
		delete [] m_pPolyLine3;
	m_pPolyLine3 = NULL;

	if(m_pPolyLine4)
		delete [] m_pPolyLine4;
	m_pPolyLine4 = NULL;

}

//////////////////////////////////////////////////////////////////////
// Public Functions
//////////////////////////////////////////////////////////////////////

BOOL CAttitudeCtrl::InitCtrl(CWnd *pWnd, CWnd* pRectWnd, int maxWidth)
{
	//save the parent DC & bounding area
	m_pParentWnd  = pWnd;
	m_pwndBltArea = pRectWnd;
	m_Rect		  = GetBltRect();

	CDC *pDC = pWnd->GetDC();

	//create our own DC to work with
	if(!m_DC1.CreateCompatibleDC(pDC))
	{
		pWnd->ReleaseDC(pDC);
		return FALSE;
	}
	if(!m_DC2.CreateCompatibleDC(&m_DC1))
	{
		pWnd->ReleaseDC(pDC);
		return FALSE;
	}
	pWnd->ReleaseDC(pDC);

	m_Bitmap2.CreateBitmap(m_Rect.Width(), m_Rect.Height(), 1, 32, NULL);
	
	CBitmap *pOldBmp = m_DC2.SelectObject(&m_Bitmap2);
	
	//m_DC2.FillRect(m_Rect, &m_brOther);

	if(maxWidth == 0)
	{
		//Set history size to max window width
		m_maxHistorySize = GetSystemMetrics(SM_CXMAXIMIZED);
	}
	else
		//Set history to user defined width
		m_maxHistorySize = maxWidth;

	//Create Polyline array
	
	if(m_pPolyLine1){
		delete [] m_pPolyLine1;
		m_pPolyLine1 = NULL;
	}
	if(m_pPolyLine2){
		delete [] m_pPolyLine2;
		m_pPolyLine2 = NULL;
	}
	if(m_pPolyLine3){
		delete [] m_pPolyLine3;
		m_pPolyLine3 = NULL;
	}
	if(m_pPolyLine4){
		delete [] m_pPolyLine4;
		m_pPolyLine4 = NULL;
	}
	
	
	m_pPolyLine1 = new POINT[m_maxHistorySize];
    ZeroMemory(m_pPolyLine1,m_maxHistorySize*sizeof(POINT));

	m_pPolyLine2 = new POINT[m_maxHistorySize];
    ZeroMemory(m_pPolyLine2,m_maxHistorySize*sizeof(POINT));

	m_pPolyLine3 = new POINT[m_maxHistorySize];
    ZeroMemory(m_pPolyLine3,m_maxHistorySize*sizeof(POINT));

	m_pPolyLine4 = new POINT[m_maxHistorySize];
    ZeroMemory(m_pPolyLine4,m_maxHistorySize*sizeof(POINT));

	InitGDI();
	Refresh();

	//m_DC2.SelectObject(pOldBmp);

	return TRUE;
}

void CAttitudeCtrl::Cleanup()
{
	//Delete all GDI objects
	m_brPlane.DeleteObject();
	m_brOther.DeleteObject();
	m_penAxisX.DeleteObject();
	m_penAxisY.DeleteObject();

	m_penData1.DeleteObject();
	m_penData2.DeleteObject();
	m_penData3.DeleteObject();
	m_penData4.DeleteObject();
	
	m_Bitmap2.DeleteObject();
	m_Bitmap.DeleteObject();
	m_ftAngles.DeleteObject();
	m_ftCurrentAngle.DeleteObject();

	//Delete Polyline data
	//backup in  destructor
	if(m_pPolyLine1)
		delete [] m_pPolyLine1;
	m_pPolyLine1 = NULL;

	if(m_pPolyLine2)
		delete [] m_pPolyLine2;
	m_pPolyLine2 = NULL;

	if(m_pPolyLine3)
		delete [] m_pPolyLine3;
	m_pPolyLine3 = NULL;

	if(m_pPolyLine4)
		delete [] m_pPolyLine4;
	m_pPolyLine4 = NULL;
}

void CAttitudeCtrl::AddAngle(float angle, UINT lineID)
{
	switch(lineID)
	{
	case 1:{
				if(m_qHistory1.size() == m_maxHistorySize)
					m_qHistory1.pop_front();
		
				//Add new depth value
				m_qHistory1.push_back(angle);
				break;
		   }
	case 2:{	
				if(m_qHistory2.size() == m_maxHistorySize)
					m_qHistory2.pop_front();
		
				//Add new depth value
				m_qHistory2.push_back(angle);
				break;
		   }
	case 3:{
				if(m_qHistory3.size() == m_maxHistorySize)
					m_qHistory3.pop_front();
		
				//Add new depth value
				m_qHistory3.push_back(angle);
				break;
		   }
	case 4:{	
				if(m_qHistory4.size() == m_maxHistorySize)
					m_qHistory4.pop_front();
		
				//Add new depth value
				m_qHistory4.push_back(angle);
				break;
		   }

	}
}

void CAttitudeCtrl::Resize(CRect rect)
{	
	m_Bitmap2.DeleteObject();
	m_Bitmap2.CreateBitmap(rect.Width(), rect.Height(), 1, 32, NULL);
	
	CBitmap *bmpOld;
	CBrush  *brOld;

	bmpOld = m_DC2.SelectObject(&m_Bitmap2);
	brOld  = m_DC2.SelectObject(&m_brOther);
	
	//m_DC2.FloodFill(0,0,crData);
	
	m_Rect		= rect;
	ForceRefresh();
}

void CAttitudeCtrl::Refresh()
{
	if(updateCount < updateRate)
	{
		TRACE("SKIPPING: :%d\r\n", updateCount);
		updateCount++;
		return;
	}
		
	CreatePlane();
	DrawAxes();
	DrawLine();
	Render();
	
	updateCount = 0;
}

void CAttitudeCtrl::ForceRefresh()
{
	CreatePlane();
	DrawAxes();
	DrawLine();
	Render();
}

void CAttitudeCtrl::SetPlaneColor(COLORREF color)
{
	crPlane = color;
	m_brPlane.DeleteObject();
	m_DC2.SetBkColor(color);
	m_brPlane.CreateSolidBrush(crPlane);
	Refresh();
}

void CAttitudeCtrl::SetLineColor(COLORREF color, UINT lineID)
{
	switch(lineID)
	{
	case 1:{
			m_crData1 = color;
			m_penData1.DeleteObject();
			m_penData1.CreatePen(PS_SOLID, 2, m_crData1);
			break;
		   }
	case 2:{
			m_crData2 = color;
			m_penData2.DeleteObject();
			m_penData2.CreatePen(PS_SOLID, 2, m_crData2);
			break;
		   }
	case 3:{
			m_crData3 = color;
			m_penData3.DeleteObject();
			m_penData3.CreatePen(PS_SOLID, 2, m_crData3);
			break;
		   }
	case 4:{
			m_crData4 = color;
			m_penData4.DeleteObject();
			m_penData4.CreatePen(PS_SOLID, 2, m_crData4);
			break;
		   }
	}
		
	Refresh();
}

void CAttitudeCtrl::SetAxisColor(COLORREF color)
{
	crAxis = color;
	m_penAxisX.DeleteObject();
	m_penAxisY.DeleteObject();;
	m_penAxisY.CreatePen(PS_SOLID, 8, crAxis);
	m_penAxisX.CreatePen(PS_SOLID, 1, crAxis);
	Refresh();
}

void CAttitudeCtrl::SetFontColor(COLORREF color)
{
	m_DC1.SetTextColor(color);
	m_DC2.SetTextColor(color);
	Refresh();
}

void CAttitudeCtrl::SetDisplayType(int mode)
{
	switch(mode){
	case 0:  {EAttitudeType = ROLL;break;}
	case 1:  {EAttitudeType = PITCH;break;}
	case 2:  {EAttitudeType = HEAVE;break;}
	default: {EAttitudeType = ROLL;break;}
	}
}

void CAttitudeCtrl::SetScale(int degrees)
{
	m_nDegreeScale = degrees;
	Refresh();
}

void CAttitudeCtrl::SetUpdateRate(UINT rate)
{
	updateRate  = rate;
	updateCount = 0;
}

//////////////////////////////////////////////////////////////////////
// Private Functions
//////////////////////////////////////////////////////////////////////

void CAttitudeCtrl::InitGDI()
{
	m_brPlane.CreateSolidBrush(crPlane);
	
	//m_brOther.CreateSolidBrush(crData);

	m_penAxisY.CreatePen(PS_SOLID, 8, crAxis);
	m_penAxisX.CreatePen(PS_SOLID, 1, crAxis);
	
	m_penData1.CreatePen(PS_SOLID, 2, m_crData1);
    m_penData2.CreatePen(PS_SOLID, 2, m_crData2);
	m_penData3.CreatePen(PS_SOLID, 2, m_crData3);
	m_penData4.CreatePen(PS_SOLID, 2, m_crData4);
	
	//Create the Axis font
	m_ftAngles.CreatePointFont(88, "ARIAL", NULL);
	m_ftCurrentAngle.CreatePointFont(135, "ARIAL", NULL);
}

void CAttitudeCtrl::CreatePlane()
{
	//Delete any previous bmp
	m_Bitmap.DeleteObject();
	//recreate new bmp with new sizes
	m_Bitmap.CreateBitmap(m_Rect.Width(), BMP_HEIGHT,1,32,NULL);
	//select the bmp into memory DC
	CBitmap *pOldBmp = m_DC1.SelectObject(&m_Bitmap);
	
	FillPlane();

	
}

void CAttitudeCtrl::FillPlane()
{
	m_DC1.SelectObject(&m_brPlane);
	m_DC1.FloodFill(0,0,crPlane);
}

int CAttitudeCtrl::TransformToScale(int rawAngle)
{
	if(rawAngle == 0)
		return 361;	//
	else if(rawAngle > 0)
	{
		//Transform for 0-359 pixels
		return 359-(abs(rawAngle*2));
	}
	else
	{
		//Transform for 362 - 722
		return 362+(abs(rawAngle*2));
	}


}

void CAttitudeCtrl::DrawAxes()
{
	//Reference point
	POINT ref = {0,0};

	//DRAW VERTICAL AXIS
	m_DC1.SelectObject(&m_penAxisY);
	m_DC1.MoveTo(ref);
	ref.y = BMP_HEIGHT;
	m_DC1.LineTo(ref);

}

void CAttitudeCtrl::DrawLine()
{ 
	int i; //counter
	int offset = m_Rect.Width();
	m_DC1.SelectObject(m_ftCurrentAngle);
	m_pOldPen = m_DC1.SelectObject(&m_penData1);

	if(m_bLine1)	
	{
		for(i = m_qHistory1.size()-1; i>=0;i--)
		{	 
			m_pPolyLine1[i].x = offset -= m_OffsetInc;
			m_pPolyLine1[i].y = TransformToScale((int)m_qHistory1[i]);	
		}
	
		m_DC1.Polyline(m_pPolyLine1, m_qHistory1.size()); 
	}

	offset = m_Rect.Width();
	if(m_bLine2)
	{
		for(i = m_qHistory2.size()-1; i>=0;i--)
		{	 
			m_pPolyLine2[i].x = offset -= m_OffsetInc;
			m_pPolyLine2[i].y = TransformToScale((int)m_qHistory2[i]);	
		}
	
		m_DC1.SelectObject(&m_penData2);
		m_DC1.Polyline(m_pPolyLine2, m_qHistory2.size()); 
	}

	offset = m_Rect.Width();
	if(m_bLine3)
	{
		for(i = m_qHistory3.size()-1; i>=0;i--)
		{	 
			m_pPolyLine3[i].x = offset -= m_OffsetInc;
			m_pPolyLine3[i].y = TransformToScale((int)m_qHistory3[i]);	
		}
	
		m_DC1.SelectObject(&m_penData3);
		m_DC1.Polyline(m_pPolyLine3, m_qHistory3.size()); 
	}

	offset = m_Rect.Width();
	if(m_bLine4)
	{
		for(i = m_qHistory4.size()-1; i>=0;i--)
		{	 
			m_pPolyLine4[i].x = offset -= m_OffsetInc;
			m_pPolyLine4[i].y = TransformToScale((int)m_qHistory4[i]);	
		}
	
		m_DC1.SelectObject(&m_penData4);
		m_DC1.Polyline(m_pPolyLine4, m_qHistory4.size()); 
	}

	m_DC1.SelectObject(&m_pOldPen);
}

void CAttitudeCtrl::Render()
{
	m_Rect = GetBltRect();

	CString current;			//for local use many times...
	int w = m_Rect.Width();		//get once
	int h = m_Rect.Height();    //get once
	
	//Figure out our zoom scale
	int startY = (180-m_nDegreeScale)*2;
	int height = (m_nDegreeScale*4)+2;
	
	m_DC2.StretchBlt(		0,0,//m_Rect.left,m_Rect.top,
						    w, h,
							&m_DC1,
							0,startY,w,height,SRCCOPY );	
	
	
	//DRAW UNZOOMED AXIS
	m_DC2.SelectObject(&m_penAxisX);
	POINT temp = {0,h/2};
	m_DC2.MoveTo(temp);
	temp.x = w;
	m_DC2.LineTo(temp);

	//Select a new font temporarily
	void *old = m_DC2.SelectObject(&m_ftAngles);

	//Draw the unzoomed axis elements/text
	
	temp.x = 0;
	temp.y = 0;
	int mid = h/2 +1;
	temp.y = mid-(mid/2);
	m_DC2.MoveTo(temp);
	temp.x = 8;
	m_DC2.LineTo(temp);
	current.Format("%.1f°", (float)m_nDegreeScale/2);
	m_DC2.TextOut(temp.x+5,temp.y-7, current);
	temp.x = 0;
	temp.y = mid+(mid/2);
	m_DC2.MoveTo(temp);
	temp.x = 8;
	m_DC2.LineTo(temp);
	current.Format("-%.1f°", (float)m_nDegreeScale/2);
	m_DC2.TextOut(temp.x+5,temp.y-7, current);

	//Select our original font
	m_DC2.SelectObject((CFont*)old);

	//Write text  
	//if(m_qHistory.size())
	//{
		
	//	current.Format("Current Value: %3f", m_qHistory[0]);
	//	m_DC2.TextOut(10,5, current);
	//}

	//DO FINAL BLTTING
	CDC *pDC = m_pParentWnd->GetDC();

	pDC->StretchBlt(m_Rect.left,m_Rect.top,
						    w, h,
							&m_DC2,
							0,0,w,h,SRCCOPY);

	m_pParentWnd->ReleaseDC(pDC);

}

CRect CAttitudeCtrl::GetBltRect()
{
	CRect temp;
		
	m_pwndBltArea->GetWindowRect(&temp);
	m_pParentWnd->ScreenToClient(&temp);
	
	return temp;
}



