/****************************************************************************
*                                                                           *
* Project 64 - A Nintendo 64 emulator.                                      *
* http://www.pj64-emu.com/                                                  *
* Copyright (C) 2012 Project64. All rights reserved.                        *
*                                                                           *
* License:                                                                  *
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html                        *
*                                                                           *
****************************************************************************/
#include "stdafx.h"
#include "Debugger UI.h"

CDebugMemorySearch::CDebugMemorySearch(CDebugger * debugger) :
	CDebugDialog<CDebugMemorySearch>(debugger),
	m_MemoryState(NULL),
	m_MemoryStateSize(0)
{
}

CDebugMemorySearch::~CDebugMemorySearch()
{
	if (m_MemoryState)
	{
		delete m_MemoryState;
	}
}

void CDebugMemorySearch::AddAlignmentOptions (CComboBox  & ctrl)
{
	int Index = ctrl.AddString("32 bits (aligned)");
	ctrl.SetItemData(Index,_32Bit);
	Index = ctrl.AddString("16bits (aligned)");
	ctrl.SetItemData(Index,_16Bit);
	Index = ctrl.AddString("8bits");
	ctrl.SetCurSel(Index);
	ctrl.SetItemData(Index,_8Bit);
}

LRESULT	CDebugMemorySearch::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	m_PAddrStart.Attach(GetDlgItem(IDC_PADDR_START));
	m_PAddrStart.SetDisplayType(CEditNumber::DisplayHex);
	m_SearchLen.Attach(GetDlgItem(IDC_ADDR_END));
	m_SearchLen.SetDisplayType(CEditNumber::DisplayHex);
	m_SearchValue.Attach(GetDlgItem(IDC_SEARCH_VALUE));
	m_SearchValue.SetDisplayType(CEditNumber::DisplayDec);
	m_SearchValue.SetValue(0);
	m_MaxSearch.Attach(GetDlgItem(IDC_MAX_SEARCH));
	m_MaxSearch.SetDisplayType(CEditNumber::DisplayDec);
	m_MaxSearch.SetValue(50000);
	m_UnknownSize.Attach(GetDlgItem(IDC_UNKNOWN_ALIGN));
	AddAlignmentOptions(m_UnknownSize);
	m_ValueSize.Attach(GetDlgItem(IDC_VALUE_ALIGN));
	AddAlignmentOptions(m_ValueSize);
	m_SearchResults.Attach(GetDlgItem(IDC_LST_RESULTS));
	m_SearchResults.AddColumn("ID",0);
	m_SearchResults.AddColumn("PAddr",1);
	m_SearchResults.AddColumn("Value",2);
	m_SearchResults.SetColumnWidth(0,50);
	m_SearchResults.SetColumnWidth(1,75);
	m_SearchResults.SetColumnWidth(2,75);
	m_SearchResults.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT);
	m_UnknownOptions.Attach(GetDlgItem(IDC_CMB_UNKNOWN));
	m_HaveResults = false;
	FixUnknownOptions(true);

	SendMessage(GetDlgItem(IDC_RADIO_VALUE),BM_SETCHECK, BST_CHECKED,0);

	BOOL bHandled;
	OnClicked(0,IDC_BTN_RDRAM,NULL,bHandled);
	OnClicked(0,IDC_RADIO_VALUE,NULL,bHandled);
	WindowCreated();
	return TRUE;
}

