
// LuaChunkStay.cpp

// Implements the cLuaChunkStay class representing a cChunkStay binding for plugins, used by cWorld:ChunkStay() Lua API

#include "Globals.h"
#include "LuaChunkStay.h"
#include "PluginLua.h"





cLuaChunkStay::cLuaChunkStay()
{
}





bool cLuaChunkStay::AddChunks(const cLuaState::cStackTable & a_ChunkCoordsTable)
{
	// This function is expected to be called just once, with all the coords in a table
	ASSERT(m_Chunks.empty());

	// Add each set of coords:
	a_ChunkCoordsTable.ForEachArrayElement([=](cLuaState & a_LuaState, int a_Index)
		{
			if (!lua_istable(a_LuaState, -1))
			{
				LOGWARNING("%s: Element #%d is not a table (got %s). Ignoring the element.",
					__FUNCTION__, a_Index, lua_typename(a_LuaState, -1)
				);
				a_LuaState.LogStackTrace();
				lua_pop(a_LuaState, 1);
				return false;
			}
			AddChunkCoord(a_LuaState, a_Index);
			return false;
		}
	);

	// If there are no chunks, log a warning and return failure:
	if (m_Chunks.empty())
	{
		LOGWARNING("%s: No valid chunk coords.", __FUNCTION__);
		a_ChunkCoordsTable.GetLuaState().LogStackTrace();
		return false;
	}

	// All ok
	return true;
}





void cLuaChunkStay::AddChunkCoord(cLuaState & L, int a_Index)
{
	// Check that the element has 2 coords:
	int NumCoords = luaL_getn(L, -1);
	if (NumCoords != 2)
	{
		LOGWARNING("%s: Element #%d doesn't contain 2 coords (got %d). Ignoring the element.",
			__FUNCTION__, a_Index, NumCoords
		);
		return;
	}

	// Read the two coords from the element:
	lua_rawgeti(L, -1, 1);
	lua_rawgeti(L, -2, 2);
	int ChunkX = luaL_checkint(L, -2);
	int ChunkZ = luaL_checkint(L, -1);
	lua_pop(L, 2);

	// Check that a coord is not yet present:
	for (cChunkCoordsVector::iterator itr = m_Chunks.begin(), end = m_Chunks.end(); itr != end; ++itr)
	{
		if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ))
		{
			LOGWARNING("%s: Element #%d is a duplicate, ignoring it.",
				__FUNCTION__, a_Index
			);
			return;
		}
	}  // for itr - m_Chunks[]

	m_Chunks.emplace_back(ChunkX, ChunkZ);
}





void cLuaChunkStay::Enable(cChunkMap & a_ChunkMap, cLuaState::cCallbackPtr a_OnChunkAvailable, cLuaState::cCallbackPtr a_OnAllChunksAvailable)
{
	m_OnChunkAvailable = std::move(a_OnChunkAvailable);
	m_OnAllChunksAvailable = std::move(a_OnAllChunksAvailable);

	// Enable the ChunkStay:
	Super::Enable(a_ChunkMap);
}





void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ)
{
	if (m_OnChunkAvailable != nullptr)
	{
		m_OnChunkAvailable->Call(a_ChunkX, a_ChunkZ);
	}
}





bool cLuaChunkStay::OnAllChunksAvailable(void)
{
	if (m_OnAllChunksAvailable != nullptr)
	{
		// Call the callback:
		m_OnAllChunksAvailable->Call();

		// Remove the callback references - they won't be needed anymore
		m_OnChunkAvailable.reset();
		m_OnAllChunksAvailable.reset();
	}

	// Disable the ChunkStay by returning true
	return true;
}





void cLuaChunkStay::OnDisabled(void)
{
	// This object is no longer needed, delete it
	delete this;
}




