//  Copyright (c) 2026 Jakub Filipowicz <jakubf@gmail.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

#ifndef CONFIGCONTROLLER_H
#define CONFIGCONTROLLER_H

#include <QObject>
#include <QString>

struct appcfg;
struct appcfg_machine;
class EmuModel;

// Owns the configuration <-> live-machine relationship: edits appcfg (the source
// of truth) and drives EmuModel to make the running machine match. EmuModel stays
// the live facade; this is the policy layer above it. Power-cycle on cold change,
// machine switch and persistence land here in later steps.
class ConfigController : public QObject
{
	Q_OBJECT

public:
	ConfigController(struct appcfg *cfg, EmuModel *emu) : cfg(cfg), emu(emu) {}

	bool is_powered() const;

	// drive the live buzzer volume without touching appcfg (preview); the working
	// copy holds the value for commit, the dialog snapshots the original to revert
	void preview_volume(int volume);

	// Commit a dialog's working copy: write it to the config file (the commit
	// point - on write failure nothing else changes), then overwrite appcfg,
	// apply live removable-media swaps and volume. Returns false on failure.
	bool apply_and_save(const struct appcfg *work);

	// Immediate media swap (Devices menu): mutate appcfg, apply the live swap when
	// the device permits it, and persist now - a per-op auto-save, deliberately
	// distinct from the dialog's buffered OK-commit path. No-op when nothing
	// changes. Empty path ejects.
	void set_disk_image(unsigned chan, unsigned dev, unsigned slot, const QString &path);

	// Switch the active machine (panel context menu): only meaningful while powered
	// off, since the choice takes effect at the next power-on. Mutates appcfg and
	// persists now. No-op when powered, unchanged, or the id is unknown.
	void set_active_machine(const QString &id);

signals:
	// a menu swap landed; an open config dialog routes it into its working copy so
	// OK cannot clobber it with a stale value. Empty path means ejected.
	void media_changed(unsigned chan, unsigned dev, unsigned slot, QString path);

	// the active machine switched from the menu; an open config dialog syncs its
	// working copy so OK cannot revert to the previously active machine
	void active_machine_changed(QString id);

private:
	struct appcfg *cfg;
	EmuModel *emu;
};

#endif // CONFIGCONTROLLER_H

// vim: tabstop=4 shiftwidth=4 autoindent