LRESULT	CDebugMemorySearch::OnClicked(WORD /*wNotifyCode*/, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/)
{
	switch(wID)
	{
	case IDCANCEL:
		EndDialog(0);
		break;
	case IDC_BTN_RDRAM:
		m_PAddrStart.SetValue(0,true,true);
		m_SearchLen.SetValue(g_MMU->RdramSize(),true,true);
		break;
	case IDC_BTN_ROM:
		m_PAddrStart.SetValue(0x10000000,true,true);
		m_SearchLen.SetValue(g_Rom->GetRomSize(),true,true);
		break;
	case IDC_BTN_SPMEM:
		m_PAddrStart.SetValue(0x04000000,true,true);
		m_SearchLen.SetValue(0x2000,true,true);
		break;		
	case IDC_SEARCH_HEX:
		{
			bool bChecked = (SendMessage(hWndCtl, BM_GETSTATE, 0,0) & BST_CHECKED) != 0; 
			m_SearchValue.SetDisplayType( bChecked ? CEditNumber::DisplayHex : CEditNumber::DisplayDec);
		}
		break;
	case ID_POPUP_SHOWINMEMORYVIEWER:
		{
			LONG iItem = m_SearchResults.GetNextItem(-1, LVNI_SELECTED);
			if (iItem == -1) 
			{
				break;
			}

			int ItemId = m_SearchResults.GetItemData(iItem);
			SearchResultItem & Result = m_SearchResult[ItemId];
			m_Debugger->Debug_ShowMemoryLocation(Result.PAddr, false);
		}
		break;
	case IDC_RADIO_UNKNOWN:
		EnableUnknownOptions(true);
		EnableValueOptions(false);
		EnableTextOptions(false);
		EnableJalOptions(false);
		break;
	case IDC_RADIO_VALUE:
		EnableUnknownOptions(false);
		EnableValueOptions(true);
		EnableTextOptions(false);
		EnableJalOptions(false);
		break;
	case IDC_RADIO_TEXT:
		EnableUnknownOptions(false);
		EnableValueOptions(false);
		EnableTextOptions(true);
		EnableJalOptions(false);
		break;
	case IDC_RADIO_JAL:
		EnableUnknownOptions(false);
		EnableValueOptions(false);
		EnableTextOptions(false);
		EnableJalOptions(true);
		break;
	case IDC_BTN_SEARCH:
		if (SendMessage(GetDlgItem(IDC_RADIO_UNKNOWN),BM_GETSTATE, 0,0) == BST_CHECKED)
		{
			g_BaseSystem->ExternalEvent(SysEvent_PauseCPU_SearchMemory); 
			SearchForUnknown();
			g_BaseSystem->ExternalEvent(SysEvent_ResumeCPU_SearchMemory); 
			break;
		} 
		if (SendMessage(GetDlgItem(IDC_RADIO_VALUE),BM_GETSTATE, 0,0) == BST_CHECKED)
		{
			g_BaseSystem->ExternalEvent(SysEvent_PauseCPU_SearchMemory); 
			SearchForValue();
			g_BaseSystem->ExternalEvent(SysEvent_ResumeCPU_SearchMemory); 
			break;
		} 
		if (SendMessage(GetDlgItem(IDC_RADIO_TEXT),BM_GETSTATE, 0,0) == BST_CHECKED)
		{
			g_BaseSystem->ExternalEvent(SysEvent_PauseCPU_SearchMemory); 
			SearchForText();
			g_BaseSystem->ExternalEvent(SysEvent_ResumeCPU_SearchMemory); 
			break;
		}
	case IDC_RESET_BUTTON:
		Reset();
		break;
	}
	return FALSE;
}

LRESULT CDebugMemorySearch::OnResultRClick ( LPNMHDR /*lpnmh*/ )
{
	LONG iItem = m_SearchResults.GetNextItem(-1, LVNI_SELECTED);
	if (iItem == -1) 
	{
		return true;
	}

	//Load the menu
	HMENU hMenu = LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_MEM_SEARCH));
	HMENU hPopupMenu = GetSubMenu(hMenu,0);

	//Get the current Mouse location
	POINT Mouse;
	GetCursorPos(&Mouse);

	//Show the menu
	TrackPopupMenu(hPopupMenu, 0, Mouse.x, Mouse.y, 0,m_hWnd, NULL);
	DestroyMenu(hMenu);
	return true;
}

void CDebugMemorySearch::EnableValueOptions( bool Enable )
{
	if (Enable)
	{
		::SetWindowText(GetDlgItem(IDC_BTN_SEARCH),m_HaveResults ? "Search Results" : "Search");
	}
	::EnableWindow(GetDlgItem(IDC_SEARCH_VALUE),Enable);
	::EnableWindow(GetDlgItem(IDC_SEARCH_HEX),Enable);
	::EnableWindow(GetDlgItem(IDC_VALUE_ALIGN),m_HaveResults ? false : Enable );
}

