// MapDlg.cpp : implementation file
//

#include "stdafx.h"
#include "mdimap.h"
#include "MapDlg.h"
#include "MapFrm.h"

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

/////////////////////////////////////////////////////////////////////////////
// CMapDlg dialog


CMapDlg::CMapDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CMapDlg::IDD, pParent)
{
	m_Screen = NULL;
	m_WalkBits = NULL;
	//{{AFX_DATA_INIT(CMapDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
}

CMapDlg::~CMapDlg()
{
	CMapFrame* pParent = STATIC_DOWNCAST(CMapFrame, GetParentFrame());

	DELETEARRAY( m_WalkBits );
	SAFEDELETE( m_Screen );
}


void CMapDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CMapDlg)
		// NOTE: the ClassWizard will add DDX and DDV calls here
	//}}AFX_DATA_MAP
}

BOOL CMapDlg::InitCDX()
{
	m_Screen = new CDXScreen;
	m_Screen->CreateWindowed(m_hWnd,GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));

	return TRUE;

}


BEGIN_MESSAGE_MAP(CMapDlg, CDialog)
	//{{AFX_MSG_MAP(CMapDlg)
	ON_WM_DESTROY()
	ON_WM_HSCROLL()
	ON_WM_KEYDOWN()
	ON_WM_KILLFOCUS()
	ON_WM_LBUTTONDOWN()
	ON_WM_MOUSEMOVE()
	ON_WM_RBUTTONDOWN()
	ON_WM_SIZE()
	ON_WM_VSCROLL()
	ON_WM_PAINT()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMapDlg message handlers



BOOL CMapDlg::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	m_InWindow=FALSE;
	m_BKeyDown = FALSE;

	if(!InitCDX()) return FALSE;
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CMapDlg::OnDestroy() 
{
	CDialog::OnDestroy();
	
	// TODO: Add your message handler code here
	
}

void CMapDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{

	CMapFrame* pParent = STATIC_DOWNCAST(CMapFrame, GetParentFrame());
	UINT pos = GetScrollPos( SB_HORZ );

	pos = pParent->ScrollBar( nSBCode, pos, nPos, 5 );
	SetScrollPos( SB_HORZ, pos );

	PostMessage(WM_PAINT);
	
	CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CMapDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
/*	CMapFrame* pParent = STATIC_DOWNCAST(CMapFrame, GetParentFrame());

	if( m_Map[pParent->m_SelLayer] )
	{
		UINT x = GetScrollPos( SB_HORZ ),
			 y = GetScrollPos( SB_VERT );

		int speed = 2;
		if( GetAsyncKeyState( VK_SHIFT )&0x8000 )
			speed=4;

		if( nChar==VK_UP )
			y-=speed;
		else if( nChar==VK_DOWN )
			y+=speed;
		else if( nChar==VK_LEFT )
			x-=speed;
		else if( nChar==VK_RIGHT )
			x+=speed;

		if( nChar==VK_SHIFT )
		{	if( GetAsyncKeyState( VK_UP )&0x8000 )
				y-=speed;
			if( GetAsyncKeyState( VK_DOWN )&0x8000 )
				y+=speed;
			if( GetAsyncKeyState( VK_LEFT )&0x8000 )
				x-=speed;
			if( GetAsyncKeyState( VK_RIGHT )&0x8000 )
				x+=speed;
		}

		if( nChar=='B' )
		{	
			m_BKeyDown = TRUE;
			m_BlockX1 = m_BlockX2 = m_MouseTile.x;
			m_BlockY1 = m_BlockY2 = m_MouseTile.y;
		}

		SetScrollPos( SB_HORZ, x );
		SetScrollPos( SB_VERT, y );

		PostMessage(WM_PAINT);
	}
*/	CDialog::OnKeyDown(nChar, nRepCnt, nFlags);
}

void CMapDlg::OnKillFocus(CWnd* pNewWnd) 
{
	if( m_InWindow )
	{
		m_InWindow=FALSE;
		RedrawWindow( NULL, NULL, RDW_INVALIDATE | RDW_FRAME );
	}
	CDialog::OnKillFocus(pNewWnd);	
}

