#include "stdafx.h"
#include <xuiresource.h>
#include <xuiapp.h>
#include <assert.h>

#include "..\..\..\Minecraft.World\Player.h"
#include "..\..\..\Minecraft.Client\LocalPlayer.h"
#include "..\..\..\Minecraft.Client\Minecraft.h"
#include "..\..\..\Minecraft.Client\GameMode.h"
#include "..\..\..\Minecraft.World\AbstractContainerMenu.h"
#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h"
#include "..\..\..\Minecraft.World\net.minecraft.world.item.h"
#include "..\..\..\Minecraft.World\Tile.h"
#include "..\..\..\Minecraft.World\FurnaceRecipes.h"
#include "..\..\..\Minecraft.World\Recipy.h"
#include "..\..\..\Minecraft.World\Recipes.h"
#include "..\..\..\Minecraft.World\ArmorRecipes.h"
#include "..\..\..\Minecraft.World\StringHelpers.h"

#include "..\..\Common\Tutorial\Tutorial.h"
#include "..\..\Common\Tutorial\TutorialMode.h"

#include "XUI_Ctrl_SlotList.h"
#include "XUI_Ctrl_SlotItem.h"
#include "XUI_Ctrl_SlotItemListItem.h"
#include "XUI_Scene_AbstractContainer.h"
#ifdef _DEBUG_MENUS_ENABLED	
#include "XUI_DebugItemEditor.h"
#endif

#define IGNORE_KEYPRESS_TIMERID 11
#define IGNORE_KEYPRESS_TIME 100

void CXuiSceneAbstractContainer::PlatformInitialize(int iPad, int startIndex)
{
	m_bIgnoreKeyPresses=true;
	m_iPad = iPad;

	XuiControlSetText(m_InventoryText,app.GetString(IDS_INVENTORY));

		// Determine min and max extents for pointer, it needs to be able to move off the container to drop items.
	float fPanelWidth, fPanelHeight;
	float fPointerWidth, fPointerHeight;

	// We may have varying depths of controls here, so base off the pointers parent
	HXUIOBJ parent;
	XuiElementGetBounds( m_pointerControl->m_hObj, &fPointerWidth, &fPointerHeight );	
	XuiElementGetParent( m_pointerControl->m_hObj, &parent );
	m_pointerControl->SetShow(TRUE);
	XuiElementGetBounds( parent, &fPanelWidth, &fPanelHeight );	
	// Get size of pointer
	m_fPointerImageOffsetX = floor(fPointerWidth/2.0f);
	m_fPointerImageOffsetY = floor(fPointerHeight/2.0f);
	
	m_fPanelMinX = 0.0f;
	m_fPanelMaxX = fPanelWidth;
	m_fPanelMinY = 0.0f;
	m_fPanelMaxY = fPanelHeight;

	// 4J-PB - need to limit this in splitscreen
	if(app.GetLocalPlayerCount()>1)
	{
		// don't let the pointer go into someone's screen
		m_fPointerMinY = floor(fPointerHeight/2.0f);
	}
	else
	{
		m_fPointerMinY = -fPointerHeight;
	}
	m_fPointerMinX = -fPointerWidth;
	m_fPointerMaxX = fPanelWidth + fPointerWidth;
	m_fPointerMaxY = fPanelHeight + (fPointerHeight/2);

// 	m_hPointerText=NULL;
// 	m_hPointerTextBkg=NULL;

	UIVec2D itemPos;
	UIVec2D itemSize;
	GetItemScreenData( m_eCurrSection, 0, &( itemPos ), &( itemSize ) );

	UIVec2D sectionPos;
	GetPositionOfSection( m_eCurrSection, &( sectionPos ) );

	UIVec2D vPointerPos = sectionPos;
	vPointerPos += itemPos;
	vPointerPos.x += ( itemSize.x / 2.0f );
	vPointerPos.y += ( itemSize.y / 2.0f );

	vPointerPos.x -= m_fPointerImageOffsetX;
	vPointerPos.y -= m_fPointerImageOffsetY;

	D3DXVECTOR3 newPointerPos;
	newPointerPos.x = vPointerPos.x;
	newPointerPos.y = vPointerPos.y;
	newPointerPos.z = 0.0f;
	m_pointerControl->SetPosition( &newPointerPos );
	m_pointerPos.x = newPointerPos.x;
	m_pointerPos.y = newPointerPos.y;

#ifdef USE_POINTER_ACCEL	
	m_fPointerVelX = 0.0f;
	m_fPointerVelY = 0.0f;
	m_fPointerAccelX = 0.0f;
	m_fPointerAccelY = 0.0f;
#endif
	
	// Add timer to poll controller stick input at 60Hz
	HRESULT timerResult = SetTimer( POINTER_INPUT_TIMER_ID, ( 1000 / 60 ) );
	assert( timerResult == S_OK );

	XuiSetTimer(m_hObj,IGNORE_KEYPRESS_TIMERID,IGNORE_KEYPRESS_TIME);

	// Disable the default navigation behaviour for all slot lsit items (prevent old style cursor navigation).
	for ( int iSection = m_eFirstSection; iSection < m_eMaxSection; ++iSection )
	{
		ESceneSection eSection = ( ESceneSection )( iSection );
		
		if(!IsSectionSlotList(eSection)) continue;

		// Get dimensions of this section.
		int iNumRows;
		int iNumColumns;
		int iNumItems = GetSectionDimensions( eSection, &( iNumColumns ), &( iNumRows ) );

		for ( int iItem = 0; iItem < iNumItems; ++iItem )
		{
			CXuiCtrlSlotItemListItem* pCXuiCtrlSlotItem;
			GetSectionSlotList( eSection )->GetCXuiCtrlSlotItem( iItem, &( pCXuiCtrlSlotItem ) );
			pCXuiCtrlSlotItem->SetSkipsDefaultNavigation( TRUE );
		}
	}
}