void CDebugMemorySearch::EnableTextOptions( bool Enable )
{
	if (Enable)
	{
		::SetWindowText(GetDlgItem(IDC_BTN_SEARCH),m_HaveResults ? "Search Results" : "Search");
	}
	::EnableWindow(GetDlgItem(IDC_SEARCH_TEXT),Enable);
	::EnableWindow(GetDlgItem(IDC_CASE_SENSITIVE),Enable);
}

void CDebugMemorySearch::EnableJalOptions( bool Enable )
{
	if (Enable)
	{
		::SetWindowText(GetDlgItem(IDC_BTN_SEARCH),m_HaveResults ? "Search Results" : "Search");
	}
	::EnableWindow(GetDlgItem(IDC_JAL_ADDR),Enable);
}

void CDebugMemorySearch::EnableUnknownOptions( bool Enable )
{
	if (m_UnknownOptions.GetCount() > 1)
	{
		::EnableWindow(GetDlgItem(IDC_UNKNOWN_ALIGN),m_HaveResults ? false : Enable );
		if (Enable)
		{
			::SetWindowText(GetDlgItem(IDC_BTN_SEARCH), m_HaveResults ? "Search Results" : "Search");
		}
	} else {
		::EnableWindow(GetDlgItem(IDC_UNKNOWN_ALIGN), false );
		if (Enable)
		{
			::SetWindowText(GetDlgItem(IDC_BTN_SEARCH), "Create");
		}
	}
	::EnableWindow(GetDlgItem(IDC_CMB_UNKNOWN),Enable);
}

void CDebugMemorySearch::SearchForValue( void )
{
	MemorySize Size = (MemorySize)m_ValueSize.GetItemData(m_ValueSize.GetCurSel());
	DWORD Value = m_SearchValue.GetValue();
	DWORD StartAddress = m_PAddrStart.GetValue();
	DWORD Len = m_SearchLen.GetValue();
	DWORD MaxSearch = m_MaxSearch.GetValue();
	
	DWORD MoveSize = (Size == _32Bit ? 4 : (Size == _16Bit ? 2 : 1));
	
	m_UnknownSize.SetCurSel(m_ValueSize.GetCurSel());

	LPCTSTR DisplayStr = "0x%08X";
	if (Size == _16Bit) { DisplayStr = "0x%04X"; }
	else if (Size == _8Bit) { DisplayStr = "0x%04X"; }

	if (!m_HaveResults)
	{		
		m_HaveResults = true;

		FixUnknownOptions(false);
		m_SearchResults.DeleteAllItems();
		DWORD ItemsAdded = 0;

		while (SearchForValue(Value,Size,StartAddress,Len))
		{
			SearchResultItem Result;
			Result.PAddr = StartAddress;
			Result.Value = Value;

			char LocationStr[20];
			sprintf(LocationStr,"%d",ItemsAdded + 1);
			int Index = m_SearchResults.AddItem(ItemsAdded,0,LocationStr);
			m_SearchResults.SetItemData(Index,m_SearchResult.size());
			m_SearchResult.push_back(Result);
			sprintf(LocationStr,"0x%08X",StartAddress);
			m_SearchResults.SetItemText(Index,1,LocationStr);
			sprintf(LocationStr,DisplayStr,Value);
			m_SearchResults.SetItemText(Index,2,LocationStr);
			sprintf(LocationStr,DisplayStr,Value);
			m_SearchResults.SetItemText(Index,3,LocationStr);
			StartAddress += MoveSize;
			Len -= MoveSize;
			ItemsAdded += 1;
			if (ItemsAdded >= MaxSearch)
			{
				break;
			}
		}
		::SetWindowText(GetDlgItem(IDC_BTN_SEARCH),"Search Results");
		::ShowWindow(GetDlgItem(IDC_RESET_BUTTON),SW_SHOW);
		::EnableWindow(GetDlgItem(IDC_VALUE_ALIGN),false);
	} else {
		int ItemCount = m_SearchResults.GetItemCount();
		for (int i = ItemCount - 1; i >= 0; i--)
		{
			int ItemId = m_SearchResults.GetItemData(i);
			SearchResultItem & Result = m_SearchResult[ItemId];
			
			DWORD NewValue = 0;
			BOOL valid = false;

			switch (Size) {
			case _8Bit:
				{
					BYTE mem = 0;
					valid = g_MMU->LB_PAddr(Result.PAddr, mem);
					NewValue = mem;
				}
				break;
			case _16Bit:
				{
					WORD mem = 0;
					valid = g_MMU->LH_PAddr(Result.PAddr, mem);
					NewValue = mem;
				}
				break;
			case _32Bit:
				valid = g_MMU->LW_PAddr(Result.PAddr, NewValue);
				break;
			default:
				g_Notify->BreakPoint(__FILEW__,__LINE__);
			}

			if (Value == NewValue)
			{
				char LocationStr[20];
				sprintf(LocationStr,DisplayStr,NewValue);
				m_SearchResults.SetItemText(i,2,LocationStr);
				sprintf(LocationStr,DisplayStr,Result.Value);
				m_SearchResults.SetItemText(i,3,LocationStr);
				Result.Value = NewValue;
			} else {
				m_SearchResults.DeleteItem(i);
			}
		}
	}
	::SetWindowText(GetDlgItem(IDC_BORDER_RESULTS),stdstr_f("Results (%d)",m_SearchResults.GetItemCount()).c_str());	
}

