/*
 * Copyright (C) 2025 Paul Davis <paul@linuxaudiosystems.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <glibmm/fileutils.h>

#include "pbd/types_convert.h"
#include "pbd/error.h"
#include "pbd/xml++.h"

#include "ardour/types_convert.h"

#include "editing_convert.h"
#include "region_ui_settings.h"

#include "pbd/i18n.h"

using namespace PBD;
using namespace Editing;

RegionUISettings::RegionUISettings ()
	: grid_type (GridTypeBeat)
	, samples_per_pixel (2048)
	, follow_playhead (true)
	, play_selection (true)
	, snap_mode (Editing::SnapMagnetic)
	, zoom_focus (ZoomFocusLeft)
	, mouse_mode (MouseContent)
	, note_mode (ARDOUR::Sustained)
	, x_origin (0)
	, recording_length (1, 0, 0)
	, color_mode (ARDOUR::MeterColors)
	, automation (nullptr)
	, width (-1)
	, height (-1)
	, x (-1)
	, y (-1)
	, draw_length (Editing::GridTypeBeat)
	, draw_velocity (64)
	, channel (0)
	, note_min (32)
	, note_max (96)
	, inspector_visible (false)
{
}

RegionUISettings::RegionUISettings (RegionUISettings const & other)
{
	*this = other;
}

RegionUISettings&
RegionUISettings::operator= (RegionUISettings const & other)
{
	grid_type = other.grid_type;
	samples_per_pixel = other.samples_per_pixel;
	follow_playhead = other.follow_playhead;
	play_selection = other.play_selection;
	snap_mode = other.snap_mode;
	zoom_focus = other.zoom_focus;
	mouse_mode = other.mouse_mode;
	note_mode = other.note_mode;
	x_origin = other.x_origin;
	recording_length = other.recording_length;
	color_mode = other.color_mode;
	width = other.width;
	height = other.height;
	x = other.x;
	y = other.y;
	draw_length = other.draw_length;
	draw_velocity = other.draw_velocity;
	channel = other.channel;
	note_min = other.note_min;
	note_max = other.note_max;
	inspector_visible = other.inspector_visible;
	
	if (other.automation) {
		automation.reset (new XMLNode (*other.automation));
	} else {
		automation.reset ();
	}

	return *this;
}

XMLNode&
RegionUISettings::get_state () const
{
	XMLNode* node = new XMLNode (X_("RegionUISetting"));
	node->set_property (X_("grid-type"), grid_type);
	node->set_property (X_("samples-per-pixel"), samples_per_pixel);
	node->set_property (X_("follow-playhead"), follow_playhead);
	node->set_property (X_("play-selection"), play_selection);
	node->set_property (X_("snap-mode"), snap_mode);
	node->set_property (X_("zoom-focus"), zoom_focus);
	node->set_property (X_("mouse-mode"), mouse_mode);
	node->set_property (X_("note-mode"), note_mode);
	node->set_property (X_("x-origin"), x_origin);
	node->set_property (X_("recording_length"), recording_length);
	node->set_property (X_("color-mode"), color_mode);

	if (automation) {
		node->add_child_copy (*automation);
	}

	node->set_property (X_("draw-length"), draw_length);
	node->set_property (X_("draw-velocity"), draw_velocity);
	node->set_property (X_("channel"), channel);
	node->set_property (X_("note-min"), note_min);
	node->set_property (X_("note-max"), note_max);
	node->set_property (X_("inspector-visible"), inspector_visible);

	node->set_property (X_("width"), width);
	node->set_property (X_("height"), height);
	node->set_property (X_("x"), x);
	node->set_property (X_("y"), y);

	return *node;
}

int
RegionUISettings::set_state (XMLNode const & state, int)
{
	if (state.name() != X_("RegionUISetting")) {
		return -1;
	}
	state.get_property (X_("grid-type"), grid_type);
	state.get_property (X_("samples-per-pixel"), samples_per_pixel);
	state.get_property (X_("follow-playhead"), follow_playhead);
	state.get_property (X_("play-selection"), play_selection);
	state.get_property (X_("snap-mode"), snap_mode);
	state.get_property (X_("zoom-focus"), zoom_focus);
	state.get_property (X_("mouse-mode"), mouse_mode);
	state.get_property (X_("note-mode"), note_mode);
	state.get_property (X_("x-origin"), x_origin);
	state.get_property (X_("recording_length"), recording_length);
	state.get_property (X_("color-mode"), color_mode);

	XMLNode* automation_node = state.child (X_("lanes"));
	if (automation_node) {
		automation.reset (new XMLNode (*automation_node));
	}

	state.get_property (X_("draw-length"), draw_length);
	state.get_property (X_("draw-velocity"), draw_velocity);
	state.get_property (X_("channel"), channel);
	state.get_property (X_("note-min"), note_min);
	state.get_property (X_("note-max"), note_max);
	state.get_property (X_("width"), width);
	state.get_property (X_("height"), height);
	state.get_property (X_("x"), x);
	state.get_property (X_("y"), y);
	state.get_property (X_("inspector-visible"), inspector_visible);

	return 0;
}

XMLNode&
RegionUISettingsManager::get_state () const
{
	XMLNode* node = new XMLNode (X_("RegionUISettings"));
	for (auto & [id,settings] : *this) {
		XMLNode& n (settings.get_state());
		n.set_property (X_("id"), id);
		node->add_child_nocopy (n);
	}
	return *node;
}

int
RegionUISettingsManager::set_state (XMLNode const & state, int version)
{
	if (state.name() != X_("RegionUISettings")) {
		return -1;
	}

	RegionUISettings rus;
	PBD::ID id;

	clear ();

	for (auto & child : state.children()) {
		if (rus.set_state (*child, version)) {
			return -1;
		}
		child->get_property (X_("id"), id);
		insert (std::make_pair (id, rus));
	}

	return 0;
}

void
RegionUISettingsManager::save (std::string const & path)
{
	XMLTree state_tree;

	state_tree.set_root (&get_state());
	state_tree.set_filename (path);

	if (!state_tree.write()) {
		error << string_compose (_("Could not save region GUI settings to %1"), path) << endmsg;
	}
}

int
RegionUISettingsManager::load (std::string const & xmlpath)
{
	XMLTree state_tree;

	clear ();

	if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
		return -1;
	}

	if (!state_tree.read (xmlpath)) {
		return -1;
	}

	XMLNode const & root (*state_tree.root());

	if (root.name() != X_("RegionUISettings")) {
		return -1;
	}

	for (auto const & node : root.children()) {
		RegionUISettings rsu;
		PBD::ID id;
		node->get_property ("id", id);

		if (rsu.set_state (*node, 0) == 0) {
			insert (std::make_pair (id, rsu));
		}
	}

	return 0;
}
