/*
 * Copyright (c) 2012-2025 Daniele Bartolini et al.
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

namespace Crown
{
public class ObjectEditor : Gtk.ApplicationWindow
{
	public DatabaseEditor _database_editor;
	public Database _database;
	public ObjectTree _objects_tree;
	public ObjectProperties _objects_properties;
	public Gtk.Paned _paned;
	public Statusbar _statusbar;

	public Gtk.Button _cancel;
	public Gtk.Button _save;
	public Gtk.HeaderBar _header_bar;
	public Gtk.Box _box;

	public string _object_name;
	public Guid _object_id;

	public signal void saved();

	public ObjectEditor(Gtk.Application application
		, Project project
		, uint32 undo_redo_size
		)
	{
		Object(application: application);

		_object_id = GUID_ZERO;

		_database_editor = new DatabaseEditor(project, undo_redo_size);
		_database_editor.undo.connect(on_undo);
		_database_editor.redo.connect(on_redo);
		this.insert_action_group("database", _database_editor._action_group);

		_database = _database_editor._database;
		_database.objects_created.connect(on_objects_created);
		_database.objects_destroyed.connect(on_objects_destroyed);
		_database.objects_changed.connect(on_objects_changed);

		_objects_tree = new ObjectTree(_database_editor);
		_objects_properties = new ObjectProperties(_database_editor);

		_database_editor.load_types();

		_statusbar = new Statusbar();

		_cancel = new Gtk.Button.with_label("Cancel");
		_cancel.clicked.connect(() => {
				close();
			});
		_save = new Gtk.Button.with_label("Save & Reload");
		_save.get_style_context().add_class("suggested-action");
		_save.clicked.connect(save);

		_header_bar = new Gtk.HeaderBar();
		_header_bar.title = "Object Editor";
		_header_bar.show_close_button = true;
		_header_bar.pack_start(_cancel);
		_header_bar.pack_end(_save);

		_paned = new Gtk.Paned(Gtk.Orientation.HORIZONTAL);
		_paned.pack1(_objects_tree, true, false);
		_paned.pack2(_objects_properties, true, false);

		this.set_titlebar(_header_bar);
		this.set_size_request(1000, 600);

		int win_w;
		int win_h;
		this.get_size(out win_w, out win_h);
		_paned.set_position(win_w/2);

		GLib.Menu menu = new GLib.Menu();
		GLib.MenuItem mi = null;

		mi = new GLib.MenuItem("Edit", null);
		mi.set_submenu(make_database_editor_menu());
		menu.append_item(mi);

		this.show_menubar = false;
		Gtk.MenuBar menubar = new Gtk.MenuBar.from_model(menu);

		_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
		_box.pack_start(menubar, false);
		_box.pack_start(_paned);
		_box.pack_start(_statusbar, false);

		this.delete_event.connect(on_close_request);
		this.add(_box);

		reset();
	}

	public void update_window_title()
	{
		string title = "";

		if (_database.changed())
			title += " • ";

		title += _object_id == GUID_ZERO ? "unnamed" : _object_name;
		title += " - ";
		title += CROWN_EDITOR_NAME;

		if (this.title != title)
			this.title = title;
	}

	public void reset()
	{
		_database.reset();
		_object_name = "";
		_object_id = GUID_ZERO;
	}

	public void save()
	{
		assert(_object_id != GUID_ZERO);

		ObjectTypeInfo info = _database.type_info(StringId64(_database.object_type(_object_id)));
		if (_database.save(_database._project.absolute_path(_object_name) + "." + info.name, _object_id) == 0)
			saved();
	}

	public void on_objects_created(Guid?[] object_ids, uint32 flags)
	{
		Guid last_created = object_ids[object_ids.length - 1];

		_objects_tree.set_object(_object_id); // Force update the tree.
		_database_editor.selection_set({ last_created }); // Select the objects just created.
		update_window_title();
	}

	public void on_objects_destroyed(Guid?[] object_ids, uint32 flags = 0)
	{
		_objects_tree.set_object(_object_id); // Force update the tree.
		_database_editor.selection_set({ _object_id }); // Select the root object which must always exits.
		update_window_title();
	}

	public void on_objects_changed(Guid?[] object_ids, uint32 flags = 0)
	{
		Guid last_changed = object_ids[object_ids.length - 1];

		_objects_tree.set_object(_object_id); // Force update the tree.
		_database_editor.selection_set({ last_changed });
		update_window_title();
	}

	public void do_set_object(string type, string name)
	{
		reset();

		string resource_path = ResourceId.path(type, name);
		string path = _database._project.absolute_path(resource_path);

		if (_database.load_from_path(out _object_id, path, resource_path) != 0)
			return;

		_object_name = name;
		_objects_tree.set_object(_object_id);
		_database_editor.selection_set({ _object_id });
		update_window_title();
	}

	public void set_object(string type, string name)
	{
		if (_object_name == name)
			return;

		if (!_database.changed()) {
			this.do_set_object(type, name);
		} else {
			Gtk.Dialog dlg = new_resource_changed_dialog(this, _object_name);
			dlg.response.connect((response_id) => {
					if (response_id == Gtk.ResponseType.NO) {
						this.do_set_object(type, name);
					} else if (response_id == Gtk.ResponseType.YES) {
						this.save();
						this.do_set_object(type, name);
					}
					dlg.destroy();
				});
			dlg.show_all();
		}
	}

	public void on_objects_tree_selection_changed(Guid?[] objects)
	{
		_database_editor.selection_read(objects);
	}

	public void on_undo(int action_id)
	{
		_statusbar.set_temporary_message("Undo: " + ActionNames[action_id]);
	}

	public void on_redo(int action_id)
	{
		_statusbar.set_temporary_message("Redo: " + ActionNames[action_id]);
	}

	public bool on_close_request(Gdk.EventAny event)
	{
		this.hide();
		return Gdk.EVENT_STOP;
	}
}

} /* namespace Crown */