void CDebugMemorySearch::SearchForUnknown()
{
	SearchMemChangeState Option = (SearchMemChangeState)m_UnknownOptions.GetItemData(m_UnknownOptions.GetCurSel());
	if (Option == SearchChangeState_Reset)
	{
		m_SearchResults.DeleteAllItems();
		SearchSetBaseForChanges();
		FixUnknownOptions(false);
		::ShowWindow(GetDlgItem(IDC_RESET_BUTTON),SW_SHOW);
		::EnableWindow(GetDlgItem(IDC_UNKNOWN_ALIGN),true );
		return;
	}
	MemorySize Size = (MemorySize)m_UnknownSize.GetItemData(m_UnknownSize.GetCurSel());
	m_ValueSize.SetCurSel(m_UnknownSize.GetCurSel());
	LPCTSTR DisplayStr = "0x%08X";
	if (Size == _16Bit) { DisplayStr = "0x%04X"; }
	else if (Size == _8Bit) { DisplayStr = "0x%04X"; }
	if (!m_HaveResults)
	{		
		m_HaveResults = true;

		::EnableWindow(GetDlgItem(IDC_UNKNOWN_ALIGN),false );
		DWORD StartAddress = m_PAddrStart.GetValue();
		DWORD Len = m_SearchLen.GetValue();
		DWORD MaxSearch = m_MaxSearch.GetValue();

		DWORD MoveSize = (Size == _32Bit ? 4 : (Size == _16Bit ? 2 : 1));
	
		for (int i = 2; i <  10; i++)
		{
			if (!m_SearchResults.DeleteColumn(i))
			{
				break;
			}
		}
		m_SearchResults.AddColumn("New Value",2);
		m_SearchResults.AddColumn("Old Value",3);
		m_SearchResults.SetColumnWidth(0,50);
		m_SearchResults.SetColumnWidth(1,75);
		m_SearchResults.SetColumnWidth(2,75);
		m_SearchResults.SetColumnWidth(3,75);

		m_SearchResults.DeleteAllItems();
		DWORD ItemsAdded = 0, OldValue, NewValue;
		
		while (SearchForChanges(Option,Size,StartAddress,Len,OldValue,NewValue))
		{
			SearchResultItem Result;
			Result.PAddr = StartAddress;
			Result.Value = NewValue;

			//if list size > max, then break
			char LocationStr[20];
			sprintf(LocationStr,"%d",ItemsAdded + 1);
			int Index = m_SearchResults.AddItem(ItemsAdded,0,LocationStr);
			m_SearchResults.SetItemData(Index,m_SearchResult.size());
			m_SearchResult.push_back(Result);
			sprintf(LocationStr,"0x%08X",StartAddress);
			m_SearchResults.SetItemText(Index,1,LocationStr);
			sprintf(LocationStr,DisplayStr,NewValue);
			m_SearchResults.SetItemText(Index,2,LocationStr);
			sprintf(LocationStr,DisplayStr,OldValue);
			m_SearchResults.SetItemText(Index,3,LocationStr);
			StartAddress += MoveSize;
			Len -= MoveSize;
			ItemsAdded += 1;
			if (ItemsAdded >= MaxSearch)
			{
				break;
			}
		}
		::SetWindowText(GetDlgItem(IDC_BTN_SEARCH),"Search Results");
		::ShowWindow(GetDlgItem(IDC_RESET_BUTTON),SW_SHOW);
		::EnableWindow(GetDlgItem(IDC_RADIO_TEXT),false);
		::EnableWindow(GetDlgItem(IDC_RADIO_JAL),false);
	} else {
		int ItemCount = m_SearchResults.GetItemCount();
		for (int i = ItemCount - 1; i >= 0; i--)
		{
			int ItemId = m_SearchResults.GetItemData(i);
			SearchResultItem & Result = m_SearchResult[ItemId];
			
			bool UpdateResult = false;
			DWORD NewValue = 0;
			BOOL valid = false;

			switch (Size) {
			case _8Bit:
				{
					BYTE mem = 0;
					valid = g_MMU->LB_PAddr(Result.PAddr, mem);
					NewValue = mem;
				}
				break;
			case _16Bit:
				{
					WORD mem = 0;
					valid = g_MMU->LH_PAddr(Result.PAddr, mem);
					NewValue = mem;
				}
				break;
			case _32Bit:
				valid = g_MMU->LW_PAddr(Result.PAddr, NewValue);
				break;
			default:
				g_Notify->BreakPoint(__FILEW__,__LINE__);
			}

			switch (Option)
			{
			case SearchChangeState_Changed:
				if (Result.Value != NewValue)
				{
					UpdateResult = true;
				}
				break;
			case SearchChangeState_Unchanged:
				if (Result.Value == NewValue)
				{
					UpdateResult = true;
				}
				break;
			case SearchChangeState_Greater:
				if (NewValue > Result.Value)
				{
					UpdateResult = true;
				}
				break;
			case SearchChangeState_Lessthan:
				if (NewValue < Result.Value)
				{
					UpdateResult = true;
				}
				break;
			default:
				g_Notify->BreakPoint(__FILEW__,__LINE__);
			}

			if (UpdateResult)
			{
				char LocationStr[20];
				sprintf(LocationStr,DisplayStr,NewValue);
				m_SearchResults.SetItemText(i,2,LocationStr);
				sprintf(LocationStr,DisplayStr,Result.Value);
				m_SearchResults.SetItemText(i,3,LocationStr);
				Result.Value = NewValue;
			} else {
				m_SearchResults.DeleteItem(i);
			}
		}
	}
	::SetWindowText(GetDlgItem(IDC_BORDER_RESULTS),stdstr_f("Results (%d)",m_SearchResults.GetItemCount()).c_str());	
}

