using UnityEngine;
using System.Collections.Generic;public abstract class Requests {

	public static void moveUnit(DeployedUnit unit, Vertex destination) {
		if (unit.getClass().getClassType() == ClassType.Missile) {
			return;
		}

		if (NetworkManager.isServer()) {
			Path path = PathFinding.findPath(unit, destination);

			if (path == null) {
				NetworkManager.addToLog(unit.getID(), "Unable to find path");
				return;
			}

			unit.setPath(path, false);

			//Send update to clients
			Buffer buffer = new Buffer(PacketCode.changePathAndPos);
			buffer.writeInt(unit.getID());
			buffer.writeVertex(unit.getPosition());
			buffer.writeFloat(unit.getAngle());
			buffer.writePath(path);
			NetworkManager.toClients(buffer);
		}
		else {
			//Send request to server
			Buffer buffer = new Buffer(PacketCode.requestMovement);
			buffer.writeInt(unit.getID());
			buffer.writeVertex(destination);
			NetworkManager.toServer(buffer);
		}
	}

	public static void changeTarget(DeployedUnit unit, DeployedUnit target) {
		if (NetworkManager.isServer()) {
			unit.setTarget(target);

			//Send update to clients
			Buffer buffer = new Buffer(PacketCode.changeTarget);
			buffer.writeInt(unit.getID());
			buffer.writeInt(target.getID());
			NetworkManager.toClients(buffer);
		}
		else {
			//Send request to server
			Buffer buffer = new Buffer(PacketCode.requestChangeTarget);
			buffer.writeInt(unit.getID());
			buffer.writeInt(target.getID());
			NetworkManager.toServer(buffer);
		}
	}

	public static void setNullTarget(DeployedUnit unit) {
		if (NetworkManager.isServer()) {
			unit.setTarget(null);

			//Send update to clients
			Buffer buffer = new Buffer(PacketCode.setNullTarget);
			buffer.writeInt(unit.getID());
			NetworkManager.toClients(buffer);
		}
		else {
			//Send request to server
			Buffer buffer = new Buffer(PacketCode.requestSetNullTarget);
			buffer.writeInt(unit.getID());
			NetworkManager.toServer(buffer);
		}
	}

	public static void unitOrder(DeployedUnit unit, string order) {
		if (unit.getClass().getClassType() == ClassType.Missile) {
			return;
		}

		if (NetworkManager.isServer()) {
			string message = Decoder.decode(unit, order);

			NetworkManager.addToLog(unit.getID(), message);
		}
		else {
			Buffer buffer = new Buffer(PacketCode.requestOrder);
			buffer.writeInt(unit.getID());
			buffer.writeString(order);
			NetworkManager.toServer(buffer);
		}
	}

	public static void deployUnit(StoredUnit unit) {
		if (NetworkManager.isServer()) {
			unit.deploy();

			Buffer buffer = new Buffer(PacketCode.deployUnit);
			buffer.writeInt(unit.getID());
			NetworkManager.toClients(buffer);
		}
		else {
			Debug.LogError("Clients cannot request unit deployment");
		}
	}

	public static void moveTowardsTarget(DeployedUnit unit, DeployedUnit target) {
		if (NetworkManager.isServer()) {
			Path path = PathFinding.findPath(unit, target.getPosition());

			if (path == null) {
				NetworkManager.addToLog(unit.getID(), "Unable to find path");
				return;
			}

			if (unit.getClass().getClassType() == ClassType.Missile) {
				switch(unit.getMissileTechnique()) {
					default:
						path.addEndWaypoint(new TargetWaypoint(unit, target, 1000, unit.getCruiseAltitude()));
						path.addEndWaypoint(new UnitWaypoint(target));
					break;
				}
			}
			else {
				foreach(Tuple<float, float> tuple in unit.getLandingPattern()) {
					path.addEndWaypoint(new LandingWaypoint(target, tuple._1, tuple._2));
				}

				path.addEndWaypoint(new UnitWaypoint(target));
			}

			unit.setPath(path, false);

			//Send update to clients
			Buffer buffer = new Buffer(PacketCode.changePathAndPos);
			buffer.writeInt(unit.getID());
			buffer.writeVertex(unit.getPosition());
			buffer.writeFloat(unit.getAngle());
			buffer.writePath(path);
				
			NetworkManager.toClients(buffer);
		}
		else {
			Debug.LogError("Clients cannot request move toward targets");
		}
	}

	public static void updatePath(DeployedUnit unit) {
		if (NetworkManager.isServer()) {
			Path oldPath = unit.getPath();
			List<Waypoint> oldEndWaypoints = oldPath.getEndWaypoints();

			foreach (Waypoint endWaypoint in oldEndWaypoints) {
				endWaypoint.resetInfo();
			}

			Vertex destination = oldEndWaypoints[0].getVertex();

			Path newPath = PathFinding.findPath(unit, destination);

			newPath.addEndWaypoints(oldEndWaypoints);

			unit.setPath(newPath, true);

			//Send update to clients
			Buffer buffer = new Buffer(PacketCode.changePathAndPos);
			buffer.writeInt(unit.getID());
			buffer.writeVertex(unit.getPosition());
			buffer.writeFloat(unit.getAngle());
			buffer.writePath(newPath);
			NetworkManager.toClients(buffer);
		}
		else {
			Debug.LogError("Clients cannot request path updates");
		}
	}

	public static void changeGameSpeed(float newGameSpeed) {
		if (NetworkManager.isServer()) {
			GameController.setGameSpeed(newGameSpeed);

			//Send update to clients
			Buffer buffer = new Buffer(PacketCode.changeGameSpeed);
			buffer.writeFloat(newGameSpeed);
			NetworkManager.toClients(buffer);
		}
		else {
			//Send request to server
			Buffer buffer = new Buffer(PacketCode.requestChangeGameSpeed);
			buffer.writeFloat(newGameSpeed);
			NetworkManager.toServer(buffer);
		}
	}

	public static void changePause(bool value) {
		if (NetworkManager.isServer()) {
			GameController.setPause(value);

			//Send update to clients
			Buffer buffer = new Buffer(PacketCode.changePause);
			buffer.writeBool(value);
			NetworkManager.toClients(buffer);
		}
		else {
			//Send request to server
			Buffer buffer = new Buffer(PacketCode.requestChangePause);
			buffer.writeBool(value);
			NetworkManager.toServer(buffer);
		}
	}

	public static void destroyUnit(DeployedUnit unit) {
		if (NetworkManager.isServer()) {
			GameController.destroyUnit(unit);

			//Send update to clients
			Buffer buffer = new Buffer(PacketCode.destroyUnit);
			buffer.writeInt(unit.getID());
			NetworkManager.toClients(buffer);
		}
		else {
			Debug.LogError("Clients cannot request destruction of units");
		}
	}

	public static void setHealth(DeployedUnit unit, int moduleDataID, float newHealth) {
		if (NetworkManager.isServer()) {
			unit.setHealth(moduleDataID, newHealth);

			//Send update to clients
			Buffer buffer = new Buffer(PacketCode.setHealth);
			buffer.writeInt(unit.getID());
			buffer.writeInt(moduleDataID);
			buffer.writeFloat(newHealth);
			NetworkManager.toClients(buffer);
		}
		else {
			Debug.LogError("Clients cannot set health");
		}
	}

	public static void setIsFiring(DeployedUnit unit, int moduleDataID, bool isFiring) {
		if (NetworkManager.isServer()) {
			//unit.setFiring(moduleDataID, isFiring); //useless as the server does not use the 'firing' boolean

			//Send update to clients
			Buffer buffer = new Buffer(PacketCode.setFiring);
			buffer.writeInt(unit.getID());
			buffer.writeInt(moduleDataID);
			buffer.writeBool(isFiring);
			NetworkManager.toClients(buffer);
		}
		else {
			Debug.LogError("Clients cannot set firing status");
		}
	}

	public static void disableModule(DeployedUnit unit, int moduleDataID, bool isDisabled) {
		if (NetworkManager.isServer()) {
			unit.setDisabled(moduleDataID, isDisabled);

			//Send update to clients
			Buffer buffer = new Buffer(PacketCode.setDisabled);
			buffer.writeInt(unit.getID());
			buffer.writeInt(moduleDataID);
			buffer.writeBool(isDisabled);
			NetworkManager.toClients(buffer);
		}
		else {
			//Send request to server
			Buffer buffer = new Buffer(PacketCode.requestSetDisabled);
			buffer.writeInt(unit.getID());
			buffer.writeInt(moduleDataID);
			buffer.writeBool(isDisabled);
			NetworkManager.toServer(buffer);
		}
	}

	public static void setTargetSpeed(DeployedUnit unit, float newTargetSpeed) {
		if (NetworkManager.isServer()) {
			unit.setTargetSpeed(newTargetSpeed);

			//Send update to clients
			Buffer buffer = new Buffer(PacketCode.setTargetSpeed);
			buffer.writeInt(unit.getID());
			buffer.writeFloat(newTargetSpeed);
			NetworkManager.toClients(buffer);
		}
		else {
			Debug.LogError("Clients cannot set target speed");
		}
	}

	public static void setAltitude(DeployedUnit unit, float newAltitude) {
		if (NetworkManager.isServer()) {
			Path newPath = new Path(new Vertex(unit.getPosition().x(), unit.getPosition().y(), newAltitude));

			unit.setCruiseAltitude(newAltitude); //no need to send this update to the clients
			unit.setPath(newPath, false);

			//Send update to clients
			Buffer buffer = new Buffer(PacketCode.changePathAndPos);
			buffer.writeInt(unit.getID());
			buffer.writeVertex(unit.getPosition());
			buffer.writeFloat(unit.getAngle());
			buffer.writePath(newPath);

			NetworkManager.toClients(buffer);
		}
		else {
			Debug.LogError("Clients cannot set altitude");
		}
	}

	public static void setStore(StoredUnit stored, ModuleData newStore) {
		if (NetworkManager.isServer()) {

			stored.changeStore(newStore);

			//Send update to clients
			Buffer buffer = new Buffer(PacketCode.setStore);
			buffer.writeInt(stored.getID());
			buffer.writeInt(newStore.getID());

			NetworkManager.toClients(buffer);
		}
		else {
			//Debug.LogError("Clients cannot update store");
		}
	}

	public static void storeUnit(DeployedUnit unit) {
		if (NetworkManager.isServer()) {

			GameController.destroyUnit(unit);
			StoredUnit newStored = new StoredUnit(unit);

			//Send update to clients
			Buffer buffer = new Buffer(PacketCode.storeUnit);
			buffer.writeInt(unit.getID());

			NetworkManager.toClients(buffer);
		}
		else {
			Debug.LogError("Clients cannot store unit");
		}
	}
}