// 4J Stu - Added to support auto-save. Need to re-associate on a navigate back
void CXuiSceneAbstractContainer::InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex /*= 0*/)
{
	// TODO Inventory dimensions need defined as constants
	m_inventoryControl->SetData( iPad, menu, 3, 9, startIndex, startIndex + 3*9 );

	// TODO Inventory dimensions need defined as constants
	m_useRowControl->SetData( iPad, menu, 1, 9, startIndex + 3*9, startIndex + 4*9 );

	m_pointerControl->SetUserIndex(m_pointerControl->m_hObj, iPad);
}

int CXuiSceneAbstractContainer::getSectionColumns(ESceneSection eSection)
{
	return GetSectionSlotList( eSection )->GetColumns();
}

int CXuiSceneAbstractContainer::getSectionRows(ESceneSection eSection)
{
	return GetSectionSlotList( eSection )->GetRows();
}

// Adding this so we can turn off the pointer text background, since it flickers on then off at the start of a scene where a tutorial popup is 
HRESULT CXuiSceneAbstractContainer::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled )
{
	if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK;

	if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO)
	{
		// 4J Stu - Added to support auto-save. Need to re-associate on a navigate back
		if(pTransition->dwTransType == XUI_TRANSITION_BACKTO)
		{
			// Add timer to poll controller stick input at 60Hz
			HRESULT timerResult = SetTimer( POINTER_INPUT_TIMER_ID, ( 1000 / 60 ) );
			assert( timerResult == S_OK );

			InitDataAssociations(m_iPad, m_menu);
		}

		HXUIOBJ hObj=NULL;
		HRESULT hr=XuiControlGetVisual(m_pointerControl->m_hObj,&hObj);
		hr=XuiElementGetChildById(hObj,L"text_measurer",&m_hPointerTextMeasurer);
		hr=XuiElementGetChildById(hObj,L"text_name",&m_hPointerText);
		hr=XuiElementGetChildById(hObj,L"text_panel",&m_hPointerTextBkg);
		hr=XuiElementGetChildById(hObj,L"pointer_image",&m_hPointerImg);
		XuiElementSetShow(m_hPointerText,FALSE);
		XuiElementSetShow(m_hPointerTextBkg,FALSE);
	}

	return S_OK;
}


D3DXVECTOR3 CXuiSceneAbstractContainer::GetCursorScreenPosition()
{
	return app.GetElementScreenPosition(m_pointerControl->m_hObj);
}

