
#ifdef USING_PCH
#	include "pch.h"
#else
#ifdef HAVE_CONFIG_H
#	include <config.h>
#endif

#include "dialog_workspaces.h"

#include "gui/resourcehelper.h"
#include "gui/localization.h"
#include "gui/app.h"
#include "gui/workspacehandler.h"

#include <synfig/general.h>

#include <glibmm/fileutils.h>
#include <glibmm/markup.h>
#include <gtkmm/treeview.h>
#include <gtkmm/liststore.h>
#include <gtkmm/messagedialog.h>

#endif

using namespace studio;

static Glib::RefPtr<Gtk::Builder> load_interface() {
	auto refBuilder = Gtk::Builder::create();
	try
	{
		refBuilder->add_from_file(ResourceHelper::get_ui_path("dialog_workspaces.ui"));
	}
	catch(const Glib::FileError& ex)
	{
		synfig::error("FileError: " + ex.what());
		return Glib::RefPtr<Gtk::Builder>();
	}
	catch(const Glib::MarkupError& ex)
	{
		synfig::error("MarkupError: " + ex.what());
		return Glib::RefPtr<Gtk::Builder>();
	}
	catch(const Gtk::BuilderError& ex)
	{
		synfig::error("BuilderError: " + ex.what());
		return Glib::RefPtr<Gtk::Builder>();
	}
	return refBuilder;
}

class WorkspaceCols: public Gtk::TreeModel::ColumnRecord {
    public:
        WorkspaceCols() {
            this->add(this->col_name);
        }

        Gtk::TreeModelColumn<Glib::ustring> col_name;
};

Dialog_Workspaces::Dialog_Workspaces(Gtk::Dialog::BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refGlade) :
	Gtk::Dialog(cobject),
	builder(refGlade),
	rename_button(nullptr),
	delete_button(nullptr)
{
	Gtk::Button *button = nullptr;

	refGlade->get_widget("workspaces_close_button", button);
	if (button)
		button->signal_clicked().connect(sigc::mem_fun(*this, &Gtk::Dialog::close));

	refGlade->get_widget("workspaces_delete_button", delete_button);
	if (delete_button)
		delete_button->signal_clicked().connect(sigc::mem_fun(*this, &Dialog_Workspaces::on_delete_clicked));

	refGlade->get_widget("workspaces_rename_button", rename_button);
	if (rename_button)
		rename_button->signal_clicked().connect(sigc::mem_fun(*this, &Dialog_Workspaces::on_rename_clicked));

	Gtk::TreeView * workspace_treeview = nullptr;
	refGlade->get_widget("workspaces_treeview", workspace_treeview);
	if (workspace_treeview) {
		current_selection = workspace_treeview->get_selection();
		current_selection->signal_changed().connect(sigc::mem_fun(*this, &Dialog_Workspaces::on_selection_changed));

		workspace_model = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(
					refGlade->get_object("workspaces_liststore")
				);
//		WorkspaceCols ws_cols;
//		Gtk::TreeModel::Row row = *workspace_model->append();
//		row[ws_cols.col_name] = "ui";
//		workspace_model->append()->set_value(0, Glib::ustring("ui"));

		App::signal_custom_workspaces_changed().connect(sigc::mem_fun(*this, &Dialog_Workspaces::rebuild_list));

		rebuild_list();
	}
}

Dialog_Workspaces* Dialog_Workspaces::create(Gtk::Window& parent)
{
	auto refBuilder = load_interface();
	if (!refBuilder)
		return nullptr;
	Dialog_Workspaces * dialog = nullptr;
	refBuilder->get_widget_derived("dialog_workspaces", dialog);
	if (dialog) {
		dialog->set_transient_for(parent);
	}
	return dialog;
}

Dialog_Workspaces::~Dialog_Workspaces()
{

}

void Dialog_Workspaces::on_selection_changed()
{
	int count = current_selection->count_selected_rows();
	rename_button->set_sensitive(count == 1);
	delete_button->set_sensitive(count > 0);
}

void Dialog_Workspaces::on_delete_clicked()
{
	char msg[256];
	snprintf(msg, 255, _("Are you sure you want to delete %d workspaces?"), current_selection->count_selected_rows());
	Gtk::MessageDialog confirm_dlg(*this, msg, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, true);
	if (confirm_dlg.run() == Gtk::RESPONSE_NO)
		return;

	// get_selected_rows() return TreePath not TreeIter
	// So, deleting an item, invalidates the other TreePaths (they point to wrong items)
	std::vector<std::string> names;
	for (auto selected_path : current_selection->get_selected_rows()) {
		std::string name;
		workspace_model->get_iter(selected_path)->get_value(0, name);
		names.push_back(name);
	}
	for (const std::string & name : names) {
		App::get_workspace_handler()->remove_workspace(name);
	}
}

void Dialog_Workspaces::on_rename_clicked()
{
	std::string old_name;
	auto selected_path = current_selection->get_selected_rows()[0];
	workspace_model->get_iter(selected_path)->get_value(0, old_name);

	Gtk::MessageDialog dialog(*this, _("Type a name for this custom workspace:"), false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_NONE, true);
	dialog.add_button(_("Cancel"), Gtk::RESPONSE_CANCEL);
	Gtk::Button * ok_button = dialog.add_button(_("Ok"), Gtk::RESPONSE_OK);
	ok_button->set_sensitive(false);

	Gtk::Entry * name_entry = Gtk::manage(new Gtk::Entry());
	name_entry->set_margin_left(16);
	name_entry->set_margin_right(16);
	name_entry->signal_changed().connect([&](){
		std::string name = name_entry->get_text();
		WorkspaceHandler::trim_string(name);
		bool has_equal_sign = name.find("=") != std::string::npos;
		ok_button->set_sensitive(!name.empty() && !has_equal_sign);
		if (ok_button->is_sensitive())
			ok_button->grab_default();
	});
	name_entry->signal_activate().connect(sigc::mem_fun(*ok_button, &Gtk::Button::clicked));
	name_entry->set_text(old_name);

	dialog.get_content_area()->set_spacing(12);
	dialog.get_content_area()->add(*name_entry);

	ok_button->set_can_default(true);

	dialog.show_all();

	int response = dialog.run();
	if (response == Gtk::RESPONSE_CANCEL)
		return;

	std::string name = name_entry->get_text();
	WorkspaceHandler::trim_string(name);

	if (old_name == name)
		return;

	if (App::get_workspace_handler()->has_workspace(name)) {
		Gtk::MessageDialog error_dlg(dialog, _("There is already a workspace with this name."), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
		error_dlg.run();
		return;
	}

	std::string tpl;
	App::get_workspace_handler()->get_workspace(old_name, tpl);
	App::get_workspace_handler()->remove_workspace(old_name);
	App::get_workspace_handler()->add_workspace(name, tpl);
}

void Dialog_Workspaces::rebuild_list()
{
	workspace_model->clear();

	WorkspaceHandler *workspaces = App::get_workspace_handler();
	std::vector<std::string> names;
	workspaces->get_name_list(names);
	for (const std::string & name : names)
		workspace_model->append()->set_value(0, name);
}
