﻿
using UnityEngine;
using UltimateSurvival;
using ORKFramework.Behaviours;
using ORKFramework.UltimateSurvival;
using System.Collections.Generic;
using System.Text;

namespace ORKFramework.Events.Steps
{
	[ORKEditorHelp("US Add To Inventory", "Adds items to the Ultimate Survival inventory.", "")]
	[ORKEventStep(typeof(BaseEvent))]
	[ORKNodeInfo("Game/Ultimate Survival")]
	public class USAddToInventoryStep : BaseEventStep
	{
		[ORKEditorArray(false, "Add Item", "Adds an item to the list.", "",
			"Remove", "Removes this item from the list.", "",
			noRemoveCount=1, isCopy=true, isMove=true, foldout=true, foldoutText=new string[] {
				"Item", "Define the Ultimate Survival item that will be used.", ""
		})]
		public UltimateSurvivalItem[] item = new UltimateSurvivalItem[] { new UltimateSurvivalItem() };

		public USAddToInventoryStep()
		{

		}

		public override void Execute(BaseEvent baseEvent)
		{
			InventoryController inventory = InventoryController.Instance;

			if(inventory != null)
			{
				for(int i = 0; i < this.item.Length; i++)
				{
					this.item[i].Add(inventory, baseEvent);
				}
			}

			baseEvent.StepFinished(this.next);
		}


		/*
		============================================================================
		Node name functions
		============================================================================
		*/
		public override string GetNodeDetails()
		{
			StringBuilder builder = new StringBuilder();
			for(int i = 0; i < this.item.Length; i++)
			{
				if(i > 0)
				{
					builder.Append(", ");
				}
				this.item[i].GetInfoText(builder);
			}
			return builder.ToString();
		}
	}

	[ORKEditorHelp("US Remove From Inventory", "Removes items from the Ultimate Survival inventory.", "")]
	[ORKEventStep(typeof(BaseEvent))]
	[ORKNodeInfo("Game/Ultimate Survival")]
	public class USRemoveFromInventoryStep : BaseEventStep
	{
		[ORKEditorArray(false, "Add Item", "Adds an item to the list.", "",
			"Remove", "Removes this item from the list.", "",
			noRemoveCount=1, isCopy=true, isMove=true, foldout=true, foldoutText=new string[] {
				"Item", "Define the Ultimate Survival item that will be used.", ""
		})]
		public UltimateSurvivalItem[] item = new UltimateSurvivalItem[] { new UltimateSurvivalItem() };

		public USRemoveFromInventoryStep()
		{

		}

		public override void Execute(BaseEvent baseEvent)
		{
			InventoryController inventory = InventoryController.Instance;

			if(inventory != null)
			{
				for(int i = 0; i < this.item.Length; i++)
				{
					this.item[i].Remove(inventory, baseEvent);
				}
			}

			baseEvent.StepFinished(this.next);
		}


		/*
		============================================================================
		Node name functions
		============================================================================
		*/
		public override string GetNodeDetails()
		{
			StringBuilder builder = new StringBuilder();
			for(int i = 0; i < this.item.Length; i++)
			{
				if(i > 0)
				{
					builder.Append(", ");
				}
				this.item[i].GetInfoText(builder);
			}
			return builder.ToString();
		}
	}

	[ORKEditorHelp("US Has In Inventory", "Checks if the Ultimate Survival inventory has defined items.\n" +
		"If the inventory has the items, 'Success' will be executed, otherwise 'Failed'.", "")]
	[ORKEventStep(typeof(BaseEvent))]
	[ORKNodeInfo("Game/Ultimate Survival")]
	public class USHasInInventoryStep : BaseEventCheckStep
	{
		[ORKEditorHelp("Is Exact Quantity", "Check for the exact quantity (quantity == inventory).\n" +
			"If disabled, the inventory must containt at least the defined quantity (quantity <= inventory).", "")]
		public bool isExactQuantity = false;

		[ORKEditorHelp("Needed", "Either ALL or only ONE item must be in the inventory.", "")]
		[ORKEditorInfo(isEnumToolbar=true, toolbarWidth=75)]
		public Needed needed = Needed.All;

		[ORKEditorArray(false, "Add Item", "Adds an item to the list.", "",
			"Remove", "Removes this item from the list.", "",
			noRemoveCount=1, isCopy=true, isMove=true, foldout=true, foldoutText=new string[] {
				"Item", "Define the Ultimate Survival item that will be used.", ""
		})]
		public UltimateSurvivalItem[] item = new UltimateSurvivalItem[] { new UltimateSurvivalItem() };

		public USHasInInventoryStep()
		{

		}

		public override void Execute(BaseEvent baseEvent)
		{
			InventoryController inventory = InventoryController.Instance;

			if(inventory != null && this.Check(inventory, baseEvent))
			{
				baseEvent.StepFinished(this.next);
			}
			else
			{
				baseEvent.StepFinished(this.nextFail);
			}
		}

		private bool Check(InventoryController inventory, BaseEvent baseEvent)
		{
			if(this.item.Length > 0)
			{
				for(int i = 0; i < this.item.Length; i++)
				{
					if(this.isExactQuantity ?
						this.item[i].HasExact(inventory, baseEvent) :
						this.item[i].Has(inventory, baseEvent))
					{
						if(Needed.One == needed)
						{
							return true;
						}
					}
					else if(Needed.All == needed)
					{
						return false;
					}
				}
				if(Needed.All == needed)
				{
					return true;
				}
				else
				{
					return false;
				}
			}
			else
			{
				return true;
			}
		}


