// mapqueryDlg.cpp : implementation file
//

#include "stdafx.h"
#include "mapquery.h"
#include "mapqueryDlg.h"
#include <stdio.h>

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

#define MAPLEFT 135
#define MAPTOP 10
#define MAPWIDTH 512
#define MAPHEIGHT 512

	const unsigned short	LEGPASS_FLAG 			= 0x0001;		// true if legged units cannot use
	const unsigned short	HOVERPASS_FLAG		= 0x0002;		// true if hover units cannot use
	const unsigned short	TRACKPASS_FLAG		= 0x0004;		// true if track units cannot use
	const unsigned short  WHEELPASS_FLAG		= 0x0008;		// true if wheel units cannot use
	const unsigned short  WATERPASS_FLAG		= 0x0010;		// true if water units cannot use
	const unsigned short  JUMPPASS_FLAG			= 0x0020;		// true if cannot jump through
	const unsigned short	MOVEPASSNOW_FLAG	= 0x0040;		// if a vehicle has this cell blocked now
	const unsigned short	BRIDGE_FLAG				= 0x0080;		// true if this cell is a bridge cell
	const unsigned short	WATER1_FLAG				= 0x0100;		// with water 2 for four levels of water
	const unsigned short	WATER2_FLAG				= 0x0200;		//  no, shallow, medium, deep
	const unsigned short	STEEP1_FLAG				= 0x0400;		// with steep 2 for steepness of slope for descending, going up uses blocked flags
	const unsigned short	STEEP2_FLAG				= 0x0800;		// mech down, track down, wheel down, hover down
	const unsigned short	SLOPEDIR1_FLAG		= 0x1000;		// quanta of slope direction
	const unsigned short	SLOPEDIR2_FLAG		= 0x2000;	
	const unsigned short	SLOPEDIR3_FLAG		= 0x4000;	
	
	const int HOVERDOWN_SLOPE = 0;
	const int WHEELDOWN_SLOPE = 1;
	const int TRACKDOWN_SLOPE = 2;
	const int LEGDOWN_SLOPE		= 3;
	const int STEEP_MASK			= 0x0c00;
	const int STEEP_SHIFT			= 10;

	const int NO_WATER				= 0;
	const int SHALLOW_WATER		= 1;
	const int MEDIUM_WATER		= 2;
	const int DEEP_WATER			= 3;
	const int WATER_MASK			= 0x0300;
	const int WATER_SHIFT			= 8;

	const int SLOPEDIR_MASK		= 0x7000;
	const int SLOPEDIR_SHIFT	= 12;

	const float LEGUP_SLOPE_THRESHOLD			= 0.707f;					//cos (45 deg)
	const float LEGDOWN_SLOPE_THRESHOLD		= 0.5f;					//cos (60 deg)
	
	const float TRACKUP_SLOPE_THRESHOLD		= 0.819f;					//cos (35 deg)
	const float TRACKDOWN_SLOPE_THRESHOLD = 0.707f;					//cos (45 deg)
	
	const float WHEELUP_SLOPE_THRESHOLD		= 0.906f;					//cos (25 deg)
	const float WHEELDOWN_SLOPE_THRESHOLD = 0.819f;					//cos (35 deg)

	const float HOVERUP_SLOPE_THRESHOLD		= 0.965f;					//cos (15 deg)
	const float HOVERDOWN_SLOPE_THRESHOLD = 0.906f;					//cos (25 deg)

	const unsigned short  BLOCKED_FLAGS			= 0x003f;		// for all blocked flags

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMapqueryDlg dialog

CMapqueryDlg::CMapqueryDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CMapqueryDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CMapqueryDlg)
	m_YValue = 0;
	m_XValue = 0;
	m_Value = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_Width = 1;
	m_Height = 1;
}

void CMapqueryDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CMapqueryDlg)
	DDX_Control(pDX, IDC_WHEEL, m_Wheel);
	DDX_Control(pDX, IDC_TRACK, m_Track);
	DDX_Control(pDX, IDC_LEG, m_Leg);
	DDX_Control(pDX, IDC_HOVER, m_Hover);
	DDX_Control(pDX, IDC_BLOCK, m_Block);
	DDX_Text(pDX, IDC_EDITYVALUE, m_YValue);
	DDV_MinMaxInt(pDX, m_YValue, 0, m_Height);
	DDX_Text(pDX, IDC_EDITXVALUE, m_XValue);
	DDV_MinMaxInt(pDX, m_XValue, 0, m_Width);
	DDX_Text(pDX, IDC_MAPVALUE, m_Value);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CMapqueryDlg, CDialog)
	//{{AFX_MSG_MAP(CMapqueryDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_QUERY, OnQuery)
	ON_BN_CLICKED(IDC_FILEOPEN, OnFileopen)
	ON_WM_MOUSEMOVE()
	ON_BN_CLICKED(IDC_BLOCK, OnBlock)
	ON_BN_CLICKED(IDC_HOVER, OnHover)
	ON_BN_CLICKED(IDC_LEG, OnLeg)
	ON_BN_CLICKED(IDC_TRACK, OnTrack)
	ON_BN_CLICKED(IDC_WHEEL, OnWheel)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMapqueryDlg message handlers

BOOL CMapqueryDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	
	m_MapSurf.Create (10,10,24);
	m_MapSurf.SetColor (RGB (0,0,0));
	m_Data = NULL;
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CMapqueryDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CMapqueryDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CPaintDC dc(this);
		HDC surfdc;

		surfdc = m_MapSurf.GetDC ();
		CDC surface;
		
		surface.Attach (surfdc);

		dc.StretchBlt (MAPLEFT,MAPTOP,MAPWIDTH,MAPHEIGHT,&surface,0,0,m_MapSurf.GetWidth (),m_MapSurf.GetHeight (),SRCCOPY);

		surface.Detach ();
		m_MapSurf.ReleaseDC (surfdc);

		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CMapqueryDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CMapqueryDlg::OnQuery() 
{
	// TODO: Add your control notification handler code here
	UpdateData (TRUE);

	int value;
	value = m_Data[m_YValue][m_XValue];
	m_Value.Format ("%x",value);
	UpdateData (FALSE);
}

void CMapqueryDlg::OnFileopen() 
{
	// TODO: Add your control notification handler code here
	CFileDialog dlg(TRUE);

	dlg.m_ofn.lpstrInitialDir = "content\\missions";

	if (dlg.DoModal ()== IDOK)
	{
		CString filename;
		FILE *file;
		int datasize,size,chunksize;

		m_Wheel.SetCheck (1);
		m_Track.SetCheck (1);
		m_Leg.SetCheck (1);
		m_Hover.SetCheck (1);
		m_Block.SetCheck (1);

		filename = dlg.GetPathName ();
		file = fopen ((LPCTSTR) filename,"rb");

		m_Data = NULL;
		m_AllocWidth = 0;
		m_AllocHeight = 0;
		fread (&m_Width,sizeof (m_Width),1,file);
		m_Width *= -1;
		fread (&m_Height,sizeof (m_Height),1,file);
		m_Height *= -1;
		fread (&datasize,sizeof (datasize),1,file);

		m_Width /= 10;
		m_Height /= 10;
		m_Data = new unsigned short *[m_Height];
		m_AllocHeight = m_Height;
		m_AllocWidth = m_Width;
		for (int i=0;i<m_Height;i++)
		{
			m_Data[i] = new unsigned short[m_Width];
		}

		
		size = m_Height;
		chunksize = m_Width;
		chunksize <<= 1;
		for (i=0;i<size;i++)
		{
			fread (m_Data[size - i - 1],chunksize,1,file);
			datasize -= chunksize;
		}

		int x,y;
		for (y=0;y<m_Height;y++)
		{
			for (x=0;x<(m_Width>>1);x++)
			{
				unsigned short temp;
				temp = m_Data[y][x];
				m_Data[y][x] = m_Data[y][m_Width-x];
				m_Data[y][m_Width-x] = temp;
			}
		}

		fclose (file);
		BuildSurface ();
	}
	
}

