#include "stdafx.h"
#include "XUI_Ctrl_4JList.h"

static bool TimeSortFn(const void *a, const void *b);

HRESULT CXuiCtrl4JList::OnInit(XUIMessageInit *pInitData, BOOL& bHandled)
{
	InitializeCriticalSection(&m_AccessListData);

	m_hSelectionChangedHandlerObj = NULL;

	return S_OK;
}

void CXuiCtrl4JList::AddData( const LIST_ITEM_INFO& ItemInfo , int iSortListFromIndex, int iSortFunction)
{
	// need to allocate memory for the structure and its strings
	// and remap the string pointers	
	DWORD dwBytes=0;
	DWORD dwLen1=0;
	DWORD dwLen2=0;

	if(ItemInfo.pwszText)
	{
		dwLen1=(int)wcslen(ItemInfo.pwszText)*sizeof(WCHAR);
		dwBytes+=dwLen1+sizeof(WCHAR);
	}

	if(ItemInfo.pwszImage)
	{
		dwLen2=(int)(wcslen(ItemInfo.pwszImage))*sizeof(WCHAR);
		dwBytes+=dwLen2+sizeof(WCHAR);
	}

	dwBytes+=sizeof( LIST_ITEM_INFO );
	LIST_ITEM_INFO *pItemInfo = (LIST_ITEM_INFO *)new BYTE[dwBytes];
	ZeroMemory(pItemInfo,dwBytes);

	XMemCpy( pItemInfo, &ItemInfo, sizeof( LIST_ITEM_INFO ) );
	if(dwLen1!=0) 
	{
		XMemCpy( &pItemInfo[1], ItemInfo.pwszText, dwLen1 );
		pItemInfo->pwszText=(LPCWSTR)&pItemInfo[1];
		if(dwLen2!=0)
		{
			BYTE *pwszImage = ((BYTE *)&pItemInfo[1])+dwLen1+sizeof(WCHAR);
			XMemCpy( pwszImage, ItemInfo.pwszImage, dwLen2 );
			pItemInfo->pwszImage=(LPCWSTR)pwszImage;
		}
	}
	else if(dwLen2!=0)
	{
		XMemCpy( &pItemInfo[1], ItemInfo.pwszImage, dwLen2 );
		pItemInfo->pwszImage=(LPCWSTR)&pItemInfo[1];
	}

	EnterCriticalSection(&m_AccessListData);

	// need to remember the original index of this addition before it gets sorted - this will get used to load the game
	if(iSortListFromIndex!=-1)
	{
		pItemInfo->iIndex=(int)m_vListData.size()-iSortListFromIndex;
	}
	else
	{
		pItemInfo->iIndex=(int)m_vListData.size();
	}

	// added to force a sort order for DLC
	//pItemInfo->iSortIndex=iSortIndex;
	
	m_vListData.push_back(pItemInfo);

#ifdef _DEBUG

	int iCount=0;
	for (AUTO_VAR(it, m_vListData.begin()); it != m_vListData.end(); it++)
	{
		PLIST_ITEM_INFO pInfo=(PLIST_ITEM_INFO)*it;
		app.DebugPrintf("%d. ",iCount++);
		OutputDebugStringW(pInfo->pwszText);
		app.DebugPrintf(" - %d\n",pInfo->iSortIndex);

	}
#endif


	if(iSortListFromIndex!=-1)
	{
		switch(iSortFunction)
		{
		case eSortList_Date:
			// sort from the index passed (to leave create world and tutorial in the saves list)
			sort(m_vListData.begin()+iSortListFromIndex, m_vListData.end(),CXuiCtrl4JList::TimeSortFn);
			break;
		case eSortList_Alphabetical:
			// alphabetical sort
			sort(m_vListData.begin()+iSortListFromIndex, m_vListData.end(),CXuiCtrl4JList::AlphabeticSortFn);
			break;
		case eSortList_Index:
			sort(m_vListData.begin()+iSortListFromIndex, m_vListData.end(),CXuiCtrl4JList::IndexSortFn);
			break;		
		}
	}
	LeaveCriticalSection(&m_AccessListData);
// #ifdef _DEBUG
// 
// 	iCount=0;
// 	for (AUTO_VAR(it, m_vListData.begin()); it != m_vListData.end(); it++)
// 	{
// 		PLIST_ITEM_INFO pInfo=(PLIST_ITEM_INFO)*it;
// 		app.DebugPrintf("After Sort - %d. ",iCount++);
// 		OutputDebugStringW(pInfo->pwszText);
// 		app.DebugPrintf(" - %d\n",pInfo->iSortIndex);
// 
// 	}
// #endif
	InsertItems( 0, 1 );
}

