#include "Commands_MiscForms.h"
#include "ParamInfos.h"
#include "Script.h"

#if OBLIVION
#include "GameObjects.h"
#include "GameAPI.h"
#include "GameForms.h"
#include "StringVar.h"
#include "Hooks_Gameplay.h"

static enum {
	eMode_Get,
	eMode_Set,
	eMode_GetChance,
	eMode_SetChance
};

static bool IngredientCommand_Execute(COMMAND_ARGS, UInt32 mode)
{
	UInt32* refResult = (UInt32*)result;
	*refResult = 0;

	TESForm* floraForm = NULL;
	TESForm* ingredientForm = NULL;
	UInt32 whichSeason = 0;
	UInt32 newChance = 0;

	bool bExtracted = false;
	switch (mode)
	{
	case eMode_Get:
		bExtracted = ExtractArgsEx(paramInfo, arg1, opcodeOffsetPtr, scriptObj, eventList, &floraForm);
		break;
	case eMode_Set:
		bExtracted = ExtractArgsEx(paramInfo, arg1, opcodeOffsetPtr, scriptObj, eventList, &ingredientForm, &floraForm);
		break;
	case eMode_GetChance:
		bExtracted = ExtractArgsEx(paramInfo, arg1, opcodeOffsetPtr, scriptObj, eventList, &whichSeason, &floraForm);
		break;
	case eMode_SetChance:
		bExtracted = ExtractArgsEx(paramInfo, arg1, opcodeOffsetPtr, scriptObj, eventList, &whichSeason, &newChance, &floraForm);
		break;
	}

	if (!bExtracted)
		return true;
	else if (!floraForm)
	{
		if (thisObj)
			floraForm = thisObj->TryGetREFRParent();
		else
			return true;
	}
	
	TESProduceForm* produceForm = (TESProduceForm*)Oblivion_DynamicCast(floraForm, 0, RTTI_TESForm, RTTI_TESProduceForm, 0);
	IngredientItem* ingredient = NULL;
	if (ingredientForm)
		ingredient = (IngredientItem*)Oblivion_DynamicCast(ingredientForm, 0, RTTI_TESForm, RTTI_IngredientItem, 0);

	if (!produceForm)
		return true;

	switch (mode)
	{
	case eMode_Get:
		if (produceForm->ingredient)
			*refResult = produceForm->ingredient->refID;
		break;
	case eMode_Set:
		produceForm->ingredient = ingredient;
		break;
	case eMode_GetChance:
		if (whichSeason < 4)
			*result = produceForm->harvestChance[whichSeason];
		break;
	case eMode_SetChance:
		if (whichSeason < 4 && newChance <= 100)
			produceForm->harvestChance[whichSeason] = newChance;
		break;
	}

	return true;
}

static bool Cmd_GetIngredient_Execute(COMMAND_ARGS)
{
	return IngredientCommand_Execute(PASS_COMMAND_ARGS, eMode_Get);
}

static bool Cmd_SetIngredient_Execute(COMMAND_ARGS)
{
	return IngredientCommand_Execute(PASS_COMMAND_ARGS, eMode_Set);
}

static bool Cmd_GetIngredientChance_Execute(COMMAND_ARGS)
{
	return IngredientCommand_Execute(PASS_COMMAND_ARGS, eMode_GetChance);
}

static bool Cmd_SetIngredientChance_Execute(COMMAND_ARGS)
{
	return IngredientCommand_Execute(PASS_COMMAND_ARGS, eMode_SetChance);
}

static const UInt32 kGetText_arg1 = 0x43534544;

