/*
* SACD Decoder plugin
* Copyright (c) 2011-2023 Maxim V.Anisiutkin <maxim.anisiutkin@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifndef _SACD_PREFERENCES_H_INCLUDED
#define _SACD_PREFERENCES_H_INCLUDED

#include <helpers/foobar2000+atl.h>
#include <helpers/atl-misc.h>
#include <helpers/DarkMode.h>
#include "libPPUI/Controls.h"
#include "resource.h"

#include "sacd_config.h"
#include "autoproxy_output.h"

GUID xor_guids(const GUID& p_guid1, const GUID& p_guid2);

class cfg_dsddsp_entry_t {
public:
	GUID    m_guid;
	string8 m_name;
	cfg_dsddsp_entry_t() {
		m_guid = GUID_NULL;
	}
	cfg_dsddsp_entry_t(const GUID p_guid, const char* p_name) {
		m_guid = p_guid;
		m_name = p_name;
	}
};

class cfg_output_entry_t {
public:
	GUID     m_guid;
	unsigned m_type;
	unsigned m_samplerate;
	float    m_vol_adjust;
	unsigned m_lfe_adjust;
	float    m_transition;
	cfg_output_entry_t() : m_guid(GUID_NULL), m_type(0), m_samplerate(0), m_vol_adjust(+6.0f), m_lfe_adjust(1), m_transition(0.0f) {
	}
	cfg_output_entry_t(const cfg_output_entry_t& p_src) {
		m_guid       = p_src.m_guid;
		m_type       = p_src.m_type;
		m_samplerate = p_src.m_samplerate;
		m_vol_adjust = p_src.m_vol_adjust;
		m_lfe_adjust = p_src.m_lfe_adjust;
		m_transition = p_src.m_transition;
	}
	cfg_output_entry_t& operator=(const cfg_output_entry_t& p_src) {
		m_guid       = p_src.m_guid;
		m_type       = p_src.m_type;
		m_samplerate = p_src.m_samplerate;
		m_vol_adjust = p_src.m_vol_adjust;
		m_lfe_adjust = p_src.m_lfe_adjust;
		m_transition = p_src.m_transition;
		return *this;
	}
	bool operator==(const cfg_output_entry_t& p_src) {
		return
			m_guid == p_src.m_guid &&
			m_type == p_src.m_type &&
			m_samplerate == p_src.m_samplerate &&
			m_vol_adjust == p_src.m_vol_adjust &&
			m_lfe_adjust == p_src.m_lfe_adjust &&
			m_transition == p_src.m_transition;
	}
	bool operator!=(const cfg_output_entry_t& p_src) {
		return !(*this == p_src);
	}
};

FB2K_STREAM_READER_OVERLOAD(cfg_output_entry_t) {
	cfg_output_entry_t temp;
	stream >> temp.m_guid;
	stream >> temp.m_type;
	stream >> temp.m_samplerate;
	stream >> temp.m_vol_adjust;
	stream >> temp.m_lfe_adjust;
	stream >> temp.m_transition;
	value = temp;
	return stream;
}

FB2K_STREAM_WRITER_OVERLOAD(cfg_output_entry_t) {
	stream << value.m_guid;
	stream << value.m_type;
	stream << value.m_samplerate;
	stream << value.m_vol_adjust;
	stream << value.m_lfe_adjust;
	stream << value.m_transition;
	return stream;
}

class CSACDPreferences : public CDialogImpl<CSACDPreferences>, public preferences_page_instance {
	static CSACDPreferences*  s_this;
	static cfg_output_entry_t s_output;
public:
	static void load();
	static void save();
	static void update();
	static bool use_dsd_path();
	static bool use_pcm_path();
	static cfg_output_entry_t& get_output();
	static int get_output_type();
	static int get_samplerate();
	static float get_vol_adjust();
	static float get_lfe_adjust();
	static float get_transition();
	static int get_converter_mode();
	static int get_decimation();
	static cfg_objList<double>& get_user_fir();
	static bool get_log_overloads();
	static float get_ramp();
	static GUID get_dsd_processor();
	static int get_area();
	static bool get_editable_tags();
	static bool get_store_tags_with_iso();
	static bool get_linked_tags();
	static bool get_emaster();
	static bool get_std_tags();
	static bool get_dop_for_converter();
	static bool get_trace();
	static int get_converter_thread_count();

	CSACDPreferences(preferences_page_callback::ptr callback);
	~CSACDPreferences();

	enum {IDD = IDD_SACD_PREFERENCES};

	t_uint32 get_state();
	void apply();
	void reset();

	BEGIN_MSG_MAP(CSACDPreferences)
		MSG_WM_INITDIALOG(OnInitDialog)
		MSG_WM_ACTIVATE(OnActivate)
		MSG_WM_DESTROY(OnDestroy)
		COMMAND_HANDLER_EX(IDC_OUTPUT_TYPE_COMBO, CBN_SELCHANGE, OnOutputTypeChange)
		COMMAND_HANDLER_EX(IDC_DOP_FOR_CONVERTER, BN_CLICKED, OnDoPForConverterClicked)
		COMMAND_HANDLER_EX(IDC_VOLUME_ADJ_COMBO, CBN_SELCHANGE, OnVolumeAdjustChange)
		COMMAND_HANDLER_EX(IDC_VOLUME_ADJ_COMBO, CBN_EDITUPDATE, OnVolumeAdjustChange)
		COMMAND_HANDLER_EX(IDC_LFE_ADJ_COMBO, CBN_SELCHANGE, OnLFEAdjustChange)
		COMMAND_HANDLER_EX(IDC_TRANSITION_COMBO, CBN_SELCHANGE, OnTransitionChange)
		COMMAND_HANDLER_EX(IDC_TRANSITION_COMBO, CBN_EDITUPDATE, OnTransitionChange)
		COMMAND_HANDLER_EX(IDC_RAMP_COMBO, CBN_SELCHANGE, OnRampChange)
		COMMAND_HANDLER_EX(IDC_RAMP_COMBO, CBN_EDITUPDATE, OnRampChange)
		COMMAND_HANDLER_EX(IDC_LOG_OVERLOADS, BN_CLICKED, OnLogOverloadsClicked)
		COMMAND_HANDLER_EX(IDC_SAMPLERATE_COMBO, CBN_SELCHANGE, OnSamplerateChange)
		COMMAND_HANDLER_EX(IDC_CONVERTER_MODE_COMBO, CBN_SELCHANGE, OnConverterModeChange)
		COMMAND_HANDLER_EX(IDC_DECIMATION_COMBO, CBN_SELCHANGE, OnDecimationChange)
		COMMAND_HANDLER_EX(IDC_LOAD_FIR_BUTTON, BN_CLICKED, OnLoadFirClicked)
		COMMAND_HANDLER_EX(IDC_SAVE_FIR_BUTTON, BN_CLICKED, OnSaveFirClicked)
		COMMAND_HANDLER_EX(IDC_AREA_COMBO, CBN_SELCHANGE, OnAreaChange)
		COMMAND_HANDLER_EX(IDC_EDITABLE_TAGS, BN_CLICKED, OnEditableTagsClicked)
		COMMAND_HANDLER_EX(IDC_STORE_TAGS_WITH_ISO, BN_CLICKED, OnStoreWithIsoClicked)
		COMMAND_HANDLER_EX(IDC_LINKED_TAGS, BN_CLICKED, OnLinkedTagsClicked)
		COMMAND_HANDLER_EX(IDC_EMASTER, BN_CLICKED, OnEMasterClicked)
		COMMAND_HANDLER_EX(IDC_STD_TAGS, BN_CLICKED, OnStdTagsClicked)
		COMMAND_HANDLER_EX(IDC_DSD_PROCESSOR_COMBO, CBN_SELCHANGE, OnDSDDSPChange)
		COMMAND_HANDLER_EX(IDC_TRACE, BN_CLICKED, OnTraceClicked)
	END_MSG_MAP()

private:

	void update_UI();
	HFONT create_separator_font();
	static void translate_string(const char* p_inp, array_t<TCHAR>& p_out);
	t_size get_dsddsp_item_by_guid(GUID p_guid);
	GUID get_dsddsp_guid_by_item(t_size p_item);
	BOOL OnInitDialog(CWindow, LPARAM);
	void OnActivate(UINT, int, CWindow);
	void OnDestroy();
	void OnOutputTypeChange(UINT, int, CWindow);
	void OnDoPForConverterClicked(UINT, int, CWindow);
	void OnVolumeAdjustChange(UINT, int, CWindow);
	void OnLFEAdjustChange(UINT, int, CWindow);
	void OnTransitionChange(UINT, int, CWindow);
	void OnRampChange(UINT, int, CWindow);
	void OnLogOverloadsClicked(UINT, int, CWindow);
	void OnSamplerateChange(UINT, int, CWindow);
	void OnConverterModeChange(UINT, int, CWindow);
	void OnDecimationChange(UINT, int, CWindow);
	void OnLoadFirClicked(UINT, int, CWindow);
	void OnSaveFirClicked(UINT, int, CWindow);
	void OnAreaChange(UINT, int, CWindow);
	void OnEditableTagsClicked(UINT, int, CWindow);
	void OnStoreWithIsoClicked(UINT, int, CWindow);
	void OnLinkedTagsClicked(UINT, int, CWindow);
	void OnEMasterClicked(UINT, int, CWindow);
	void OnStdTagsClicked(UINT, int, CWindow);
	void OnDSDDSPChange(UINT, int, CWindow);
	void OnTraceClicked(UINT, int, CWindow);
	bool HasChanged();
	void OnChanged();
	void GetOutputModeList();
	void GetVolumeList();
	void GetLFEAdjustList();
	void GetTransitionList();
	void GetRampList();
	void GetSamplerateList();
	void GetConverterModeList();
	void GetDecimationList();
	void GetAreaList();
	void GetDSDDSPList();
	void SetOutputControls();
	void SetUserFirState();
	float GetDlgItemFloatValue(int dlgId, float value, float minValue, float maxValue);
	void SetDlgItemFloatValue(int dlgId, float value, bool forceSign);

	array_t<cfg_dsddsp_entry_t> m_dsddsps;
	const preferences_page_callback::ptr m_callback;
	HFONT      m_separator_font;
	CSeparator m_separator1;
	CSeparator m_separator2;
	CSeparator m_separator3;
	CSeparator m_separator4;
	fb2k::CDarkModeHooks m_dark;
};

class preferences_page_sacd_t : public preferences_page_impl<CSACDPreferences> {
public:
	const char* get_name();
	GUID get_guid();
	GUID get_parent_guid();
};

#endif
