
public abstract class Decoder {

	public static string decode(DeployedUnit unit, string order) {
		char[] space = { ' ' };
		string[] split = order.ToLower().Trim().Split(space);

		if (split[0] == "fire") {
			return decodeFire(unit, split);
		}
		else if (split[0] == "launch") {
			return decodeLaunch(unit, split);
		}
		else if (split[0] == "land") {
			return decodeLand(unit, split);
		}
		else if (split[0] == "set") {
			if (split.Length == 1) {
				return "Unknown set command";
			}
			else if (split[1] == "speed") {
				return decodeSetSpeed(unit, split);
			}
			else if (split[1] == "altitude") {
				return decodeSetAltitude(unit, split);
			}
			return "Unknown set command";
		}

		return order;
	}

	private static string decodeFire(DeployedUnit unit, string[] array) {
		if (array.Length == 1) {
			return "Fire what Sir ?";
		}

		string first = array[1];

		string name = "";
		int number = 1;
		if (int.TryParse(first, out number)) {
			if (array.Length < 3) {
				return "Can you specify what we have to fire Admiral ?";
			}

			name = array[2];
		}
		else {
			number = 1;
			name = array[1];
		}

		Class unitClass = GameController.classFromUniqueNameLower(name);

		if (unitClass == null) {
			return "The name of the missile could not be found";
		}

		if (unit.getTarget() == null) {
			return "Fire on what Sir ????";
		}

		if (!unitClass.canHit(unit.getTarget().getClass().getClassType())) {
			return "This type of missile cannot hit this target Sir !";
		}

		if (unit.canFire(unitClass, number)) {
			unit.fire(unitClass, number, unit.getTarget());
			return "The " + number + " " + unitClass.getName() + " will be fired ASAP !";
		}
		else {
			return "We don't have enough missiles Sir !";
		}
	}

	private static string decodeLaunch(DeployedUnit unit, string[] array) {
		if (array.Length == 1) {
			return "Launch what Sir ?";
		}

		string first = array[1];

		string name = "";
		int number = 1;
		int withSlot = 0;
		if (int.TryParse(first, out number)) {
			if (array.Length < 3) {
				return "Can you specify what we have to launch Admiral ?";
			}

			name = array[2];
			withSlot = 3;
		}
		else {
			number = 1;
			name = array[1];
			withSlot = 2;
		}

		string loadoutName = "";
		if (withSlot < array.Length - 1 && array[withSlot] == "with") {
			loadoutName = array[withSlot + 1];
		}

		Class unitClass = GameController.classFromUniqueNameLower(name);

		if (unitClass == null) {
			return "The name of the unit could not be found";
		}

		if (!unitClass.getPathConstraints().canGoThrough(GameController.getTerrainAt(Converter.metersToGameCoo(unit.getPosition())))) {
			return "This unit cannot be deployed here";
		}

		Loadout loadout = null;
		if (loadoutName != "") {
			loadout = unitClass.getLoadout(loadoutName);

			if (loadout == null) {
				return "The loadout name cannot be found";
			}
		}

		if (unit.canLaunch(unitClass, number, loadout)) { // TODO : check loadout
			unit.launch(unitClass, number, loadout);
			return "The " + number + " " + unitClass.getName() + " will be lauched ASAP !";
		}
		else {
			return "We don't have enough units of this kind, Sir !";
		}
	}

	private static string decodeLand(DeployedUnit unit, string[] array) {
		if (unit.getClass().getClassType() != ClassType.Helicopter) {
			return "Are you joking ?";
		}

		if (unit.getTarget() == null) {
			return "Land on what Sir ????";
		}

		if (unit.getTarget().getClass().getCountry().getRelation(unit.getClass().getCountry()) != Relation.Player) {
			return "We can only land on our units Sir";
		}

		//maybe later, keep a list of units that will land soon, so that the hangars cannot overflow
		if (unit.getTarget().canBeLandedOn(unit)) {
			unit.landOn(unit.getTarget());
			return "We will land ASAP Sir !";
		}
		else {
			return "We cannot land on that, Sir !";
		}
	}

	private static string decodeSetSpeed(DeployedUnit unit, string[] array) {
		if (array.Length != 3) {
			return "Invalid set speed command";
		}

		float newSpeed = float.Parse(array[2]);

		if (newSpeed >= unit.getMinSpeed() && newSpeed <= unit.getMaxSpeed()) {
			Requests.setTargetSpeed(unit, newSpeed);
			return "New speed set !";
		}
		else {
			return "The new speed is invalid";
		}
	}

	private static string decodeSetAltitude(DeployedUnit unit, string[] array) {
		if (array.Length != 3) {
			return "Invalid set speed command";
		}

		float newAltitude = float.Parse(array[2]);

		if (newAltitude >= unit.getMinAltitude() && newAltitude <= unit.getMaxAltitude()) {
			Requests.setAltitude(unit, newAltitude);
			return "New altitude set !";
		}
		else {
			return "The new altitude is invalid";
		}
	}
}
