// ----------------------------------------------------------------------------
// Copyright (C) 2014
//              David Freese, W1HKJ
//
// This file is part of flrig.
//
// flrig 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 3 of the License, or
// (at your option) any later version.
//
// flrig 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, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------

using namespace std;

#ifndef _HPSDR_H
#define _HPSDR_H

#include "rigbase.h"
#include "debug.h"
#include "support.h"

extern int __argc;
extern char** __argv;

#if 1
#define SELRIG_TRACK(X)
#else
#define SELRIG_TRACK(X)									\
  { fprintf(stderr, "################# %s::%s(), %s rig_nbr: %d pS.rn: %d, %p\n",	\
    __FILE__, __func__, X, rig_nbr, progStatus.rig_nbr, selrig); }
#endif // 1

#define RATE_8000	"8000"
#define RATE_48000	"48000"
#define CHNLS_MONO	"Mono"
#define CHNLS_STEREO	"Stereo"

#define ENC_ALAW	"Alaw"
#define ENC_PCM		"Pcm"
#define ENC_CODEC2	"Codec2"
#define ENC_ALAW2	"Alaw2"
#define MIC_ENC_ALAW	"Alaw"
#define MIC_ENC_CODEC2	"Codec2"

// from dspserver/audiostream.h:
#define ENCODING_ALAW		0
#define ENCODING_PCM		1
#define ENCODING_CODEC2		2
#define ENCODING_ALAW2		3
#define MIC_ENCODING_ALAW	0
#define MIC_ENCODING_CODEC2	1
#define AUDIO_BUFFER_SIZE	2000

// from DttSP/dttspagc.h:
typedef enum _agcmode
{ agcOFF, agcLONG, agcSLOW, agcMED, agcFAST } AGCMODE;

class RIG_HPSDR : public rigbase {
protected:
	int	sample_frequency;

private:
	string	sdr_address;
	string	sdr_port;

	int	sdr_frequency;
	int	sdr_receiver;
	int	sdr_filt_lo;
	int	sdr_filt_hi;

	// Extra "has_xxx_controls"
	bool	has_dither;
	bool	has_random;

	int	device_fd;  // XXX nuke this

	string  hxmit_os;
	string  hrcv_os;

	int	open_sdr();
	void	close_sdr();

	int	statusWindow(const char* msg, int level = 0);

public:
	RIG_HPSDR();
	virtual ~RIG_HPSDR() {}

	int  Open(int freq = 8000);
	void Close();

	void initialize();
	int  Write_cmd(const char *, bool answer = true);
	int  Parse_cmd(char *);

	long get_vfoA();
	void set_vfoA(long);
	long get_vfoB();
	void set_vfoB(long);

	void set_modeA(int);
	int  get_modeA() { return (modeA); } // XXX from SDR?
	void set_modeB(int);
	int  get_modeB() { return (modeB); } // XXX from SDR?
	int  get_modetype(int n);

	int  get_volume_control() { return (progStatus.volume); } // XXX from SDR?
	void set_volume_control(int);
	void get_vol_min_max_step(int &min, int &max, int &step) { min = 0; max = 100; step = 1; }

	void set_attenuator(int val);
	int  get_attenuator() { return (progStatus.attenuator); }

	void set_preamp(int);
	int  get_preamp() { return (progStatus.preamp); }

	bool can_split() { return (true); }
	int  get_split() { return (split); }
	void set_split(bool val);

	void set_PTT_control(int val);

	// ui_small.cxx
	void addto_small_main_group();
	void addto_group(GUI2* wP);
	void add_tab1();
	void adjust_small_main_group(int, int, int &, int &);

	// support.cxx
	void initXcvrTab();
	void hide();
	bool adjust_small_uiA(int*);
	bool adjust_small_uiB(int*);

	// statux.cxx, dialogs.cxx
	void setColors(Fl_Color &, Fl_Color &, Fl_Color &);

	// statux.cxx
	void spref_get(Fl_Preferences &spref);
	void spref_set(Fl_Preferences &spref);

#if 1 //STATUS_BAR
	static void cb_status_clear(Fl_Button*, void*);
#endif
	static void cb_spnr_hermes(Hspinner *, void*);
	static void cb_btn_hermes(Fl_Check_Button*, void*);

	static void cb_Dither(Fl_Light_Button*, void*);
	static void cb_Random(Fl_Light_Button*, void*);
	static void cb_Rxdcb(Fl_Light_Button*, void*);
	static void cb_Txdcb(Fl_Light_Button*, void*);
	static void cb_Pwsmode(Fl_Light_Button*, void*);

