# toolbar_menu.gd
# This file is part of: SimpleGrassTextured
# Copyright (c) 2023 IcterusGames
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the 
# "Software"), to deal in the Software without restriction, including 
# without limitation the rights to use, copy, modify, merge, publish, 
# distribute, sublicense, and/or sell copies of the Software, and to 
# permit persons to whom the Software is furnished to do so, subject to 
# the following conditions: 
#
# The above copyright notice and this permission notice shall be 
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@tool
extends MenuButton

enum MENU_ID {
	TOOL_FOLLOW_NORMAL,
	TOOL_SHAPE_AIRBRUSH,
	TOOL_SHAPE_PENCIL,
	TOOL_SHAPE_ERASER,
	TOOL_SNAP_TO_TERRAIN,
	AUTO_CENTER_POSITION,
	CAST_SHADOW,
	BAKE_HEIGHT_MAP,
	GLOBAL_PARAMETERS,
	CLEAR_ALL,
	HELP_ABOUT,
	RECALCULATE_AABB,
}

enum MENU_SHAPE_ID {
	TOOL_SHAPE_SPHERE,
	TOOL_SHAPE_CYLINDER,
	TOOL_SHAPE_CYLINDER_INF_H,
	TOOL_SHAPE_BOX,
	TOOL_SHAPE_BOX_INF_H,
}

var _plugin: EditorPlugin = null
var _grass_selected = null
var _tools_menu: PopupMenu = null
var _airbrush_shape_menu: PopupMenu = null
var _pencil_shape_menu: PopupMenu = null
var _eraser_shape_menu: PopupMenu = null


func set_plugin(plugin :EditorPlugin) -> void:
	var popup := get_popup()
	_plugin = plugin
	_airbrush_shape_menu = PopupMenu.new()
	_airbrush_shape_menu.name = &"AirbrushShapeMenu"
	_airbrush_shape_menu.add_radio_check_item("Cylinder", MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER)
	_airbrush_shape_menu.add_radio_check_item("Box", MENU_SHAPE_ID.TOOL_SHAPE_BOX)
	_pencil_shape_menu = PopupMenu.new()
	_pencil_shape_menu.name = &"PencilShapeMenu"
	_pencil_shape_menu.add_radio_check_item("Cylinder", MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER)
	_pencil_shape_menu.add_radio_check_item("Box", MENU_SHAPE_ID.TOOL_SHAPE_BOX)
	_eraser_shape_menu = PopupMenu.new()
	_eraser_shape_menu.name = &"EraserShapeMenu"
	_eraser_shape_menu.add_radio_check_item("Sphere", MENU_SHAPE_ID.TOOL_SHAPE_SPHERE)
	_eraser_shape_menu.add_radio_check_item("Cylinder", MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER)
	_eraser_shape_menu.add_radio_check_item("Infinite vertical cylinder", MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER_INF_H)
	_eraser_shape_menu.add_radio_check_item("Box", MENU_SHAPE_ID.TOOL_SHAPE_BOX)
	_eraser_shape_menu.add_radio_check_item("Infinite vertical box", MENU_SHAPE_ID.TOOL_SHAPE_BOX_INF_H)
	_tools_menu = PopupMenu.new()
	_tools_menu.add_child(_airbrush_shape_menu)
	_tools_menu.add_child(_pencil_shape_menu)
	_tools_menu.add_child(_eraser_shape_menu)
	_tools_menu.name = &"ToolsMenu"
	_tools_menu.add_check_item("Follow terrain's normal", MENU_ID.TOOL_FOLLOW_NORMAL)
	_tools_menu.add_submenu_item("Airbrush shape", "AirbrushShapeMenu")
	_tools_menu.add_submenu_item("Pencil shape", "PencilShapeMenu")
	_tools_menu.add_submenu_item("Eraser shape", "EraserShapeMenu")
	_tools_menu.add_separator()
	_tools_menu.add_item("Snap to terrain", MENU_ID.TOOL_SNAP_TO_TERRAIN)
	popup.add_child(_tools_menu)
	popup.clear()
	popup.add_submenu_item("Tools", "ToolsMenu")
	popup.add_separator()
	popup.add_item("Auto center position", MENU_ID.AUTO_CENTER_POSITION)
	popup.add_item("Recalculate custom AABB", MENU_ID.RECALCULATE_AABB)
	popup.add_item("Bake height map", MENU_ID.BAKE_HEIGHT_MAP)
	popup.add_check_item("Cast shadow", MENU_ID.CAST_SHADOW)
	popup.add_item("Global parameters", MENU_ID.GLOBAL_PARAMETERS)
	popup.add_separator()
	popup.add_item("Clear all", MENU_ID.CLEAR_ALL)
	popup.add_separator()
	popup.add_item("About SimpleGrassTextured", MENU_ID.HELP_ABOUT)
	popup.id_pressed.connect(_on_sgt_menu_button)
	_tools_menu.id_pressed.connect(_on_sgt_tools_menu_button)
	_airbrush_shape_menu.id_pressed.connect(_on_sgt_shape_menu_pressed.bind("airbrush", _airbrush_shape_menu))
	_pencil_shape_menu.id_pressed.connect(_on_sgt_shape_menu_pressed.bind("pencil", _pencil_shape_menu))
	_eraser_shape_menu.id_pressed.connect(_on_sgt_shape_menu_pressed.bind("eraser", _eraser_shape_menu))
	about_to_popup.connect(_on_about_to_popup)


