using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using UnityEngine;

public class LauncherModule : Module {
	private List<string> temporaryCanLaunch;
	private List<Class> launchable;
	private float launchWaitingTime;

	public LauncherModule(JObject json) : base(json) {
		temporaryCanLaunch = new List<string>();
		launchable = new List<Class>();

		foreach (string uniqueClassName in json["canLaunch"]) {
			temporaryCanLaunch.Add(uniqueClassName);
		}

		launchWaitingTime = (float)json["launchWaitingTime"];

		sprite = Resources.Load("Sprites/Modules/Launchers/" + getUniqueName(), typeof(Sprite)) as Sprite;
	}

	public float getWaitingTime() {
		return launchWaitingTime;
	}

	public bool canLaunch(Class unitClass) {
		return launchable.Contains(unitClass);
	}

	public static LauncherModule[] loadModules(string[] filenames) {
		LauncherModule[] array = new LauncherModule[filenames.Length];

		for (int i = 0; i < filenames.Length; i++) {
			array[i] = new LauncherModule(jsonFromFile(filenames[i]));
		}

		return array;
	}

	override public void updateClasses() {
		foreach(string uniqueClassName in temporaryCanLaunch) {
			launchable.Add(GameController.classFromUniqueName(uniqueClassName));
		}
	}

	override public ModuleData getData(int parent) {
		return new LauncherModuleData(parent, this);
	}
}

public class LauncherModuleData : ModuleData {
	private List<StoredUnit> readyToLaunch;
	private float waitingTime;

	public LauncherModuleData(int parent, Module template) : base(parent, template) {
		readyToLaunch = new List<StoredUnit>();
		waitingTime = 0.0f;
	}

	//should only be called from StoredUnit's changeStore
	public void addReadyToLaunch(StoredUnit unit) {
		readyToLaunch.Add(unit);
		//TODO : add delay
	}

	public void removeFromReady(StoredUnit unit) {
		readyToLaunch.Remove(unit);
	}

	public void removeFromReadyIfExists(int unitID) {
		StoredUnit unit = null;

		foreach(StoredUnit stored in readyToLaunch) {
			if (stored.getID() == unitID) {
				unit = stored;
			}
		}

		if (unit == null) {
			return;
		}

		readyToLaunch.Remove(unit);
	}

	public int getNumberReadyToLaunch(Class launchedClass) {
		int num = 0;

		foreach(StoredUnit unit in readyToLaunch) {
			if (!unit.isBeingLoaded() && unit.getClass() == launchedClass) {
				num ++;
			}
		}

		return num;
	}

	public bool tryToFire(Class missileClass, DeployedUnit target) {
		if (waitingTime > 0.0f) {
			return false;
		}

		bool hasFired = false;
		StoredUnit toBeRemoved = null;

		foreach(StoredUnit unit in readyToLaunch) {
			if (unit.getClass() == missileClass) {

				Requests.deployUnit(unit);
				Requests.changeTarget(GameController.fromID(unit.getID()), target);
				Requests.moveTowardsTarget(GameController.fromID(unit.getID()), target);

				toBeRemoved = unit;
				hasFired = true;
				break;
			}
		}

		if (hasFired) {
			toBeRemoved.removeFromStore();
			waitingTime = ((LauncherModule)template).getWaitingTime();
		}

		return hasFired;
	}

	public bool tryToLaunch(StoredUnit toBeLaunched) {
		if (waitingTime > 0.0f) {
			return false;
		}

		bool hasLaunched = false;
		StoredUnit toBeRemoved = null;

		foreach(StoredUnit unit in readyToLaunch) {
			if (unit == toBeLaunched) {

				Requests.deployUnit(unit);

				float angle = GameController.fromID(parent).getAngle();
				Vector displacement = new Vector(Mathf.Cos(angle), Mathf.Sin(angle), 0);
				Requests.moveUnit(GameController.fromID(unit.getID()), GameController.fromID(parent).getPosition() + displacement * unit.getClass().getLaunchDistance());

				toBeRemoved = unit;
				hasLaunched = true;
				break;
			}
		}

		if (hasLaunched) {
			toBeRemoved.removeFromStore();
			waitingTime = ((LauncherModule)template).getWaitingTime();
		}

		return hasLaunched;
	}

	//returns a unit of the right class which is not being loaded
	public StoredUnit prepareLoading(Class unitClass) {
		foreach(StoredUnit unit in readyToLaunch) {
			if (unit.getClass() == unitClass && !unit.isBeingLoaded()) {
				return unit;
			}
		}

		return null;
	}

	override public void deployUnit(int storedUnitID) {
		foreach(StoredUnit unit in readyToLaunch) {
			if (unit.getID() == storedUnitID) {
				unit.deploy();
			}
		}

		removeFromReadyIfExists(storedUnitID);
	}

	override public bool isFiring() {
		return waitingTime > 0.0f;
	}

	override public void updateTime(float delta) {
		waitingTime = Mathf.Max(0.0f, waitingTime - delta);
	}
}