	static void cb_SetAnf(Fl_Light_Button*, void*);
	static void cb_SetIQenable(Fl_Light_Button*, void*);
	static void cb_Sdrom(Fl_Light_Button*, void*);
	static void cb_SpectrumPPhase(Fl_Light_Button*, void*);
	static void cb_RxSquelch(Fl_Light_Button*, void*);
	static void cb_SubRxSquelch(Fl_Light_Button*, void*);
	static void cb_Testbutton(Fl_Light_Button*, void*);

	static void cb_sldrAtten(Fl_Wheel_Value_Slider*, void*);
	static void cb_sldrRxGain(Fl_Wheel_Value_Slider*, void*);
	static void cb_sldrSubRxGain(Fl_Wheel_Value_Slider*, void*);
	static void cb_sldrTest(Fl_Wheel_Value_Slider*, void*);

	static void cb_sldr2(Fl_Wheel_Value_Slider*, void*);
	static void cb_sldr3(Fl_Wheel_Value_Slider*, void*);
	static void cb_sldr4(Fl_Wheel_Value_Slider*, void*);

	static void cb_master(Fl_Button*, void*);
	static void cb_master_name(Fl_Input2*, void*);
	static void cb_master_passwd(Fl_Input2*, void*);

#if 1
	static void cb_alexatt(Fl_ComboBox*, void*);
	static void cb_txant(Fl_ComboBox*, void*);
	static void cb_rxant(Fl_ComboBox*, void*);
	static void cb_hpfilt(Fl_ComboBox*, void*);
	static void cb_lpfilt(Fl_ComboBox*, void*);
#endif

	static void cb_filter(Fl_Button*, void*);
	static void cb_filter_low(Fl_Int_Input*, void*);
	static void cb_filter_high(Fl_Int_Input*, void*);

	static void cb_spectrum(Fl_Light_Button*, void*);
	static void cb_spectrum_fps(Fl_Int_Input*, void*);
	static void cb_spectrum_samples(Fl_Int_Input*, void*);

	static void cb_audio(Fl_Button*, void*);
	static void cb_audio_buf(Fl_Int_Input*, void*);
	static void cb_audio_rate(Fl_ComboBox*, void*);
	static void cb_audio_chnls(Fl_ComboBox*, void*);
	static void cb_audio_mic_enc(Fl_ComboBox*, void*);

	static void cb_notch(Fl_Button*, void*);
	static void cb_notch_vfo(Fl_ComboBox*, void*);
	static void cb_notch_index(Fl_ComboBox*, void*);
	static void cb_notch_bandwidth(Fl_Int_Input*, void*);
	static void cb_notch_offset(Fl_Int_Input*, void*);

	static void cb_notchenable(Fl_Button*, void*);
	static void cb_notchenable_vfo(Fl_ComboBox*, void*);
	static void cb_notchenable_index(Fl_ComboBox*, void*);
	static void cb_notchenable_value(Fl_ComboBox*, void*);

	static void cb_sldrHzhos(Fl_Wheel_Value_Slider*, void*);
	static void cb_hydraOS(Fl_Button*, void*);
	static void cb_hydra_dwf(Fl_Int_Input*, void*);
	static void cb_hydra_xwf(Fl_Int_Input*, void*);
	static void cb_hydra_rwf(Fl_Int_Input*, void*);
	static void cb_hydra_pwf(Fl_Int_Input*, void*);

	static void cb_rx_encoding(Fl_ComboBox*, void*);
	static void cb_rx_agc(Fl_ComboBox*, void*);
	static void cb_fixed_agc(Fl_Int_Input*, void*);

	// NEW_WIDGET callback ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

private:
	void post_initialize();
	void shutdown();

	//
	// Sliders.
	//
	int  get_subrxgain() { return (progStatus.subrx_gain); }
	void set_subrxgain(int);

	void set_atten_sldr(int val);
	int  get_atten_sldr() { return (progStatus.attenuation); }
	void cbSldrAtten();

	int  get_testslider() { return (progStatus.testslider); }
	void set_testslider(int);

	//
	// Combo controls.
	//
	void set_master(int);
	void set_master_name(string name);
	void set_master_passwd(string passwd);

#if 1
	void set_alexatt(int);
	void set_txant(int);
	void set_rxant(int);
	void set_hpfilt(int);
	void set_lpfilt(int);
#endif

