/**
 *	This script demonstrates how to create a new action that can be accessed from the 
 *	ProBuilder toolbar.
 *
 *	A new menu item is registered under "Geometry" actions called "Make Double-Sided".
 *	
 *	To enable, remove the #if PROBUILDER_API_EXAMPLE and #endif directives.
 */

// Uncomment this line to enable the menu action.
// #define PROBUILDER_API_EXAMPLE

#if PROBUILDER_API_EXAMPLE

using UnityEngine;
using UnityEditor;
using ProBuilder2.Common;
using ProBuilder2.EditorCommon;
using ProBuilder2.Interface;
using System.Linq;
using System.Collections.Generic;

namespace MySpecialNamespace.Actions
{
	/**
	 *	This class is responsible for loading the pb_MenuAction into the toolbar and menu.
	 */
	[InitializeOnLoad]
	static class RegisterCustomAction
	{
		/**
		 *	Static initializer is called when Unity loads the assembly.
		 */
		static RegisterCustomAction()
		{
			// This registers a new MakeFacesDoubleSided menu action with the toolbar.
			pb_EditorToolbarLoader.RegisterMenuItem(InitCustomAction);
		}

		/**
		 *	Helper function to load a new menu action object.
		 */
		static pb_MenuAction InitCustomAction()
		{
			return new MakeFacesDoubleSided();
		}

		/**
		 *	Usually you'll want to add a menu item entry for your action.
		 * 	https://docs.unity3d.com/ScriptReference/MenuItem.html
		 */
		[MenuItem("Tools/ProBuilder/Geometry/Make Faces Double-Sided", true)]
		static bool MenuVerifyDoSomethingWithPbObject()
		{
			// Using pb_EditorToolbarLoader.GetInstance keeps MakeFacesDoubleSided as a singleton.
			MakeFacesDoubleSided instance = pb_EditorToolbarLoader.GetInstance<MakeFacesDoubleSided>();
			return instance != null && instance.IsEnabled();
		}

		[MenuItem("Tools/ProBuilder/Geometry/Make Faces Double-Sided", false, pb_Constant.MENU_GEOMETRY + 3)]
		static void MenuDoDoSomethingWithPbObject()
		{
			MakeFacesDoubleSided instance = pb_EditorToolbarLoader.GetInstance<MakeFacesDoubleSided>();

			if(instance != null)
				pb_EditorUtility.ShowNotification(instance.DoAction().notification);
		}
	}

	/**
	 *	This is the actual action that will be executed.
	 */
	public class MakeFacesDoubleSided : pb_MenuAction
	{
		public override pb_ToolbarGroup group { get { return pb_ToolbarGroup.Geometry; } }
		public override Texture2D icon { get { return null; } }
		public override pb_TooltipContent tooltip { get { return _tooltip; } }

		/**
		 *	What to show in the hover tooltip window.  pb_TooltipContent is similar to GUIContent, with the exception that it also
		 *	includes an optional params[] char list in the constructor to define shortcut keys (ex, CMD_CONTROL, K).
		 */
		static readonly pb_TooltipContent _tooltip = new pb_TooltipContent
		(
			"Set Double-Sided",
			"Adds another face to the back of the selected faces."
		);

		/**
		 *	Determines if the action should be enabled or grayed out.
		 */
		public override bool IsEnabled()
		{
			// `selection` is a helper property on pb_MenuAction that returns a pb_Object[] array from the current selection.
			return 	pb_Editor.instance != null &&
					selection != null &&
					selection.Length > 0 &&
					selection.Any(x => x.SelectedFaceCount > 0);
		}

		/**
		 *	Determines if the action should be loaded in the menu (ex, face actions shouldn't be shown when in vertex editing mode).
		 */
		public override bool IsHidden()
		{
			return 	pb_Editor.instance == null ||
					pb_Editor.instance.editLevel != EditLevel.Geometry ||
					pb_Editor.instance.selectionMode != SelectMode.Face;
		}

		/**
		 *	Do the thing.  Return a pb_ActionResult indicating the success/failure of action.
		 */
		public override pb_ActionResult DoAction()
		{
			pbUndo.RecordObjects(selection, "Make Double-Sided Faces");

			foreach(pb_Object pb in selection)
			{
				List<pb_FaceRebuildData> rebuild = new List<pb_FaceRebuildData>();
				List<pb_Vertex> vertices = new List<pb_Vertex>(pb_Vertex.GetVertices(pb));
				Dictionary<int, int> lookup = pb.sharedIndices.ToDictionary();

				foreach(pb_Face face in pb.SelectedFaces)
				{
					pb_FaceRebuildData data = new pb_FaceRebuildData();

					data.vertices = new List<pb_Vertex>();
					data.face = new pb_Face(face);
					data.sharedIndices = new List<int>();

					Dictionary<int, int> map = new Dictionary<int, int>();
					int len = data.face.indices.Length;

					for(int i = 0; i < len; i++)
					{
						if(map.ContainsKey(face.indices[i]))
							continue;

						map.Add(face.indices[i], map.Count);
						data.vertices.Add(vertices[face.indices[i]]);
						data.sharedIndices.Add(lookup[face.indices[i]]);
					}

					for(int i = 0; i < len; i++)
						data.face.indices[i] = map[data.face.indices[i]];

					data.face.ReverseIndices();
					rebuild.Add(data);
				}

				pb_FaceRebuildData.Apply(rebuild, pb, vertices, null, lookup, null);
				pb.ToMesh();
				pb.Refresh();
				pb.Optimize();
			}

			// This is necessary!  Otherwise the pb_Editor will be working with caches from
			// outdated meshes and throw errors.
			pb_Editor.Refresh();
			
			return new pb_ActionResult(Status.Success, "Make Faces Double-Sided");
		}
	}
}
#endif