void CMapqueryDlg::BuildSurface(void) 
{
	int x,y;

	if (m_Data)
	{
		m_MapSurf.Create (m_Width,m_Height,24);
		for (y=0;y<m_Height;y++)
		{
			for (x=0;x<m_Width;x++)
			{
				m_MapSurf.SetColor (x,y,RGB (255,255,255));
				if (m_Data[y][x] & WATER_MASK)
				{
					switch ((m_Data[y][x] & WATER_MASK) >> WATER_SHIFT)
					{
					case SHALLOW_WATER:
						m_MapSurf.SetColor (x,y,RGB (0,0,255));
						break;
					case MEDIUM_WATER:
						m_MapSurf.SetColor (x,y,RGB (0,0,128));
						break;
					case DEEP_WATER:
						m_MapSurf.SetColor (x,y,RGB (0,0,64));
						break;
					}
					continue;
				}
				else if ((m_Leg.GetCheck ()) && (m_Data[y][x] & (LEGPASS_FLAG)))
				{
					m_MapSurf.SetColor (x,y,RGB (255,0,0));
				}
				else if ((m_Track.GetCheck ()) && (m_Data[y][x] & (TRACKPASS_FLAG)))
				{
					m_MapSurf.SetColor (x,y,RGB (196,0,0));
				}
				else if ((m_Wheel.GetCheck ()) && (m_Data[y][x] & (WHEELPASS_FLAG)))
				{
					m_MapSurf.SetColor (x,y,RGB (128,0,0));
				}
				else if ((m_Hover.GetCheck ()) && (m_Data[y][x] & (HOVERPASS_FLAG)))
				{
					m_MapSurf.SetColor (x,y,RGB (64,0,0));
				}
				else if (m_Data[y][x] & BRIDGE_FLAG)
				{
					m_MapSurf.SetColor (x,y,RGB (0,255,0));
				}
			}
		}
	}
	InvalidateRect (NULL,FALSE);
}

BOOL CMapqueryDlg::DestroyWindow() 
{
	int i,size;

	if (m_Data)
	{
		size = m_Height;
		for (i=0;i<size;i++)
		{
			delete[] m_Data[i];
		}
		delete[] m_Data;
		m_Data = NULL;
	}
	
	return CDialog::DestroyWindow();
}

void CMapqueryDlg::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	
	int mapx,mapy;

	if (!m_Data)
	{
		CDialog::OnMouseMove(nFlags, point);
		return;
	}
	mapx = point.x - MAPLEFT;
	mapy = point.y - MAPTOP;
	if ((mapx < 0) || (mapy < 0))
		CDialog::OnMouseMove(nFlags, point);
	else if ((mapx>=MAPWIDTH) || (mapy >= MAPHEIGHT))
		CDialog::OnMouseMove(nFlags, point);
	else
	{
		float dx,dy;

		dx = ((float) MAPWIDTH) / ((float) m_MapSurf.GetWidth ());
		dy = ((float) MAPHEIGHT) / ((float) m_MapSurf.GetHeight ());
		mapx /= dx;
		mapy /= dy;
		int value;
		value = m_Data[m_YValue][m_XValue];
		m_Value.Format ("%x",value);
		m_XValue = mapx;
		m_YValue = mapy;
		UpdateData (FALSE);
	}
}

void CMapqueryDlg::OnBlock() 
{
	// TODO: Add your control notification handler code here
	BuildSurface ();
	InvalidateRect (NULL,FALSE);
}

void CMapqueryDlg::OnHover() 
{
	// TODO: Add your control notification handler code here
	BuildSurface ();
	InvalidateRect (NULL,FALSE);
	
}

void CMapqueryDlg::OnLeg() 
{
	// TODO: Add your control notification handler code here
	BuildSurface ();
	InvalidateRect (NULL,FALSE);
	
}

void CMapqueryDlg::OnTrack() 
{
	// TODO: Add your control notification handler code here
	BuildSurface ();
	InvalidateRect (NULL,FALSE);
	
}

void CMapqueryDlg::OnWheel() 
{
	// TODO: Add your control notification handler code here
	BuildSurface ();
	InvalidateRect (NULL,FALSE);
	
}