void CMapDlg::OnLButtonDown(UINT nFlags, CPoint point) 
{
	CMapFrame* pParent = STATIC_DOWNCAST(CMapFrame, GetParentFrame());

	if( m_BKeyDown )
	{
		m_BKeyDown=FALSE;

		int xSize = m_BlockX2-m_BlockX1+1;
		int ySize = m_BlockY2-m_BlockY1+1;

		pParent->SetBrush(pParent->GetSelBrush(), ySize, xSize, m_BlockX1, m_BlockY1);

		CDXMap *map = pParent->GetMap(pParent->GetSelLayer());

		int yPos = m_BlockY1;
		int xPos = m_BlockX1;

		for( int y=0; y<ySize; y++ )
		{
			if( yPos >= map->GetMapHeight() )
				yPos -= map->GetMapHeight();

			for( int x=0; x < xSize; x++ )
			{	
				if( xPos >= map->GetMapWidth() )
					xPos -= map->GetMapWidth();

				map->SetTile( xPos, yPos, pParent->GetBrush(pParent->GetSelBrush())[y * (xSize) + x] );
//				pParent->GetBrush(pParent->GetSelBrush())[y*(xSize)+x] = map->GetTile( xPos, yPos );
				xPos++;
			}
			yPos++;
		}
		pParent->UpdateMenu( );
	}
	else
	{	
		if( pParent->GetPaintBit() )
		{
			ChangeBit( pParent->GetSelBit() - 1 );
		}
		else
		{
			// Reset our undo system
			if( pParent->m_StoreUndo==FALSE )
			{	pParent->m_Undo.RemoveAll( );
				pParent->m_StoreUndo=TRUE;
			}

			// Draw the brush
			DrawBrush( );
		}
	}

	PostMessage(WM_PAINT);

	CDialog::OnLButtonDown(nFlags, point);
}

void CMapDlg::OnMouseMove(UINT nFlags, CPoint point) 
{
	CMapFrame* pParent = STATIC_DOWNCAST(CMapFrame, GetParentFrame());

	// If it was outside window, Set the input focus
	if( m_InWindow == FALSE )
	{
		SetFocus( );
		m_InWindow = TRUE;
//		SendMessage( WM_NCPAINT, 0, 0 );
	}

	m_MousePos = point;
	CDXMap *map = pParent->GetMap(pParent->GetSelLayer());
	if( map )
	{
		int newx = (m_MousePos.x + map->GetPosX()) / 32;
		int newy = (m_MousePos.y + map->GetPosY()) / 32;

		if( newx != m_MouseTile.x || newy != m_MouseTile.y )
		{
//			CString str;
//			str.Format( "Map Pos: x:%i / y:%i", newx, newy );
//			pParent->m_StatusBar->SetText(str,1,0);

			m_MouseTile.x = newx;
			m_MouseTile.y = newy;

			if( m_BKeyDown )
			{
				int x = m_MouseTile.x;
				int y = m_MouseTile.y;

				if( x > m_BlockX1 ) m_BlockX2 = x;
				else m_BlockX1 = x;

				if( y > m_BlockY1 ) m_BlockY2 = y;
				else m_BlockY1 = y;
			}
			else
			{
			// When the mouse is down, paint the brush
				if( GetAsyncKeyState(VK_LBUTTON)& 0x8000 )
				{
					if( pParent->GetPaintBit() )
						ChangeBit( pParent->GetSelBit() - 1 );
					else
						DrawBrush( );
				}
				else pParent->m_StoreUndo=FALSE;
			}
		}
	}

	CDialog::OnMouseMove(nFlags, point);

	PostMessage(WM_PAINT);

}

void CMapDlg::OnRButtonDown(UINT nFlags, CPoint point) 
{
	CMapFrame* pParent = STATIC_DOWNCAST(CMapFrame, GetParentFrame());
	CDXMap* map = pParent->GetMap(pParent->GetSelLayer());

	if( map )
	{
		CMenu menu;
		CMenu *submenu;
		// load the menu
		menu.LoadMenu(IDR_MAP);
		// get the popup menu
		submenu = menu.GetSubMenu(0);
		// convert to screen coordinates
		ClientToScreen(&point);
		// post the menu

		int bit=1;
		for( int i=0; i<6; i++ )
		{
			menu.CheckMenuItem( ID_WALKBITS1+i, (m_WalkBits[m_MouseTile.y * map->GetMapWidth() + m_MouseTile.x] & bit) ? MF_CHECKED : MF_UNCHECKED );
			bit<<=1;
		}
		submenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
			                    point.x, point.y,
				                AfxGetApp()->m_pMainWnd,NULL);	
	}
	
	CDialog::OnRButtonDown(nFlags, point);
}