void CDebugMemorySearch::SearchForText()
{
	g_Notify->BreakPoint(__FILEW__,__LINE__);
}

void CDebugMemorySearch::Reset ( void )
{
	m_HaveResults = false;
	SendMessage(GetDlgItem(IDC_RADIO_VALUE),BM_SETCHECK, BST_CHECKED,0);
	EnableUnknownOptions(false);
	EnableValueOptions(true);
	EnableTextOptions(false);
	EnableJalOptions(false);
	::SetWindowText(GetDlgItem(IDC_BTN_SEARCH),"Search");
	::SetWindowText(GetDlgItem(IDC_BORDER_RESULTS),"Results");	
	::ShowWindow(GetDlgItem(IDC_RESET_BUTTON),SW_HIDE);
	::EnableWindow(GetDlgItem(IDC_RADIO_UNKNOWN),true);
	::EnableWindow(GetDlgItem(IDC_RADIO_VALUE),true);
	::EnableWindow(GetDlgItem(IDC_RADIO_TEXT),false);
	::EnableWindow(GetDlgItem(IDC_RADIO_JAL),false);
	for (int i = 1; i <  10; i++)
	{
		if (!m_SearchResults.DeleteColumn(i))
		{
			break;
		}
	}
	m_SearchResults.AddColumn("Value",2);
	m_SearchResults.DeleteAllItems();
	m_SearchResults.SetColumnWidth(0,50);
	m_SearchResults.SetColumnWidth(1,75);
	m_SearchResults.SetColumnWidth(2,75);
	m_SearchResults.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT);
	FixUnknownOptions(true);
}