HRESULT CXuiSceneAbstractContainer::OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled)
{
	if(m_bIgnoreKeyPresses) return S_OK;

	bHandled = handleKeyDown(pInputData->UserIndex, mapVKToAction(pInputData->dwKeyCode), (pInputData->dwFlags & XUI_INPUT_FLAG_REPEAT) != 0);

	return S_OK;
}

int CXuiSceneAbstractContainer::mapVKToAction(int vk)
{
	int action = MINECRAFT_ACTION_MAX;
	switch(vk)
	{
	case VK_PAD_A:
		action = ACTION_MENU_A;
		break;
	case VK_PAD_B:
	case VK_PAD_START:
		action = ACTION_MENU_B;
		break;
	case VK_PAD_X:
		action = ACTION_MENU_X;
		break;
	case VK_PAD_Y:
		action = ACTION_MENU_Y;
		break;
	case VK_PAD_DPAD_LEFT:
		action = ACTION_MENU_LEFT;
		break;
	case VK_PAD_DPAD_RIGHT:
		action = ACTION_MENU_RIGHT;
		break;
	case VK_PAD_DPAD_UP:
		action = ACTION_MENU_UP;
		break;
	case VK_PAD_DPAD_DOWN:
		action = ACTION_MENU_DOWN;
		break;
	case VK_PAD_LTRIGGER:
		action = ACTION_MENU_PAGEUP;
		break;
	case VK_PAD_RTRIGGER:
		action = ACTION_MENU_PAGEDOWN;
		break;
	case VK_PAD_LSHOULDER:
		action = ACTION_MENU_LEFT_SCROLL;
		break;
	case VK_PAD_RSHOULDER:
		action = ACTION_MENU_RIGHT_SCROLL;
		break;
	case VK_PAD_RTHUMB_UP:
		action =  ACTION_MENU_OTHER_STICK_UP;
		break;
	case VK_PAD_RTHUMB_DOWN:
		action =  ACTION_MENU_OTHER_STICK_DOWN;
		break;
	case VK_PAD_RTHUMB_RIGHT:
		action =  ACTION_MENU_OTHER_STICK_RIGHT;
		break;
	case VK_PAD_RTHUMB_LEFT:
		action =  ACTION_MENU_OTHER_STICK_LEFT;
		break;
	};

	return action;
}

void CXuiSceneAbstractContainer::handleSectionClick(ESceneSection eSection)
{
	CXuiCtrlSlotList *slotList = GetSectionSlotList( eSection );
	slotList->Clicked();
}

HRESULT CXuiSceneAbstractContainer::handleCustomTimer( XUIMessageTimer *pTimer, BOOL& bHandled )
{
	return S_OK;
}

// Returns XUI position of given scene section.
void CXuiSceneAbstractContainer::GetPositionOfSection( ESceneSection eSection, UIVec2D* pPosition )
{
	D3DXVECTOR3 xuiPos;
	GetSectionControl( eSection )->GetPosition( &xuiPos );
	pPosition->x = xuiPos.x;
	pPosition->y = xuiPos.y;
}

void CXuiSceneAbstractContainer::GetItemScreenData( ESceneSection eSection, int iItemIndex, UIVec2D* pPosition, UIVec2D* pSize )
{
	D3DXVECTOR3 xuiPos;
	if(IsSectionSlotList(eSection))
	{
		// Get slot item.
		CXuiCtrlSlotItemListItem* pCXuiCtrlSlotItem;
		GetSectionSlotList( eSection )->GetCXuiCtrlSlotItem( iItemIndex, &( pCXuiCtrlSlotItem ) );

		// Get size of slot.
		pCXuiCtrlSlotItem->GetBounds( &( pSize->x ), &( pSize->y ) );

		// Get position of slot.
		pCXuiCtrlSlotItem->GetPosition( &xuiPos );
		pPosition->x = xuiPos.x;
		pPosition->y = xuiPos.y;
	}
	else
	{
		// Get size of control
		GetSectionControl( eSection )->GetBounds( &( pSize->x ), &( pSize->y ) );

		// Get position of control
		GetSectionControl( eSection )->GetPosition( &xuiPos );
		pPosition->x = xuiPos.x;
		pPosition->y = xuiPos.y;
	}
}