void CMapDlg::OnSize(UINT nType, int cx, int cy) 
{
	CDialog::OnSize(nType, cx, cy);

	m_xTiles=(cx)/32;
	m_yTiles=(cy)/32;
	ReCalcScreen( );
}

void CMapDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{

	CMapFrame* pParent = STATIC_DOWNCAST(CMapFrame, GetParentFrame());
	UINT pos = GetScrollPos( SB_VERT );

	pos = pParent->ScrollBar( nSBCode, pos, nPos, 5 );
	SetScrollPos( SB_VERT, pos );

	PostMessage(WM_PAINT);

	CDialog::OnVScroll(nSBCode, nPos, pScrollBar);
}


/////////////////////////////////////////////////////////////////////////////
//Miscellaneous Functions
void CMapDlg::DrawScreen()
{
	CMapFrame* pParent = STATIC_DOWNCAST(CMapFrame, GetParentFrame());
	CDXMap* map = NULL;

	if(!m_Screen)
		return;

	m_Screen->GetBack( )->Fill( 0 );

	int s = pParent->GetSelLayer(), e = pParent->GetSelLayer() + 1;

	if( pParent->cfg.m_AllLayers>0 )
	{	
		s = 0;
		e = 2;
	}

	for( int i = s; i < e; i++ )
	{
		map = pParent->GetMap(i);
		if( map )
		{
			map->MoveTo( GetScrollPos( SB_HORZ )*4, GetScrollPos( SB_VERT )*4 );

			// Draw Map with correct settings
			int type=0;

			if( pParent->cfg.m_ColorKey && i==1 )
				type = CDXBLT_TRANS;
			
			if( pParent->cfg.m_AllLayers>1 && i != pParent->GetSelLayer() )
				type += 2;

			map->Draw(m_Screen->GetBack(), type, FALSE);
		}
	}

	map = pParent->GetMap(0);

	if( map && pParent->GetSelBit() > 0 )
	{
	    int xoff = map->GetPosX() % map->GetTileWidth();
		int yoff = map->GetPosY() % map->GetTileHeight();
		int xs = GetScrollPos( SB_HORZ ) / 8;
		int ys = GetScrollPos( SB_VERT ) / 8;
		int bit = 1 << (pParent->GetSelBit() - 1);
		for( int y = ys;
			 y < min(ys + map->GetScreenBlocksHeight(), map->GetMapHeight());
			 y++ )
		{
			for( int x = xs;
				 x < min(xs + map->GetScreenBlocksWidth(), map->GetMapWidth());
				 x++ )
			{
				if( m_WalkBits[ (y * map->GetMapWidth()) + x ] & bit )
					m_Screen->GetBack()->FillRect( (x-xs)*32-xoff, (y-ys)*32-yoff, (x-xs)*32+8-xoff, (y-ys)*32+8-yoff, RGB( 0, 255, 0 ) );
				else 
					m_Screen->GetBack()->FillRect( (x-xs)*32-xoff, (y-ys)*32-yoff, (x-xs)*32+8-xoff, (y-ys)*32+8-yoff, RGB( 255,0, 0 ) );
			}
		}
	}

	CDXTile* tiles = pParent->GetTiles(pParent->GetSelLayer());
	map = pParent->GetMap(pParent->GetSelLayer());

	if( map && tiles )
	{
		// If the mouse is in the window (Draw the Brush)
		if( m_InWindow )
		{	
			if( !m_BKeyDown )
			{
				if( pParent->GetBrush(pParent->GetSelBrush()) )
				{
					int xPos = ( (m_MousePos.x + (map->GetPosX() % 32)) / 32 * 32 ) - (map->GetPosX() % 32);
					int yPos = ( (m_MousePos.y + (map->GetPosY() % 32)) / 32 * 32 ) - (map->GetPosY() % 32);
					int BrushId = pParent->GetSelBrush();

					for( int y=0; y < pParent->GetBrushY(BrushId); y++ )
					{	
						for( int x=0; x < pParent->GetBrushX(BrushId); x++ )
						{	
							int tile = pParent->GetBrush(BrushId)[y * pParent->GetBrushX(BrushId) + x];
							if( pParent->cfg.m_DrawTrans )
								tiles->Draw( xPos + x * 32,
											 yPos + y * 32,
											 m_Screen->GetBack( ),
											 CDXBLT_BLKALPHAFAST, tile );
							else tiles->Draw( xPos + x * 32,
											  yPos + y * 32,
											  m_Screen->GetBack( ),
											  CDXBLT_BLK,
											  tile );
						}
					}
				}
			}
			else
			{
				int scx = GetScrollPos( SB_HORZ ) * 4,
				    scy = GetScrollPos( SB_VERT ) * 4;
				for( int y = m_BlockY1; y <= m_BlockY2; y++ )
				{
					for( int x=m_BlockX1; x<=m_BlockX2; x++ )
					{
						m_Screen->GetBack( )->InvertColors( x * 32 - scx,
													  y * 32 - scy,
													  x * 32 + 32 - scx,
													  y * 32 + 32 - scy );
					}
				}
			}
		}
	}

	//Flip screen
	m_Screen->Flip( pParent->cfg.m_PlayAnim, FALSE );
}