void CXuiCtrl4JList::RemoveAllData( )
{
	EnterCriticalSection(&m_AccessListData);

	int iSize=(int)m_vListData.size();
	for(int i=0;i<iSize;i++)
	{
		LIST_ITEM_INFO *pBack = m_vListData.back();
		if( pBack->hXuiBrush )
		{
			XuiDestroyBrush(pBack->hXuiBrush);
		}
		m_vListData.pop_back();
		DeleteItems( 0, 1 );
	}

	LeaveCriticalSection(&m_AccessListData);
}

void CXuiCtrl4JList::SelectByUserData(int iData)
{
	for(unsigned int i = 0; i < m_vListData.size(); ++i)
	{
		if(m_vListData.at(i)->iData == iData)
		{
			SetCurSel(i);
			SetTopItem(i); // scroll the item into view if it's not visible
			break;
		}
	}
}

int CXuiCtrl4JList::GetIndexByUserData(int iData)
{
	for(unsigned int i = 0; i < m_vListData.size(); ++i)
	{
		if(m_vListData.at(i)->iData == iData)
		{
			return i;
		}
	}
	return 0;
}

CXuiCtrl4JList::LIST_ITEM_INFO&	CXuiCtrl4JList::GetData(DWORD dw) 
{ 
	return *m_vListData[dw]; 
}

CXuiCtrl4JList::LIST_ITEM_INFO&	CXuiCtrl4JList::GetDataiData(int iData) 
{ 
	LIST_ITEM_INFO info;

	for(unsigned int i=0;i<m_vListData.size();i++)
	{
		info=*m_vListData[i];
		if(info.iData==iData)
		{
			return *m_vListData[i];
		}
	}

	return *m_vListData[0]; 
}

CXuiCtrl4JList::LIST_ITEM_INFO&	CXuiCtrl4JList::GetData(FILETIME *pFileTime) 
{ 
	LIST_ITEM_INFO info;

	for(unsigned int i=0;i<m_vListData.size();i++)
	{
		info=*m_vListData[i];
		if((info.fTime.dwHighDateTime==pFileTime->dwHighDateTime)&&(info.fTime.dwLowDateTime==pFileTime->dwLowDateTime))
		{
			return *m_vListData[i];
		}
	}

	return *m_vListData[0]; 
}

bool CXuiCtrl4JList::TimeSortFn(const void *a, const void *b)
{
	CXuiCtrl4JList::LIST_ITEM_INFO *SaveDetailsA=(CXuiCtrl4JList::LIST_ITEM_INFO *)a;
	CXuiCtrl4JList::LIST_ITEM_INFO *SaveDetailsB=(CXuiCtrl4JList::LIST_ITEM_INFO *)b; 

	if(SaveDetailsA->fTime.dwHighDateTime > SaveDetailsB->fTime.dwHighDateTime)
	{
		return true;
	}
	else if(SaveDetailsA->fTime.dwHighDateTime == SaveDetailsB->fTime.dwHighDateTime)
	{
		if(SaveDetailsA->fTime.dwLowDateTime > SaveDetailsB->fTime.dwLowDateTime)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	else
	{
		return false;
	}

}

bool CXuiCtrl4JList::AlphabeticSortFn(const void *a, const void *b)
{
	CXuiCtrl4JList::LIST_ITEM_INFO *SaveDetailsA=(CXuiCtrl4JList::LIST_ITEM_INFO *)a;
	CXuiCtrl4JList::LIST_ITEM_INFO *SaveDetailsB=(CXuiCtrl4JList::LIST_ITEM_INFO *)b; 

	wstring wstr1=SaveDetailsA->pwszText;
	wstring wstr2=SaveDetailsB->pwszText;
	if(wstr1.compare(wstr2)<0)
	{
		return true;
	}	

	return false;
}

bool CXuiCtrl4JList::IndexSortFn(const void *a, const void *b)
{
	CXuiCtrl4JList::LIST_ITEM_INFO *SaveDetailsA=(CXuiCtrl4JList::LIST_ITEM_INFO *)a;
	CXuiCtrl4JList::LIST_ITEM_INFO *SaveDetailsB=(CXuiCtrl4JList::LIST_ITEM_INFO *)b; 

	int iA=SaveDetailsA->iSortIndex;
	int iB=SaveDetailsB->iSortIndex;
	if(iA>iB)
	{
		return true;
	}	

	return false;
}

void CXuiCtrl4JList::UpdateGraphic(int iItem,HXUIBRUSH hXuiBrush )
{
	// need to update the one with the matching filetime
	EnterCriticalSection(&m_AccessListData);
	if( GetData(iItem).hXuiBrush )
	{
		XuiDestroyBrush( GetData(iItem).hXuiBrush );
	}
	GetData(iItem).hXuiBrush=hXuiBrush;
	LeaveCriticalSection(&m_AccessListData);
}

void CXuiCtrl4JList::UpdateText(int iItem,LPCWSTR pwszText )
{
	// need to update the one with the matching filetime
	EnterCriticalSection(&m_AccessListData);
	GetData(iItem).pwszText=pwszText;
	LeaveCriticalSection(&m_AccessListData);
}

void CXuiCtrl4JList::UpdateGraphicFromiData(int iData,HXUIBRUSH hXuiBrush )
{
	// need to update the one with the matching iData
	EnterCriticalSection(&m_AccessListData);
	if( GetDataiData(iData).hXuiBrush )
	{
		XuiDestroyBrush( GetDataiData(iData).hXuiBrush );
	}
	GetDataiData(iData).hXuiBrush=hXuiBrush;
	LeaveCriticalSection(&m_AccessListData);
}

void CXuiCtrl4JList::UpdateGraphic(FILETIME *pfTime,HXUIBRUSH hXuiBrush )
{
	// need to update the one with the matching filetime
	EnterCriticalSection(&m_AccessListData);
	if( GetData(pfTime).hXuiBrush )
	{
		XuiDestroyBrush( GetData(pfTime).hXuiBrush );
	}
	GetData(pfTime).hXuiBrush=hXuiBrush;
	LeaveCriticalSection(&m_AccessListData);
}

// Gets called every frame
HRESULT CXuiCtrl4JList::OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData,BOOL& bHandled)
{
	if( ( 0 == pGetSourceTextData->iData ) && ( ( pGetSourceTextData->bItemData ) ) ) 
	{
		EnterCriticalSection(&m_AccessListData);
		pGetSourceTextData->szText = 
			GetData(pGetSourceTextData->iItem).pwszText;
		LeaveCriticalSection(&m_AccessListData);
		bHandled = TRUE;
	}
	return S_OK;
}