void CDebugMemorySearch::FixUnknownOptions ( bool Reset )
{
	CComboBox & cb = m_UnknownOptions ;

	if (!Reset && cb.GetCount() > 1)
	{
		return;
	}
	cb.ResetContent();
	if (Reset)
	{
		cb.SetItemData(cb.AddString("Create compare base"),SearchChangeState_Reset);
		cb.SetCurSel(0);
		return;
	}
	cb.SetItemData(cb.AddString("memory changed"),SearchChangeState_Changed);
	cb.SetItemData(cb.AddString("memory unchanged"),SearchChangeState_Unchanged);
	cb.SetItemData(cb.AddString("Value has increased"),SearchChangeState_Greater);
	cb.SetItemData(cb.AddString("Value has descreased"),SearchChangeState_Lessthan);
	cb.SetCurSel(1);
	::SetWindowText(GetDlgItem(IDC_BTN_SEARCH),"Search");
}

bool CDebugMemorySearch::SearchSetBaseForChanges ( void )
{
	if (m_MemoryState != NULL)
	{
		delete [] m_MemoryState;
	}
	m_MemoryStateSize = g_MMU->RdramSize();
	m_MemoryState = new BYTE[m_MemoryStateSize];
	memcpy(m_MemoryState,g_MMU->Rdram(),m_MemoryStateSize);
	return true;
}

bool CDebugMemorySearch::SearchForChanges(SearchMemChangeState SearchType, MemorySize Size, 
								   DWORD &StartAddress, DWORD &Len, 
								   DWORD &OldValue,     DWORD &NewValue)
{
	if (g_MMU == NULL)
	{
		return false;
	}

	if (SearchType == SearchChangeState_Reset)
	{
		Notify().BreakPoint(__FILEW__,__LINE__);
	}
	if (Size == _32Bit) { StartAddress = ((StartAddress + 3) & ~3); }
	if (Size == _16Bit) { StartAddress = ((StartAddress + 1) & ~1); }

	//search memory
	if (StartAddress < g_MMU->RdramSize())
	{
		DWORD EndMemSearchAddr = StartAddress + Len;
		if (EndMemSearchAddr > g_MMU->RdramSize())
		{
			EndMemSearchAddr = g_MMU->RdramSize(); 
		}
		
		DWORD pos;
		switch (Size)
		{
		case _32Bit:
			for (pos  = StartAddress; pos < EndMemSearchAddr; pos += 4)
			{
				OldValue = *(DWORD *)(m_MemoryState + pos);
				NewValue = *(DWORD *)(g_MMU->Rdram() + pos);
				if ((SearchType == SearchChangeState_Changed && NewValue != OldValue) ||
					(SearchType == SearchChangeState_Unchanged && NewValue == OldValue) ||
					(SearchType == SearchChangeState_Greater && NewValue > OldValue) || 
					(SearchType == SearchChangeState_Lessthan && NewValue < OldValue))
				{
					*(DWORD *)(m_MemoryState + pos) = NewValue;
					Len -= pos - StartAddress;
					StartAddress = pos;
					return true;
				}
			}
			break;
		case _16Bit:
			for (pos = StartAddress; pos < EndMemSearchAddr; pos += 2)
			{
				OldValue = *(WORD *)(m_MemoryState + (pos ^ 2));
				NewValue = *(WORD *)(g_MMU->Rdram() + (pos ^ 2));
				if ((SearchType == SearchChangeState_Changed && NewValue != OldValue) ||
					(SearchType == SearchChangeState_Unchanged && NewValue == OldValue) ||
					(SearchType == SearchChangeState_Greater && NewValue > OldValue) || 
					(SearchType == SearchChangeState_Lessthan && NewValue < OldValue))
				{
					Len -= pos - StartAddress;
					StartAddress = pos;
					return true;
				}
			}
			break;
		case _8Bit:
			for (pos = StartAddress; pos < EndMemSearchAddr; pos ++)
			{
				OldValue = *(BYTE *)(m_MemoryState + (pos ^ 3));
				NewValue = *(BYTE *)(g_MMU->Rdram() + (pos ^ 3));
				if ((SearchType == SearchChangeState_Changed && NewValue != OldValue) ||
					(SearchType == SearchChangeState_Unchanged && NewValue == OldValue) ||
					(SearchType == SearchChangeState_Greater && NewValue > OldValue) || 
					(SearchType == SearchChangeState_Lessthan && NewValue < OldValue))
				{
					Len -= pos - StartAddress;
					StartAddress = pos;
					return true;
				}
			}
			break;
		default:
			g_Notify->BreakPoint(__FILEW__,__LINE__);
		}
	}
	return false;
}