shared_ptr<ItemInstance> CXuiSceneAbstractContainer::getSlotItem(ESceneSection eSection, int iSlot)
{
	CXuiCtrlSlotItemListItem* pCXuiCtrlSlotItem;
	GetSectionSlotList( eSection )->GetCXuiCtrlSlotItem( iSlot, &( pCXuiCtrlSlotItem ) );
	return pCXuiCtrlSlotItem->getItemInstance( pCXuiCtrlSlotItem->m_hObj );
}

bool CXuiSceneAbstractContainer::isSlotEmpty(ESceneSection eSection, int iSlot)
{
	CXuiCtrlSlotItemListItem* pCXuiCtrlSlotItem;
	GetSectionSlotList( eSection )->GetCXuiCtrlSlotItem( iSlot, &( pCXuiCtrlSlotItem ) );
	return pCXuiCtrlSlotItem->isEmpty( pCXuiCtrlSlotItem->m_hObj );
}

HRESULT CXuiSceneAbstractContainer::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled )
{
	HRESULT hr = S_OK;

	// Update pointer from stick input on timer.
	if ( pTimer->nId == POINTER_INPUT_TIMER_ID )
    {
		
		onMouseTick();
		D3DXVECTOR3 pointerPos;
		pointerPos.x = m_pointerPos.x;
		pointerPos.y = m_pointerPos.y;
		pointerPos.z = 0.0f;
		m_pointerControl->SetPosition( &pointerPos );
		// This message has been dealt with, don't pass it on further.
		bHandled = TRUE;
	}
	else if ( pTimer->nId == IGNORE_KEYPRESS_TIMERID)
	{
		KillTimer(IGNORE_KEYPRESS_TIMERID);
		m_bIgnoreKeyPresses=false;
	}
	else
	{
		// Some scenes may have their own timers for other events, so handle them here
		hr = handleCustomTimer( pTimer, bHandled );
	}
	return hr;
}		

HRESULT CXuiSceneAbstractContainer::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled)
{
	bHandled=true;
	return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining);
}

bool CXuiSceneAbstractContainer::doesSectionTreeHaveFocus(ESceneSection eSection)
{
	return GetSectionControl( eSection )->TreeHasFocus();
}

void CXuiSceneAbstractContainer::setSectionFocus(ESceneSection eSection, int iPad)
{
	HRESULT focusResult = GetSectionControl( eSection )->SetFocus( iPad );
	assert( focusResult == S_OK );
}

void CXuiSceneAbstractContainer::setSectionSelectedSlot(ESceneSection eSection, int x, int y)
{
	GetSectionSlotList( eSection )->SetCurrentSlot(y,x);
}

void CXuiSceneAbstractContainer::setFocusToPointer(int iPad)
{
	m_pointerControl->SetFocus( iPad );
}

