// SixtyFourDoc.cpp : implementation of the CSixtyFourDoc class
//

#include "stdafx.h"
#include "SixtyFour.h"
#include "Search.h"
#include "SixtyFourDoc.h"

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

/////////////////////////////////////////////////////////////////////////////
// CSixtyFourDoc

IMPLEMENT_DYNCREATE(CSixtyFourDoc, CDocument)

BEGIN_MESSAGE_MAP(CSixtyFourDoc, CDocument)
	//{{AFX_MSG_MAP(CSixtyFourDoc)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSixtyFourDoc construction/destruction

CSixtyFourDoc::CSixtyFourDoc()
{
	// TODO: add one-time construction code here

}

CSixtyFourDoc::~CSixtyFourDoc()
{
}

BOOL CSixtyFourDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	CSixtyFourApp *pApp = (CSixtyFourApp*)AfxGetApp();
	ASSERT_VALID(pApp);

	for (int i = 0; i < 64; i++)
		m_uGameCube[i] = 0;

	switch(pApp->m_nSettingCPUColor)
	{
	case DIALOG_COLOR_NEITHER:
		m_plPlayers[PLAYER_RED].nType = PLAYER_TYPE_MOUSE;
		m_plPlayers[PLAYER_BLUE].nType = PLAYER_TYPE_MOUSE;
		break;
	case DIALOG_COLOR_RED:
		m_plPlayers[PLAYER_RED].nType = PLAYER_TYPE_COMPUTER;
		m_plPlayers[PLAYER_BLUE].nType = PLAYER_TYPE_MOUSE;
		break;
	case DIALOG_COLOR_BLUE:
		m_plPlayers[PLAYER_RED].nType = PLAYER_TYPE_MOUSE;
		m_plPlayers[PLAYER_BLUE].nType = PLAYER_TYPE_COMPUTER;
		break;
	case DIALOG_COLOR_BOTH:
		m_plPlayers[PLAYER_RED].nType = PLAYER_TYPE_COMPUTER;
		m_plPlayers[PLAYER_BLUE].nType = PLAYER_TYPE_COMPUTER;
		break;
	}

	m_gldRotateAroundX = m_gldRotateAroundY = 0;

	m_nGameState = GAME_PLAYING;
	m_nCurrentPlayer = PLAYER_RED;
	m_bGameOver = FALSE;

	m_nCurrentMove = m_nLastMove = -1;

	return TRUE;
}



/////////////////////////////////////////////////////////////////////////////
// CSixtyFourDoc serialization

void CSixtyFourDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		ar << m_gldRotateAroundX << m_gldRotateAroundY;
		for (int i = 0; i <= m_nLastMove; i++)
			ar << m_moveHistory[i].nMoveI << m_moveHistory[i].nMoveJ << m_moveHistory[i].nMoveK;
	}
	else	// loading
	{
		OnNewDocument();

		int i, j, k;
		Move move;

		ar >> m_gldRotateAroundX >> m_gldRotateAroundY;

		do
		{
			ar >> i >> j >> k;

			move.nMoveI = i;
			move.nMoveJ = j;
			move.nMoveK = k;

			if (!MakeMove(move))
			{
				AfxThrowArchiveException(CArchiveException::badClass, NULL);
				return;
			}

			SwitchPlayers();
		}
		while (!ar.IsBufferEmpty());
	}
}

BOOL CSixtyFourDoc::MakeMove(Move move, BOOL bUpdateHistory)
{
	int nLoc = (move.nMoveI << 4) + (move.nMoveJ << 2) + move.nMoveK;

	if ((m_uGameCube[nLoc] & MOVE) == PLAYER_NONE)
	{
		m_uGameCube[nLoc] = m_nCurrentPlayer;

		if (bUpdateHistory)
		{
			m_nCurrentMove++;
			m_nLastMove = m_nCurrentMove;

			m_moveHistory[m_nCurrentMove].nMoveI = move.nMoveI;
			m_moveHistory[m_nCurrentMove].nMoveJ = move.nMoveJ;
			m_moveHistory[m_nCurrentMove].nMoveK = move.nMoveK;
		}

		if (m_nWinner = IsGameOver())
			m_bGameOver = TRUE;

		return TRUE;
	}

	return FALSE;
}

void CSixtyFourDoc::UnMakeMove(Move move)
{
	int nLoc = (move.nMoveI << 4) + (move.nMoveJ << 2) + move.nMoveK;
	m_uGameCube[nLoc] = PLAYER_NONE;
	m_bGameOver = IsGameOver();
}

void CSixtyFourDoc::SwitchPlayers()
{
	m_nCurrentPlayer = (m_nCurrentPlayer == PLAYER_RED) ? PLAYER_BLUE : PLAYER_RED;
}

UINT CSixtyFourDoc::GetOpponent()
{
	return m_nCurrentPlayer == PLAYER_RED ? PLAYER_BLUE : PLAYER_RED;
}

BOOL CSixtyFourDoc::HistoryCanGoBack()
{
	return m_nCurrentMove >= 0;
}

BOOL CSixtyFourDoc::HistoryCanGoForward()
{
	return m_nCurrentMove < m_nLastMove;
}

void CSixtyFourDoc::HistoryGoBack()
{
	if (!HistoryCanGoBack())
		return;
	
	UnMakeMove(m_moveHistory[m_nCurrentMove--]);
	SwitchPlayers();
}

void CSixtyFourDoc::HistoryGoForward()
{
	if (!HistoryCanGoForward())
		return;

	MakeMove(m_moveHistory[++m_nCurrentMove], FALSE);
	SwitchPlayers();
}

void CSixtyFourDoc::HistoryGoStart()
{
	while(HistoryCanGoBack())
		HistoryGoBack();
}

void CSixtyFourDoc::HistoryGoEnd()
{
	while(HistoryCanGoForward())
		HistoryGoForward();
}

UINT CSixtyFourDoc::IsGameOver()
{
	int nEval;
	g_bRecord = TRUE;
	nEval = searchEvaluate(m_uGameCube, m_nCurrentPlayer);

	if (nEval >= INFINITY)
		return PLAYER_RED;
	else if (nEval <= -INFINITY)
		return PLAYER_BLUE;
	else for (int i = 0; i < 64; i++)
		if ((m_uGameCube[i] & MOVE) == 0)
			return PLAYER_NONE;
	
	return PLAYER_BOTH;
}

/////////////////////////////////////////////////////////////////////////////
// CSixtyFourDoc diagnostics

#ifdef _DEBUG
void CSixtyFourDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CSixtyFourDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CSixtyFourDoc commands

void CSixtyFourDoc::ReportSaveLoadException(LPCTSTR lpszPathName, CException* e, BOOL bSaving, UINT nIDPDefault) 
{
	OnNewDocument();
	UpdateAllViews(NULL);
	CDocument::ReportSaveLoadException(lpszPathName, e, bSaving, nIDPDefault);
}