// Draws our selected brush at the mouse position
void CMapDlg::DrawBrush()
{
	CMapFrame* pParent = STATIC_DOWNCAST(CMapFrame, GetParentFrame());
	CDXMap *map = pParent->GetMap(pParent->GetSelLayer());
	int sel = pParent->GetSelBrush();

	if( map && pParent->GetBrush(sel) )
	{
		int yPos = (m_MousePos.y + map->GetPosY()) / 32;
		for( int y = 0; y < pParent->GetBrushY(sel); y++ )
		{
			if( yPos >= map->GetMapHeight() ) break; //yPos-=map->GetMapHeight();

			int xPos = (m_MousePos.x + map->GetPosX()) / 32;
			for( int x = 0; x < pParent->GetBrushX(sel); x++ )
			{	
				if( xPos>=map->GetMapWidth() ) break; // xPos-=map->GetMapWidth();

				// Save for Undo
				sUndo Undo;
				Undo.x = xPos;
				Undo.y = yPos;
				Undo.Tile = map->GetTile( xPos, yPos );
				pParent->m_Undo.Add( Undo );
				// end of Undo

				map->SetTile( xPos, yPos, pParent->GetBrush(sel)[(y * pParent->GetBrushX(sel)) + x] );
				xPos++;
			}
			yPos++;
		}
		pParent->m_Changed=TRUE;
	}
}


//move to CMapFrame!
void CMapDlg::ReCalcScreen()
{
	CMapFrame* pParent = STATIC_DOWNCAST(CMapFrame, GetParentFrame());
	CDXMap *map = pParent->GetMap(pParent->GetSelLayer());

	if( map )
	{
		SetScrollRange( SB_HORZ, 0, (map->GetMapWidth()-m_xTiles)*8 );
		SetScrollRange( SB_VERT, 0, (map->GetMapHeight()-m_yTiles)*8 );
		RECT rc;
		GetClientRect( &rc );
		rc.right += 31;
		rc.bottom += 31;
		map->SetViewPort( &rc );
	}


	//NOTE: create a pParent->Paint that does this
	pParent->PostMessage(WM_PAINT);
}

void CMapDlg::ChangeBit(int bitnr)
{
	CMapFrame* pParent = STATIC_DOWNCAST(CMapFrame, GetParentFrame());

	int bit = 1<<bitnr;
	int off = m_MouseTile.y * pParent->GetMap(0)->GetMapWidth() + m_MouseTile.x;

	if( m_WalkBits[off]&bit )
		m_WalkBits[off]&=~bit;
	else
		m_WalkBits[off]|=bit;
}

void CMapDlg::OnPaint() 
{
	DrawScreen();
	CDialog::OnPaint();
}
