using UnityEngine;
using System.Collections;
using Game.Plugins.App.Sync;

namespace Pathfinding.Examples {
	/// <summary>Small sample script for placing obstacles</summary>
	[HelpURL("https://arongranberg.com/astar/documentation/stable/class_pathfinding_1_1_examples_1_1_object_placer.php")]
	public class ObjectPlacer : JNGSyncFrameDefault {
		/// <summary>
		/// GameObject to place.
		/// When using a Grid Graph you need to make sure the object's layer is included in the collision mask in the GridGraph settings.
		/// </summary>
		public GameObject go;

		/// <summary>Flush Graph Updates directly after placing. Slower, but updates are applied immidiately</summary>
		public bool direct = false;

		/// <summary>Issue a graph update object after placement</summary>
		public bool issueGUOs = true;

		float lastPlacedTime;

		public override void OnSyncUpdate(int dt, JNFrameInfo frame, Object input)
		{
			base.OnSyncUpdate(dt, frame, input);
			// Check if P is being pressed.
			// Don't place objects if ctrl is pressed to avoid conflicts with the pause shortcut (ctrl+shift+P)
			if (!Input.GetKey(KeyCode.LeftControl) && (Input.GetKeyDown("p") || (Input.GetKey("p") && GetSync().Time.time - lastPlacedTime > 0.3f))) {
				PlaceObject();
			}

			if (Input.GetKeyDown("r")) {
				StartCoroutine(RemoveObject());
			}
		}
		
		public void PlaceObject () {
			lastPlacedTime = GetSync().Time.time;
			Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
			RaycastHit hit;

			// Figure out where the ground is
			if (Physics.Raycast(ray, out hit, Mathf.Infinity)) {
				Vector3 p = hit.point;
				GameObject obj = GameObject.Instantiate(go, p, Quaternion.identity) as GameObject;

				if (issueGUOs) {
					Bounds b = obj.GetComponent<Collider>().bounds;
					GraphUpdateObject guo = new GraphUpdateObject(b);
					AstarPath.active.UpdateGraphs(guo);
					if (direct) {
						AstarPath.active.FlushGraphUpdates();
					}
				}
			}
		}

		public IEnumerator RemoveObject () {
			Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
			RaycastHit hit;

			// Check what object is under the mouse cursor
			if (Physics.Raycast(ray, out hit, Mathf.Infinity)) {
				// Ignore ground and triggers
				if (hit.collider.isTrigger || hit.transform.gameObject.name == "Ground") yield break;

				Bounds b = hit.collider.bounds;
				Destroy(hit.collider);
				Destroy(hit.collider.gameObject);

				if (issueGUOs) {
					// In Unity, object destruction is actually delayed until the end of the Update loop.
					// This means that we need to wait until the end of the frame (or until the next frame) before
					// we update the graph. Otherwise the graph would still think that the objects are there.
					yield return new WaitForEndOfFrame();
					GraphUpdateObject guo = new GraphUpdateObject(b);
					AstarPath.active.UpdateGraphs(guo);
					if (direct) {
						AstarPath.active.FlushGraphUpdates();
					}
				}
			}
		}
	}
}