		/*
		============================================================================
		Node name functions
		============================================================================
		*/
		public override string GetNodeDetails()
		{
			StringBuilder builder = new StringBuilder(this.needed.ToString());
			builder.Append(": ");

			for(int i = 0; i < this.item.Length; i++)
			{
				if(i > 0)
				{
					builder.Append(", ");
				}
				this.item[i].GetInfoText(builder);
			}
			return builder.ToString();
		}
	}

	[ORKEditorHelp("US Inventory To Variable", "Stores the quantity of a selected " +
		"item found in the Ultimate Survival inventory into a float game variable.", "")]
	[ORKEventStep(typeof(BaseEvent))]
	[ORKNodeInfo("Game/Ultimate Survival")]
	public class USInventoryToVariableStep : BaseEventStep
	{
		// variable settings
		[ORKEditorHelp("Variable Origin", "Select the origin of the variables:\n" +
			"- Local: Local variables are only used in a running event and don't interfere with global variables. " +
			"The variable will be gone once the event ends.\n" +
			"- Global: Global variables are persistent and available everywhere, everytime. " +
			"They can be saved in save games.\n" +
			"- Object: Object variables are bound to objects in the scene by an object ID. " +
			"They can be saved in save games.\n" +
			"- Selected: Variables assigned to selected data of the event.\n" +
			"In a battle event, the variables are usually assigned to the ability or item of the action.", "")]
		[ORKEditorInfo(labelText="Variable Settings")]
		public VariableOrigin origin = VariableOrigin.Global;

		[ORKEditorInfo(labelText="Selected Key")]
		[ORKEditorLayout("origin", VariableOrigin.Selected, endCheckGroup=true, autoInit=true)]
		public StringValue selectedKey;


		// object variables
		[ORKEditorHelp("Use Object", "Use the 'Object Variables' component of game objects to change the object variables.\n" +
			"The changes will be made on every 'Object Variables' component that is found. " +
			"If no component is found, no variables will be changed.\n" +
			"If disabled, you need to define the object ID used to change the object variables.", "")]
		[ORKEditorInfo(separator=true)]
		[ORKEditorLayout("origin", VariableOrigin.Object)]
		public bool useObject = true;

		[ORKEditorInfo(separator=true, labelText="Object")]
		[ORKEditorLayout("useObject", true, autoInit=true)]
		public EventObjectSetting fromObject;

		[ORKEditorHelp("Object ID", "Define the object ID of the object variables.\n" +
			"If the object ID doesn't exist yet, it will be created.", "")]
		[ORKEditorInfo(expandWidth=true)]
		[ORKEditorLayout(elseCheckGroup=true, endCheckGroup=true, endGroups=2)]
		public string objectID = "";


		// variable key
		[ORKEditorInfo(separator=true, labelText="Variable Key")]
		public StringValue key = new StringValue();

		[ORKEditorHelp("Operator", "Defines how the variable will be changed:\n" +
			"- Add: Adds the value to the current value of the variable.\n" +
			"- Sub: Subtracts the value from the current value of the variable.\n" +
			"- Multiply: Multiplies the current value of the variable with the value.\n" +
			"- Divide: Divides the current value of the variable by the value.\n" +
			"- Modulo: Uses the modulo operator, current value of the variable % the value.\n" +
			"- Power Of: The current variable value to the power of the value.\n" +
			"- Log: The current variable value is used in a logarithmic calculation with the value as base.\n" +
			"- Set: Sets the current variable value to the value.", "")]
		public FormulaOperator floatOperator = FormulaOperator.Set;


		// item name
		[ORKEditorInfo(separator=true, labelText="Item Name", label=new string[]
		{
			"Must match the name of the Ultimate Survival item that will be used."
		})]
		public StringValue itemName = new StringValue();

		public USInventoryToVariableStep()
		{

		}

		public override void Execute(BaseEvent baseEvent)
		{
			int quantity = -1;
			InventoryController inventory = InventoryController.Instance;

			if(inventory != null)
			{
				quantity = inventory.GetItemCount(this.itemName.GetValue());
			}


			if(quantity != -1)
			{
				if(VariableOrigin.Local == this.origin)
				{
					baseEvent.Variables.ChangeFloat(this.key.GetValue(),
						quantity, this.floatOperator);
				}
				else if(VariableOrigin.Global == this.origin)
				{
					ORK.Game.Variables.ChangeFloat(this.key.GetValue(),
						quantity, this.floatOperator);
				}
				else if(VariableOrigin.Object == this.origin)
				{
					if(this.useObject)
					{
						List<GameObject> list2 = this.fromObject.GetObject(baseEvent);
						for(int i = 0; i < list2.Count; i++)
						{
							if(list2[i] != null)
							{
								ObjectVariablesComponent[] comps = list2[i].
									GetComponentsInChildren<ObjectVariablesComponent>();
								for(int j = 0; j < comps.Length; j++)
								{
									comps[j].GetHandler().ChangeFloat(
										this.key.GetValue(), quantity, this.floatOperator);
								}
							}
						}
					}
					else
					{
						ORK.Game.Scene.GetObjectVariables(this.objectID).ChangeFloat(
							this.key.GetValue(), quantity, this.floatOperator);
					}
				}
				else if(VariableOrigin.Selected == this.origin)
				{
					List<VariableHandler> handlers = SelectedDataHelper.GetVariableHandlers(
						baseEvent.SelectedData.Get(this.selectedKey.GetValue()));
					for(int i = 0; i < handlers.Count; i++)
					{
						handlers[i].ChangeFloat(this.key.GetValue(),
							quantity, this.floatOperator);
					}
				}
			}
			baseEvent.StepFinished(this.next);
		}


		/*
		============================================================================
		Name functions
		============================================================================
		*/
		public override string GetNodeDetails()
		{
			return this.itemName.GetInfoText() + ": " + this.origin.ToString();
		}
	}
}