void CXuiSceneAbstractContainer::SetPointerText(const wstring &description, vector<wstring> &unformattedStrings, bool newSlot)
{
	if(description.empty())
	{
		m_pointerControl->SetText(L"");
		XuiElementSetShow(m_hPointerText,FALSE);
		XuiElementSetShow(m_hPointerTextBkg,FALSE);
		return;
	}

	bool smallPointer = m_bSplitscreen || (!RenderManager.IsHiDef() && !RenderManager.IsWidescreen());
	wstring desc = L"<font size=\"" + _toString<int>(smallPointer ? 12 :14) + L"\">" + description + L"</font>";

	XUIRect tempXuiRect, xuiRect;
	HRESULT hr;
	xuiRect.right = 0;

	for(AUTO_VAR(it, unformattedStrings.begin()); it != unformattedStrings.end(); ++it)
	{
		XuiTextPresenterMeasureText(m_hPointerTextMeasurer, parseXMLSpecials((*it)).c_str(), &tempXuiRect);
		if(tempXuiRect.right > xuiRect.right) xuiRect = tempXuiRect;
	}

	// Set size with the new width so that the HTML height check is correct
	XuiElementSetBounds(m_hPointerTextBkg,xuiRect.right+4.0f+4.0f+4.0f,xuiRect.bottom); // edge graphics are 8 pixels, with 4 for the border, extra 4 for the background is fudge
	XuiElementSetBounds(m_hPointerText,xuiRect.right+4.0f+4.0f,xuiRect.bottom); // edge graphics are 8 pixels, text is centred

	XuiHtmlSetText(m_hPointerText, desc.c_str() );

	// Check if we need to resize the box
	XUIContentDims contentDims;
	XuiHtmlGetContentDims(m_hPointerText,&contentDims);
	xuiRect.bottom = contentDims.nContentHeight;

	// get the size of the button, and apply the change in size due to the text to the whole button
	float fImgWidth,fImgHeight;
	XuiElementGetBounds(m_hPointerImg,&fImgWidth, &fImgHeight);
	// 4J-PB - changing to calculate values
	D3DXVECTOR3 vPosText, vPosTextBkg,vPosImg;

	XuiElementGetPosition(m_hPointerImg,&vPosImg);
	XuiElementGetPosition(m_hPointerText,&vPosText);
	XuiElementGetPosition(m_hPointerTextBkg,&vPosTextBkg);

	// Set the new height
	XuiElementSetBounds(m_hPointerTextBkg,xuiRect.right+4.0f+4.0f+4.0f,xuiRect.bottom+4.0f+4.0f); // edge graphics are 8 pixels, with 4 for the border, extra 4 for the background is fudge
	XuiElementSetBounds(m_hPointerText,xuiRect.right+4.0f+4.0f,xuiRect.bottom+4.0f+4.0f); // edge graphics are 8 pixels, text is centred

	// position the text and panel relative to the pointer image
	vPosTextBkg.x=vPosImg.x+fImgWidth*0.6f;
	vPosText.x=vPosTextBkg.x + 4;
	vPosTextBkg.y=vPosImg.y-(xuiRect.bottom+4.0f+4.0f)+fImgWidth*0.4f;
	vPosText.y=vPosTextBkg.y + 4;

	XuiElementSetPosition(m_hPointerText,&vPosText);
	XuiElementSetPosition(m_hPointerTextBkg,&vPosTextBkg);

	XuiElementSetShow(m_hPointerTextBkg,TRUE);
	XuiElementSetShow(m_hPointerText,TRUE);
}

void CXuiSceneAbstractContainer::adjustPointerForSafeZone()
{
	D3DXVECTOR2 baseSceneOrigin;
	float baseWidth, baseHeight;
	if(CXuiSceneBase::GetBaseSceneSafeZone( m_iPad, baseSceneOrigin, baseWidth, baseHeight))
	{			
		D3DXMATRIX pointerBackgroundMatrix;
		XuiElementGetFullXForm( m_hPointerTextBkg, &pointerBackgroundMatrix);

		float width, height;
		XuiElementGetBounds( m_hPointerTextBkg, &width, &height );

		if( ( (pointerBackgroundMatrix._41 / pointerBackgroundMatrix._11) + width) > (baseSceneOrigin.x + baseWidth) )
		{
			//app.DebugPrintf("Pointer is outside the safe zone for this base scene\n");

			// get the size of the button, and apply the change in size due to the text to the whole button
			float fImgWidth,fImgHeight;
			XuiElementGetBounds(m_hPointerImg,&fImgWidth, &fImgHeight);
			// 4J-PB - changing to calculate values
			D3DXVECTOR3 vPosText, vPosTextBkg,vPosImg;

			XuiElementGetPosition(m_hPointerImg,&vPosImg);
			XuiElementGetPosition(m_hPointerText,&vPosText);
			XuiElementGetPosition(m_hPointerTextBkg,&vPosTextBkg);

			// position the text and panel relative to the pointer image
			vPosTextBkg.x= (vPosImg.x+fImgWidth*0.4f) - width;
			vPosText.x=vPosTextBkg.x + 4;

			XuiElementSetPosition(m_hPointerText,&vPosText);
			XuiElementSetPosition(m_hPointerTextBkg,&vPosTextBkg);
		}
	}
}