using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//Manages the 'grid' of modules
using UnityEngine.UI;


public abstract class GridManagement {

	public static Transform allModulesUI;
	public static List<Tuple<GameObject, GameObject>> modulesPanels; //where to clone the modules' UI, depending on their tab, and the corresponding button

	public static void init() {
		modulesPanels = new List<Tuple<GameObject, GameObject>>();
		allModulesUI = GameObject.Find("Templates/ModulesUI").transform;

		modulesPanels.Add(getTabGameObjects("Weapons"));
		modulesPanels.Add(getTabGameObjects("Sensors"));
		modulesPanels.Add(getTabGameObjects("Ship&Prop"));
		modulesPanels.Add(getTabGameObjects("Command"));
	}

	private static Tuple<GameObject, GameObject> getTabGameObjects(string name) {
		return new Tuple<GameObject, GameObject>(GameObject.Find("Canvas/GUI/ModulesStates/" + name), GameObject.Find("Canvas/GUI/ModulesStates/Tabs/" + name));
	}

	public static void constructGrid(DeployedUnit selectedUnit) {
		Class unitClass = selectedUnit.getClass();

		float width = modulesPanels[0]._1.GetComponent<RectTransform>().rect.width;
		float height = modulesPanels[0]._1.GetComponent<RectTransform>().rect.height;

		foreach(Tuple<GameObject, GameObject> tab in modulesPanels) {
			GameController.deleteAllChildren(tab._1.transform);
			tab._2.SetActive(false);
		}
		foreach (ModuleUI moduleUI in unitClass.getModulesUI()) {
			modulesPanels[moduleUI.getTab()]._2.SetActive(true);

			GameObject clone = GameObject.Instantiate(allModulesUI.FindChild(moduleUI.getName()).gameObject, modulesPanels[moduleUI.getTab()]._1.transform);

			RectTransform transform = clone.GetComponent<RectTransform>();

			transform.localPosition = new Vector3(moduleUI.getX() * width / Constants.MODULE_GRID_WIDTH + Constants.MODULE_BORDER, moduleUI.getY() * height / Constants.MODULE_GRID_HEIGHT - Constants.MODULE_BORDER, 0);
			transform.sizeDelta = new Vector2(width * (-Constants.MODULE_GRID_WIDTH + moduleUI.getWidth()) / Constants.MODULE_GRID_WIDTH - 2 * Constants.MODULE_BORDER,
				height * (-Constants.MODULE_GRID_HEIGHT + moduleUI.getHeight()) / Constants.MODULE_GRID_HEIGHT - 2 * Constants.MODULE_BORDER);

			clone.name = moduleUI.getName();
			GridElement gridElement = clone.AddComponent<GridElement>();
			gridElement.moduleDatas = getModuleDatas(selectedUnit, moduleUI);

			if (moduleUI.getName().StartsWith("Template")) {
				clone.transform.Find("Header").GetComponent<Text>().text = moduleUI.getHeader();

				for(int i = 0; i < gridElement.moduleDatas.Count; i++) {
					if (clone.transform.Find("Image" + (i+1)) == null) {
						Debug.LogError(("Image" + (i+1)) + " missing : " + "Number of modules : " + gridElement.moduleDatas.Count + " for " + moduleUI.getName() + " ; " + gridElement.moduleDatas[0].getTemplate().getUniqueName());
					}
					else if (gridElement.moduleDatas[i].getTemplate().getSilhouette() != null) {
						Transform image = clone.transform.Find("Image" + (i+1));
						image.GetComponent<Image>().sprite = gridElement.moduleDatas[i].getTemplate().getSilhouette();
						image.GetComponent<Image>().preserveAspect = true;

						addModuleState("Firing", image, width, height);
						addModuleState("Offline", image, width, height);
						addModuleState("Destroyed", image, width, height);
					}
					else {
						clone.transform.Find("Image" + (i+1)).GetComponent<Image>().enabled = false;
					}
				}
			}

			//description
			ToolTip tooltip = clone.GetComponent<ToolTip>();
			tooltip.text = moduleUI.getDescription();
		}

		bool needToChangeTab = false;
		foreach(Tuple<GameObject, GameObject> tab in modulesPanels) {
			if (!tab._2.activeSelf) {
				OnOffButton button = tab._2.GetComponent<OnOffButton>();

				if (button.state) {
					needToChangeTab = true;
					break;
				}
			}
		}

		if (needToChangeTab) {
			foreach(Tuple<GameObject, GameObject> tab in modulesPanels) {
				if (tab._2.activeSelf) {
					OnOffButton button = tab._2.GetComponent<OnOffButton>();
					button.click();
				}
			}
		}
	}

	private static List<ModuleData> getModuleDatas(DeployedUnit selectedUnit, ModuleUI moduleUI) {
		List<ModuleData> datas = new List<ModuleData>();

		foreach(string moduleName in moduleUI.getMonitoredModules()) {
			datas.AddRange(selectedUnit.getModuleDatas(moduleName));
		}

		return datas;
	}

	private static void addModuleState(string name, Transform image, float width, float height) {
		GameObject firing = GameObject.Instantiate(GameObject.Find("Templates/ModuleStates/" + name), image.parent.parent);
		firing.name = name;
		firing.SetActive(false);
		firing.GetComponent<RectTransform>().sizeDelta = new Vector2(-width / 10, -height / 20);

		firing.transform.SetParent(image, true);
		firing.transform.localPosition = new Vector3();
	}

