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

/*
 * Abstract module class that is used to provide similar methods to radar / missile control / illuminator
*/
using UnityEngine.Assertions;


public abstract class AngularModule : Module {
	private float angle;
	private float minRange;
	private float maxRange;
	private float maxHeight;

	public AngularModule(JObject json) : base(json) {
		JToken token;
		if (json.TryGetValue("angle", out token)) {
			angle = Mathf.Deg2Rad * (float)json["angle"];
		}
		else {
			angle = 2 * Mathf.PI;
		}

		if (json.TryGetValue("minRange", out token)) {
			minRange = (float)json["minRange"];
		}
		else {
			minRange = 0.0f;
		}

		if (json.TryGetValue("maxRange", out token)) {
			maxRange = (float)json["maxRange"];
		}
		else {
			maxRange = float.MaxValue;
		}

		if (json.TryGetValue("maxHeight", out token)) {
			maxHeight = (float)json["maxHeight"];
		}
		else {
			maxHeight = float.MaxValue;
		}
	}

	public float getAngle() {
		return angle;
	}

	public float getMinRange() {
		return minRange;
	}

	public float getMaxRange() {
		return maxRange;
	}

	public float getMaxHeight() {
		return maxHeight;
	}
}

public abstract class AngularModuleData : ModuleData {
	private float angleOffset;
	
	public AngularModuleData(int parent, Module template, float angleOffset, Vector position) : base(parent, template, position) {
		this.angleOffset = angleOffset;
	}

	public float getAngleOffset() {
		return angleOffset;
	}

	//should only be called when the parent is deployed
	public bool isInRangeAndAngle(DeployedUnit target) {
		DeployedUnit parentUnit = GameController.fromID(parent);
		Assert.IsNotNull(parentUnit);

		Vertex position = parentUnit.getPosition();
		Vertex targetPosition = target.getPosition();
		AngularModule angularTemplate = ((AngularModule)template);

		float distance = position.distance(targetPosition);
		if (distance < angularTemplate.getMinRange() || distance > angularTemplate.getMaxRange()) {
			return false;
		}

		if ((targetPosition.z() - position.z()) > angularTemplate.getMaxHeight()) {
			return false;
		}

		if (angularTemplate.getAngle() == 2 * Mathf.PI) { //no angle restrictions
			return true;
		}

		Vector diff = targetPosition - position;
		float angleTowardsTarget = (new Vector(1, 0, 0)).angle(diff);
		float angle = (angleTowardsTarget - parentUnit.getAngle() - angleOffset) % (2 * Mathf.PI);

		if (angle > Mathf.PI) {
			angle -= 2 * Mathf.PI;
		}
		else if (angle < -Mathf.PI) {
			angle += 2 * Mathf.PI;
		}

		//angle is now between -PI and PI

		return Mathf.Abs(angle) <= angularTemplate.getAngle() / 2;
	}
}