	void set_filter();

	const char *get_filter_low() { return (progStatus.filter_low.c_str()); }
	void set_filter_low(const char *low) { progStatus.filter_low = low; }

	const char *get_filter_high() { return (progStatus.filter_high.c_str()); }
	void set_filter_high(const char *high) { progStatus.filter_high = high; }

	int  get_spectrum() { return (progStatus.spectrum); }
	void set_spectrum(int);

	const char *get_spectrum_fps() { return (progStatus.spectrum_fps.c_str()); }
	void set_spectrum_fps(const char *fps) { progStatus.spectrum_fps = fps; }

	const char *get_spectrum_samples() { return (progStatus.spectrum_samples.c_str()); }
	void set_spectrum_samples(const char *samples) { progStatus.spectrum_samples = samples; }

	int  get_audio() { return (progStatus.audio); }
	void set_audio(int);

	const char *get_audio_buf() { return (progStatus.audio_buf_size.c_str()); }
	void set_audio_buf(const char *buf_size) { progStatus.audio_buf_size = buf_size; }

	int get_audio_rate() { return (progStatus.audio_rate); }
	void set_audio_rate(int rate) { progStatus.audio_rate = rate; }

	int get_audio_chnls() { return (progStatus.audio_channels); }
	void set_audio_chnls(int chnls) { progStatus.audio_channels = chnls; }

	int get_audio_mic_enc() { return (progStatus.audio_mic_encode); }
	void set_audio_mic_enc(int mic_encode) { progStatus.audio_mic_encode = mic_encode; }

	void set_notchfilter(int);
	void set_notchenable(int);

	int get_rx_encoding() { return (progStatus.rx_encoding); }
	void set_rx_encoding(int rx_encoding);

	int get_rx_agc() { return (progStatus.rx_agc); }
	void set_rx_agc(int rx_agc);
	const char *get_fixed_agc() { return (progStatus.fixed_agc.c_str()); }
	void set_fixed_agc(const char *buf_size);

	int  get_hzhosslider() { return (progStatus.hz_hos); }
	void set_hzhosslider(int);

	float get_hydraos() { return (progStatus.ppm_hos); }
	void set_hydraos(int);

	double get_hdial_freq() { return (strtod(progStatus.hdial_freq.c_str(), NULL)); }
	void set_hdial_freq(const char *offset) { progStatus.hdial_freq = offset; }

	int get_hxmit_os() { return (atoi(hxmit_os.c_str())); }
	void set_hxmit_os(const char *offset) { hxmit_os = offset; }
	void clear_hxmit_os();

	int get_hrcv_os() { return (atoi(hrcv_os.c_str())); }
	void set_hrcv_os(const char *offset) { hrcv_os = offset; }
	void clear_hrcv_os();

	double get_ppm_os() { return (progStatus.ppm_hos); }
	void set_ppm_os(double offset) { progStatus.ppm_hos = offset; }

	//
	// Buttons.
	//
	void set_noise(bool on);
	int  get_noise() { return (progStatus.noise); }

	void set_noise_reduction(int val);
	int  get_noise_reduction() { return (progStatus.noise_reduction); }

	int  get_anf() { return (progStatus.anf); }
	void set_anf(int);

	int  get_testbutton() { return (progStatus.testbutton); }
	void set_testbutton(int);

	void set_dither(int);
	int  get_dither() { return (progStatus.dither); }

	void set_random(int);
	int  get_random() { return (progStatus.random); }

	int  get_rxdcb() { return (progStatus.rxdcb); }
	void set_rxdcb(int);

	int  get_txdcb() { return (progStatus.txdcb); }
	void set_txdcb(int);

	int  get_pwsmode() { return (progStatus.pwsmode); }
	void set_pwsmode(int);

	int  get_iqenable() { return (progStatus.iqenable); }
	void set_iqenable(int);

	int  get_sdrom() { return (progStatus.sdrom); }
	void set_sdrom(int);

	int  get_spectrumpolyphase() { return (progStatus.spectrumpolyphase); }
	void set_spectrumpolyphase(int);

	int  get_squelchstate() { return (progStatus.squelchstate); }
	void set_squelchstate(int);

	int  get_subrxquelchstate() { return (progStatus.subrxquelchstate); }
	void set_subrxquelchstate(int);

	//
	// Tabs.
	//
	void set_band_selection(int);