func set_current_grass(grass_selected) -> void:
	_grass_selected = grass_selected
	if grass_selected == null:
		return
	var popup := get_popup()
	if grass_selected.cast_shadow == GeometryInstance3D.SHADOW_CASTING_SETTING_OFF:
		popup.set_item_checked(popup.get_item_index(MENU_ID.CAST_SHADOW), false)
	else:
		popup.set_item_checked(popup.get_item_index(MENU_ID.CAST_SHADOW), true)
	if _grass_selected.baked_height_map != null:
		popup.set_item_text(popup.get_item_index(MENU_ID.BAKE_HEIGHT_MAP), "Bake height map (already baked)")
		popup.set_item_disabled(popup.get_item_index(MENU_ID.BAKE_HEIGHT_MAP), true)
	else:
		popup.set_item_text(popup.get_item_index(MENU_ID.BAKE_HEIGHT_MAP), "Bake height map")
		popup.set_item_disabled(popup.get_item_index(MENU_ID.BAKE_HEIGHT_MAP), false)
	_tools_menu.set_item_checked(_tools_menu.get_item_index(MENU_ID.TOOL_FOLLOW_NORMAL), _grass_selected.sgt_follow_normal)
	for tool_name in _grass_selected.sgt_tool_shape:
		match tool_name:
			"airbrush":
				_update_shape_menu_from_grass(_airbrush_shape_menu, _grass_selected.sgt_tool_shape[tool_name])
			"pencil":
				_update_shape_menu_from_grass(_pencil_shape_menu, _grass_selected.sgt_tool_shape[tool_name])
			"eraser":
				_update_shape_menu_from_grass(_eraser_shape_menu, _grass_selected.sgt_tool_shape[tool_name])


func _update_shape_menu_from_grass(popupmenu: PopupMenu, plugin_id_shape: int) -> void:
	for i in popupmenu.item_count:
		popupmenu.set_item_checked(i, false)
	var idx := -1
	match _plugin.get_tool_shape_name(plugin_id_shape):
		"sphere":
			idx = popupmenu.get_item_index(MENU_SHAPE_ID.TOOL_SHAPE_SPHERE)
		"cylinder":
			idx = popupmenu.get_item_index(MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER)
		"cylinder_inf_h":
			idx = popupmenu.get_item_index(MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER_INF_H)
		"box":
			idx = popupmenu.get_item_index(MENU_SHAPE_ID.TOOL_SHAPE_BOX)
		"box_inf_h":
			idx = popupmenu.get_item_index(MENU_SHAPE_ID.TOOL_SHAPE_BOX_INF_H)
		_:
			idx = -1
	if idx == -1:
		return
	popupmenu.set_item_checked(idx, true)


func _on_sgt_menu_button(id :int) -> void:
	if _grass_selected == null:
		return
	match id:
		MENU_ID.AUTO_CENTER_POSITION:
			_plugin.get_undo_redo().create_action(_grass_selected.name + " Auto Center Position")
			_plugin.get_undo_redo().add_undo_property(_grass_selected, &"baked_height_map", _grass_selected.baked_height_map)
			_plugin.get_undo_redo().add_undo_property(_grass_selected, &"multimesh", _grass_selected.multimesh)
			_plugin.get_undo_redo().add_undo_property(_grass_selected, &"global_position", _grass_selected.global_position)
			_grass_selected.auto_center_position()
			_plugin.get_undo_redo().add_do_property(_grass_selected, &"baked_height_map", _grass_selected.baked_height_map)
			_plugin.get_undo_redo().add_do_property(_grass_selected, &"multimesh", _grass_selected.multimesh)
			_plugin.get_undo_redo().add_do_property(_grass_selected, &"global_position", _grass_selected.global_position)
			_plugin.get_undo_redo().commit_action()
		MENU_ID.RECALCULATE_AABB:
			_plugin.get_undo_redo().create_action(_grass_selected.name + " Recalculate Custom AABB")
			_plugin.get_undo_redo().add_undo_property(_grass_selected, &"custom_aabb", _grass_selected.custom_aabb)
			_grass_selected.recalculate_custom_aabb()
			_plugin.get_undo_redo().add_do_property(_grass_selected, &"custom_aabb", _grass_selected.custom_aabb)
			_plugin.get_undo_redo().commit_action()
		MENU_ID.CAST_SHADOW:
			_plugin.get_undo_redo().create_action(_grass_selected.name + " Toogle Cast Shadow")
			_plugin.get_undo_redo().add_undo_property(_grass_selected, &"cast_shadow", _grass_selected.cast_shadow)
			for child in _grass_selected.get_children():
				if child.has_meta(&"SimpleGrassTexturedRegion"):
					_plugin.get_undo_redo().add_undo_property(child, &"cast_shadow", child.cast_shadow)
			if _grass_selected.cast_shadow == GeometryInstance3D.SHADOW_CASTING_SETTING_OFF:
				_grass_selected.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_ON
			else:
				_grass_selected.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
			_plugin.get_undo_redo().add_do_property(_grass_selected, &"cast_shadow", _grass_selected.cast_shadow)
			for child in _grass_selected.get_children():
				if child.has_meta(&"SimpleGrassTexturedRegion"):
					child.cast_shadow = _grass_selected.cast_shadow
					_plugin.get_undo_redo().add_do_property(child, &"cast_shadow", child.cast_shadow)
			_plugin.get_undo_redo().commit_action()
		MENU_ID.BAKE_HEIGHT_MAP:
			_grass_selected.bake_height_map()
		MENU_ID.GLOBAL_PARAMETERS:
			var _global_parameters = load("res://addons/simplegrasstextured/gui/global_parameters.tscn").instantiate()
			get_window().add_child(_global_parameters)
			_global_parameters.popup_centered()
		MENU_ID.CLEAR_ALL:
			var win = load("res://addons/simplegrasstextured/gui/clear_all_confirmation_dialog.tscn").instantiate()
			get_window().add_child(win)
			win.confirmed.connect(_on_clear_all_confirmation_dialog_confirmed)
			win.popup_centered()
		MENU_ID.HELP_ABOUT:
			var win = load("res://addons/simplegrasstextured/gui/about.tscn").instantiate()
			get_window().add_child(win)
			win.popup_centered()