	public static void updateModules(DeployedUnit selectedUnit) {
		foreach(Tuple<GameObject, GameObject> tab in modulesPanels) {
			if (tab._1.activeSelf) { //no need to update invisible tabs
				foreach (Transform child in tab._1.transform) {
					string name = child.gameObject.name;
					GridElement element = child.gameObject.GetComponent<GridElement>();

					updateHealth(child.gameObject, element);

					/*if (name == "ArleighMk-41") {
						updateModuleArleighMk_41(child.gameObject, element);
					}
					else */if (name.StartsWith("Template")) {

						int count = 1;
						foreach(ModuleData moduleData in element.moduleDatas) {
							updateModuleGeneral(child.gameObject, moduleData, count);

							if (moduleData is CIWSModuleData) {
								updateModuleCIWS(child.gameObject, moduleData, count);
							}
							else if (moduleData is FuelTankModuleData) {
								updateModuleFuelTank(child.gameObject, moduleData, count);
							}
							else if (moduleData is LauncherModuleData) {
								updateModuleLauncher(child.gameObject, moduleData, count);
							}
							else if (moduleData is MissileControlModuleData) {
								updateModuleMissileControl(child.gameObject, moduleData, count);
							}

							count++;
						}
						if (element.moduleDatas.Count == 0) {
							Debug.LogWarning("No monitored modules for " + name);
						}
					}
				}
			}
		}
	}

	private static void updateHealth(GameObject gameObject, GridElement element) {
		float health = 0.0f;
		float total = 0.0f;

		foreach(ModuleData data in element.moduleDatas) {
			health += data.getHealth();
			total += data.getTemplate().getHealth();
		}

		gameObject.GetComponent<Image>().color = Util.getColorFromValue(health / total);
	}

	/*private static void updateModuleArleighMk_41(GameObject gameObject, GridElement element) {
		LauncherModuleData fore = (LauncherModuleData)element.moduleDatas[0];
		LauncherModuleData aft = (LauncherModuleData)element.moduleDatas[0];

		Transform foreList = gameObject.transform.Find("ForeList");
		Transform aftList = gameObject.transform.Find("AftList");
		GameObject weaponText = gameObject.transform.Find("ForeList/Weapon").gameObject;

		GameController.deleteAllChildren(foreList, true);
		foreach(Tuple<Class, int> tuple in fore.getReadyToLaunch()) {
			GameObject clone = GameObject.Instantiate(weaponText, foreList);

			clone.SetActive(true);
			clone.transform.Find("Name").gameObject.GetComponent<Text>().text = tuple._1.getName();
			clone.transform.Find("Num").gameObject.GetComponent<Text>().text = tuple._2 + "";
		}

		GameController.deleteAllChildren(aftList, true);
		foreach(Tuple<Class, int> tuple in aft.getReadyToLaunch()) {
			GameObject clone = GameObject.Instantiate(weaponText, aftList);

			clone.SetActive(true);
			clone.transform.Find("Name").gameObject.GetComponent<Text>().text = tuple._1.getName();
			clone.transform.Find("Num").gameObject.GetComponent<Text>().text = tuple._2 + "";
		}
	}*/

	private static void updateModuleGeneral(GameObject gameObject, ModuleData moduleData, int count) {
		gameObject.transform.Find("Image" + count + "/Firing").gameObject.SetActive(moduleData.isFiring() && (Time.frameCount % 30) < 15);
		gameObject.transform.Find("Image" + count + "/Destroyed").gameObject.SetActive(moduleData.isDestroyed());
		gameObject.transform.Find("Image" + count + "/Offline").gameObject.SetActive(moduleData.isDisabled());
	}

	private static void updateModuleCIWS(GameObject gameObject, ModuleData moduleData, int count) {
		CIWSModule module = (CIWSModule)moduleData.getTemplate();
		CIWSModuleData data = (CIWSModuleData)moduleData;

		gameObject.transform.Find("Text" + count).gameObject.GetComponent<Text>().text = data.getAmmoLeft() + " / " + module.getMaxAmmo();
	}

	private static void updateModuleFuelTank(GameObject gameObject, ModuleData moduleData, int count) {
		FuelTankModule module = (FuelTankModule)moduleData.getTemplate();
		FuelTankModuleData data = (FuelTankModuleData)moduleData;

		gameObject.transform.Find("Text" + count).gameObject.GetComponent<Text>().text = "FUEL LEFT : " + (int)data.getFuelLeft() + " / " + module.getFuelQuantity();
	}

	private static void updateModuleLauncher(GameObject gameObject, ModuleData moduleData, int count) {
		LauncherModule module = (LauncherModule)moduleData.getTemplate();
		LauncherModuleData data = (LauncherModuleData)moduleData;

		Transform list = gameObject.transform.Find("List" + count);
		if (list != null) {
			GameObject weaponText = list.Find("Weapon").gameObject;

			GameController.deleteAllChildren(list, true);
			foreach(Tuple<Class, int> tuple in data.getReadyToLaunch()) {
				GameObject clone = GameObject.Instantiate(weaponText, list);

				clone.SetActive(true);
				clone.transform.Find("Name").gameObject.GetComponent<Text>().text = tuple._1.getName();
				clone.transform.Find("Num").gameObject.GetComponent<Text>().text = tuple._2 + "";
			}
		}
		else {
			gameObject.transform.Find("Text" + count).gameObject.GetComponent<Text>().text = "NO AMMO";
		}
	}

	private static void updateModuleMissileControl(GameObject gameObject, ModuleData moduleData, int count) {
		MissileControlModule module = (MissileControlModule)moduleData.getTemplate();
		MissileControlModuleData data = (MissileControlModuleData)moduleData;

		gameObject.transform.Find("Text" + count).gameObject.GetComponent<Text>().text = (int)data.getRemainingSlots() + " / " + module.getSlots();
	}
}