bool CDebugMemorySearch::SearchForValue (DWORD Value, MemorySize Size, DWORD &StartAddress, DWORD &Len )
{
	if (g_MMU == NULL || g_Rom == NULL)
	{
		return false;
	}

	if (Size == _32Bit) { StartAddress = ((StartAddress + 3) & ~3); }
	if (Size == _16Bit) { StartAddress = ((StartAddress + 1) & ~1); }

	//search memory
	if (StartAddress < g_MMU->RdramSize())
	{
		DWORD EndMemSearchAddr = StartAddress + Len;
		if (EndMemSearchAddr > g_MMU->RdramSize())
		{
			EndMemSearchAddr = g_MMU->RdramSize(); 
		}
		
		DWORD pos;
		BYTE * RDRAM = g_MMU->Rdram();
		switch (Size)
		{
		case _32Bit:
			for (pos  = StartAddress; pos < EndMemSearchAddr; pos += 4)
			{
				if (*(DWORD *)(RDRAM + pos) == Value)
				{
					Len -= pos - StartAddress;
					StartAddress = pos;
					return true;
				}
			}
			break;
		case _16Bit:
			for (pos = StartAddress; pos < EndMemSearchAddr; pos += 2)
			{
				if (*(WORD *)(RDRAM + (pos ^ 2)) == (WORD)Value)
				{
					Len -= pos - StartAddress;
					StartAddress = pos;
					return true;
				}
			}
			break;
		case _8Bit:
			for (pos = StartAddress; pos < EndMemSearchAddr; pos ++)
			{
				if (*(BYTE *)(RDRAM + (pos ^ 3)) == (BYTE)Value)
				{
					Len -= pos - StartAddress;
					StartAddress = pos;
					return true;
				}
			}
			break;
		default:
			g_Notify->BreakPoint(__FILEW__,__LINE__);
		}
	}
	if (StartAddress >= 0x10000000)
	{
		DWORD EndMemSearchAddr = StartAddress + Len - 0x10000000;
		if (EndMemSearchAddr > g_Rom->GetRomSize())
		{
			EndMemSearchAddr = g_Rom->GetRomSize(); 
		}
		StartAddress -= 0x10000000;
		
		DWORD pos;
		BYTE * ROM = g_Rom->GetRomAddress();
		switch (Size)
		{
		case _32Bit:
			for (pos  = StartAddress; pos < EndMemSearchAddr; pos += 4)
			{
				if (*(DWORD *)(ROM + pos) == Value)
				{
					Len -= pos - StartAddress;
					StartAddress = pos + 0x10000000;
					return true;
				}
			}
			break;
		case _16Bit:
			for (pos = StartAddress; pos < EndMemSearchAddr; pos += 2)
			{
				if (*(WORD *)(ROM + (pos ^ 2)) == (WORD)Value)
				{
					Len -= pos - StartAddress;
					StartAddress = pos + 0x10000000;
					return true;
				}
			}
			break;
		case _8Bit:
			for (pos = StartAddress; pos < EndMemSearchAddr; pos ++)
			{
				if (*(BYTE *)(ROM + (pos ^ 3)) == (BYTE)Value)
				{
					Len -= pos - StartAddress;
					StartAddress = pos + 0x10000000;
					return true;
				}
			}
			break;
		default:
			g_Notify->BreakPoint(__FILEW__,__LINE__);
		}
	}
	return false;
}