HRESULT CXuiCtrl4JList::OnGetItemCountAll(XUIMessageGetItemCount *pGetItemCountData,BOOL& bHandled)
{
	pGetItemCountData->cItems = (int)m_vListData.size();
	bHandled = TRUE;
	return S_OK;
}

HRESULT CXuiCtrl4JList::OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled)
{
	if( ( 0 == pGetSourceImageData->iData ) && ( pGetSourceImageData->bItemData ) ) 
	{
		// Check for a brush
		EnterCriticalSection(&m_AccessListData);
		if(GetData(pGetSourceImageData->iItem).hXuiBrush!=NULL)
		{
			pGetSourceImageData->hBrush=GetData(pGetSourceImageData->iItem).hXuiBrush;
		}
		else
		{
			pGetSourceImageData->szPath = 
				GetData(pGetSourceImageData->iItem).pwszImage;
		}
		LeaveCriticalSection(&m_AccessListData);
		bHandled = TRUE;
	}
	return S_OK;
}

HRESULT CXuiCtrl4JList::OnGetItemEnable(XUIMessageGetItemEnable *pGetItemEnableData,BOOL& bHandled)
{
	if(m_vListData.size()!=0)
	{
		EnterCriticalSection(&m_AccessListData);
		pGetItemEnableData->bEnabled = 
			GetData(pGetItemEnableData->iItem).fEnabled;
		LeaveCriticalSection(&m_AccessListData);
	}
	bHandled = TRUE;
	return S_OK;
}


HRESULT CXuiCtrl4JList::SetBorder(DWORD dw,BOOL bShow) 
{ 
	CXuiControl Control;
	HXUIOBJ hVisual,hBorder;
	GetItemControl(dw,&Control);
	Control.GetVisual(&hVisual);
	XuiElementGetChildById(hVisual,L"Border",&hBorder);
	return XuiElementSetShow(hBorder,bShow);	
}

void CXuiCtrl4JList::SetSelectionChangedHandle(HXUIOBJ hObj)
{
	m_hSelectionChangedHandlerObj = hObj;
}

HRESULT CXuiCtrl4JList::OnDestroy()
{
	DeleteCriticalSection(&m_AccessListData);

	if(m_vListData.size()!=0)
	{
		for (unsigned i = 0; i < m_vListData.size(); ++i)
		{
			if( m_vListData[i]->hXuiBrush )
			{
				XuiDestroyBrush( m_vListData[i]->hXuiBrush );
			}
			delete [] (BYTE *)m_vListData[i];
		}
	}
	return S_OK;
}

HRESULT CXuiCtrl4JList::OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled )
{
	if(m_hSelectionChangedHandlerObj)
	{
		XUIMessage xuiMsg;
		XUINotify xuiNotify;
		XUINotifySelChanged xuiNotifySel;
		XuiNotifySelChanged( &xuiMsg, &xuiNotify, &xuiNotifySel, hObjSource, pNotifySelChangedData->iItem, pNotifySelChangedData->iOldItem );
		XuiSendMessage( m_hSelectionChangedHandlerObj, &xuiMsg );

		bHandled = xuiMsg.bHandled;
	}
	return S_OK;
}