	// NEW_WIDGET get_/set_/_label/_value ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

#if 0
	void set_power_control(double);
	int  get_power_control();
	void get_pc_min_max_step(double &, double &, double &);

	void set_mic_gain(int val);
	int  get_mic_gain();
	void get_mic_min_max_step(int &min, int &max, int &step);

	void set_if_shift(int val);
	bool get_if_shift(int &val);
	void get_if_min_max_step(int &min, int &max, int &step);
	void get_if_mid();

	void set_PTT_control(int val);
	int  get_smeter();
	void set_bwA(int val);
	int  get_bwA();
	void set_bwB(int val);
	int  get_bwB();
	int  get_power_out();

	int  adjust_bandwidth(int m);
	int  def_bandwidth(int m);

	bool can_split() { return (true); }
	void set_split(bool val);
	int  get_split();
	bool twovfos() { return true; }

	void set_pbt_values(int val);

private:
	double  minpwr;
	double  maxpwr;
	double  steppwr;

// if shift value
	int  if_mid;
	int  if_min;
	int  if_max;

	int  get_swr();
	void tune_rig();
#endif // 0
};


class baseCfg
{
 public:
	string _label;
	string _tooltip;
	Fl_Callback* _callback;
	void* _valuePtr;

	baseCfg(string label = "", string tooltip = "", Fl_Callback* callback = NULL, void* valuePtr = NULL)
		: _label(label), _tooltip(tooltip), _callback(callback), _valuePtr(valuePtr)
	{
	}
	virtual ~baseCfg() {}

	virtual void initialize(GUI2* wP) { fprintf(stderr, "bad call\n"); exit(-1); }
};

// Plain button.
class btnPCfg : public baseCfg
{
 public:
	Fl_Color* _button_color;

	btnPCfg(string label = "", string tooltip = "", Fl_Callback* callback = NULL, void* valuePtr = NULL)
	 	: baseCfg(label, tooltip, callback, valuePtr)
	{
	}

	virtual void initialize(GUI2* wP);
};

// Lighted button.
class btnLCfg : public baseCfg
{
 public:
	Fl_Color* _button_color;

	btnLCfg(string label = "", string tooltip = "", Fl_Callback* callback = NULL, void* valuePtr = NULL)
	 	: baseCfg(label, tooltip, callback, valuePtr)
	{
	}

	virtual void initialize(GUI2* wP);
};

// Slider.
class sldrCfg : public baseCfg
{
 public:
	Fl_Color* _slider_color;
	Fl_Color* _button_color;
	int _min;
	int _max;
	int _step;

	sldrCfg(string label = "", string tooltip = "", Fl_Callback* callback = NULL, void* valuePtr = NULL,
		int min = 0, int max = 0, int step = 0)
		: baseCfg(label, tooltip, callback, valuePtr),
		_min(min), _max(max), _step(step)
	{
	}

	virtual void initialize(GUI2* wP);
};

// Numeric input.
class inpNCfg : public baseCfg
{
 public:
	int _align;

	inpNCfg(string label = "", string tooltip = "", Fl_Callback* callback = NULL, void* valuePtr = NULL,
		int align = 1)
		: baseCfg(label, tooltip, callback, valuePtr),
		_align(align)
	{
	}

	virtual void initialize(GUI2* wP);
};

// Alpha input.
class inpACfg : public baseCfg
{
 public:
	int _align;

	inpACfg(string label = "", string tooltip = "", Fl_Callback* callback = NULL, void* valuePtr = NULL,
		int align = 1)
		: baseCfg(label, tooltip, callback, valuePtr),
		_align(align)
	{
	}

	virtual void initialize(GUI2* wP);
};

// "Secret" input.
class inpSCfg : public baseCfg
{
 public:
	int _align;

	inpSCfg(string label = "", string tooltip = "", Fl_Callback* callback = NULL, void* valuePtr = NULL,
		int align = 1)
		: baseCfg(label, tooltip, callback, valuePtr),
		_align(align)
	{
	}

	virtual void initialize(GUI2* wP);
};

// ComboBox.
class cmboCfg : public baseCfg
{
 public:
 	int _align;
	const char** _choices;

	cmboCfg(string label = "", string tooltip = "", Fl_Callback* callback = NULL, void* valuePtr = NULL,
		int align = 1, const char** choices = NULL)
		: baseCfg(label, tooltip, callback, valuePtr), _align(align), _choices(choices)
	{
	}

	virtual void initialize(GUI2* wP);
};

#endif // _HPSDR_H