static bool Cmd_GetBookText_Execute(COMMAND_ARGS)
{
	TESForm* form = NULL;
	const char* text = NULL;

	if (ExtractArgs(PASS_EXTRACT_ARGS, &form))
	{
		_MESSAGE("Args extracted");
		if (!form)
			form = thisObj->baseForm;

		TESObjectBOOK* book = (TESObjectBOOK*)Oblivion_DynamicCast(form, 0, RTTI_TESForm, RTTI_TESObjectBOOK, 0);
		if (book)
		{
			_MESSAGE("Got a book");
			text = book->description.GetText(0, kGetText_arg1);
			_MESSAGE("called gettext");
		}
		else
			_MESSAGE("Couldn't geta book");
	}	

	if (!text)
	{
		_MESSAGE("Couldn't read book text");
		if (form)
			_MESSAGE("Book = %08x", form->refID);
		text = "";
	}
	else
		_MESSAGE("%s", text);

	AssignToStringVar(PASS_COMMAND_ARGS, text);
	
	return true;
}

static bool Cmd_GetEditorID_Execute(COMMAND_ARGS)
{
	// if editorID not available, use formID. if no form, use a bunch of zeroes
	char buf[0x200] = "00000000";
	const char* idStr = buf;

	TESForm* form = NULL;
	if (ExtractArgsEx(paramInfo, arg1, opcodeOffsetPtr, scriptObj, eventList, &form) && form)
	{
		const char* edID = form->GetEditorID();
		if (edID)
			idStr = edID;
		else
			sprintf_s(buf, sizeof(buf), "%08X", form->refID);
	}

	AssignToStringVar(PASS_COMMAND_ARGS, idStr);
	return true;
}

static bool Cmd_MatchPotion_Execute(COMMAND_ARGS)
{
	TESForm* potionForm = NULL;
	UInt32* refResult = (UInt32*)result;
	*refResult = 0;

	if (ExtractArgs(PASS_EXTRACT_ARGS, &potionForm) && potionForm)
	{
		AlchemyItem* alch = OBLIVION_CAST(potionForm, TESForm, AlchemyItem);
		if (alch)
		{
			alch = MatchPotion(alch);
			if (alch)
				*refResult = alch->refID;
		}
	}

	return true;
}

#endif

static ParamInfo kParams_GetIngredient[1] =
{
	{	"Flora",	kParamType_InventoryObject,		1	},
};

// 1st param is optional to allow setting ingredient to NULL
static ParamInfo kParams_SetIngredient[2] =
{
	{	"Ingredient",	kParamType_InventoryObject,		1	},		
	{	"Flora",		kParamType_InventoryObject,		1	},
};

static ParamInfo kParams_GetIngredientChance[2] =
{
	{	"Season",		kParamType_Integer,				0	},
	{	"Flora",		kParamType_InventoryObject,		1	},
};

static ParamInfo kParams_SetIngredientChance[3] =
{
	{	"Season",		kParamType_Integer,				0	},
	{	"New Chance",	kParamType_Integer,				0	},
	{	"Flora",		kParamType_InventoryObject,		1	},
};

DEFINE_COMMAND(GetIngredient,
			   returns the ingredient contained by a TESFlora object,
			   0,
			   1,
			   kParams_GetIngredient);

DEFINE_COMMAND(SetIngredient,
			   sets the ingredient contained by a TESFlora object,
			   0,
			   2,
			   kParams_SetIngredient);

DEFINE_COMMAND(GetIngredientChance,
			   returns the seasonal chance of harvesting an ingredient,
			   0,
			   2,
			   kParams_GetIngredientChance);

DEFINE_COMMAND(SetIngredientChance,
			   sets the seasonal chance of harvesting an ingredient,
			   0,
			   3,
			   kParams_SetIngredientChance);

DEFINE_COMMAND(GetBookText,
			   returns the text of a book,
			   0,
			   1,
			   kParams_OneOptionalInventoryObject);

DEFINE_COMMAND(GetEditorID, returns the editorID of a form if possible, 0, 1, kParams_OneInventoryObject);

DEFINE_COMMAND(MatchPotion, returns a potion matching the effects of the passed potion if any, 0, 1, kParams_OneInventoryObject);