func _on_sgt_tools_menu_button(id :int) -> void:
	if _grass_selected == null:
		return
	match id:
		MENU_ID.TOOL_FOLLOW_NORMAL:
			var idx := _tools_menu.get_item_index(id)
			_tools_menu.set_item_checked(idx, not _tools_menu.is_item_checked(idx))
			_grass_selected.sgt_follow_normal = _tools_menu.is_item_checked(idx)
		MENU_ID.TOOL_SNAP_TO_TERRAIN:
			_plugin.get_undo_redo().create_action(_grass_selected.name + " Snap to terrain")
			_plugin.get_undo_redo().add_undo_property(_grass_selected, &"baked_height_map", _grass_selected.baked_height_map)
			_plugin.get_undo_redo().add_undo_property(_grass_selected, &"multimesh", _grass_selected.multimesh.duplicate())
			_plugin.get_undo_redo().add_undo_property(_grass_selected, &"global_position", _grass_selected.global_position)
			_grass_selected.snap_to_terrain()
			_plugin.get_undo_redo().add_do_property(_grass_selected, &"baked_height_map", _grass_selected.baked_height_map)
			_plugin.get_undo_redo().add_do_property(_grass_selected, &"multimesh", _grass_selected.multimesh)
			_plugin.get_undo_redo().add_do_property(_grass_selected, &"global_position", _grass_selected.global_position)
			_plugin.get_undo_redo().commit_action()


func _on_sgt_shape_menu_pressed(id: int, tool_name: String, popupmenu: PopupMenu) -> void:
	if _grass_selected == null:
		return
	for i in popupmenu.item_count:
		popupmenu.set_item_checked(i, false)
	var idx := popupmenu.get_item_index(id)
	if idx == -1:
		return
	popupmenu.set_item_checked(idx, true)
	var shape_name := ""
	match id:
		MENU_SHAPE_ID.TOOL_SHAPE_SPHERE:
			shape_name = "sphere"
		MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER:
			shape_name = "cylinder"
		MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER_INF_H:
			shape_name = "cylinder_inf_h"
		MENU_SHAPE_ID.TOOL_SHAPE_BOX:
			shape_name = "box"
		MENU_SHAPE_ID.TOOL_SHAPE_BOX_INF_H:
			shape_name = "box_inf_h"
	_plugin.set_tool_shape(tool_name, shape_name)


func _on_about_to_popup() -> void:
	set_current_grass(_grass_selected)


func _on_clear_all_confirmation_dialog_confirmed() -> void:
	if _grass_selected == null:
		return
	_plugin.get_undo_redo().create_action(_grass_selected.name + " Clear All Grass")
	_plugin.get_undo_redo().add_undo_property(_grass_selected, &"baked_height_map", _grass_selected.baked_height_map)
	_plugin.get_undo_redo().add_undo_property(_grass_selected, &"multimesh", _grass_selected.multimesh)
	_grass_selected.clear_all()
	_plugin.get_undo_redo().add_do_property(_grass_selected, &"baked_height_map", _grass_selected.baked_height_map)
	_plugin.get_undo_redo().add_do_property(_grass_selected, &"multimesh", _grass_selected.multimesh)
	_plugin.get_undo_redo().commit_action()
