/*
 * Copyright (C) 2019      Kai Ludwig, DG4KLU
 * Copyright (C) 2019-2021 Roger Clark, VK3KYY / G4KYF
 *                         Daniel Caujolle-Bert, F1RMB
 *
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
 *    in the documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * 4. Use of this source code or binary releases for commercial purposes is strictly forbidden. This includes, without limitation,
 *    incorporation in a commercial product or incorporation into a product or project which allows commercial use.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef _OPENGD77_SETTINGS_H_
#define _OPENGD77_SETTINGS_H_

#include "functions/codeplug.h"
#include "functions/trx.h"

enum USB_MODE { USB_MODE_CPS, USB_MODE_HOTSPOT, USB_MODE_DEBUG };
enum SETTINGS_UI_MODE { SETTINGS_CHANNEL_MODE = 0, SETTINGS_VFO_A_MODE, SETTINGS_VFO_B_MODE };
enum BACKLIGHT_MODE { BACKLIGHT_MODE_AUTO = 0, BACKLIGHT_MODE_SQUELCH, BACKLIGHT_MODE_MANUAL, BACKLIGHT_MODE_BUTTONS, BACKLIGHT_MODE_NONE };
enum HOTSPOT_TYPE { HOTSPOT_TYPE_OFF = 0, HOTSPOT_TYPE_MMDVM, HOTSPOT_TYPE_BLUEDV };
enum CONTACT_DISPLAY_PRIO { CONTACT_DISPLAY_PRIO_CC_DB_TA = 0, CONTACT_DISPLAY_PRIO_DB_CC_TA, CONTACT_DISPLAY_PRIO_TA_CC_DB, CONTACT_DISPLAY_PRIO_TA_DB_CC };
enum SCAN_MODE { SCAN_MODE_HOLD = 0, SCAN_MODE_PAUSE, SCAN_MODE_STOP };
enum SPLIT_CONTACT { SPLIT_CONTACT_SINGLE_LINE_ONLY = 0, SPLIT_CONTACT_ON_TWO_LINES, SPLIT_CONTACT_AUTO };
enum ALLOW_PRIVATE_CALLS_MODE { ALLOW_PRIVATE_CALLS_OFF = 0, ALLOW_PRIVATE_CALLS_ON, ALLOW_PRIVATE_CALLS_PTT };//, ALLOW_PRIVATE_CALLS_AUTO };
enum BAND_LIMITS_ENUM { BAND_LIMITS_NONE = 0 , BAND_LIMITS_ON_LEGACY_DEFAULT, BAND_LIMITS_FROM_CPS };
enum INFO_ON_SCREEN { INFO_ON_SCREEN_OFF = 0x00, INFO_ON_SCREEN_TS = 0x01, INFO_ON_SCREEN_PWR = 0x02, INFO_ON_SCREEN_BOTH = 0x03 };

#define ECO_LEVEL_MAX          5

#define SETTINGS_TIMEZONE_UTC 64
extern const uint32_t SETTINGS_UNITIALISED_LOCATION_LAT;

// Bit patterns for DMR Beep
#define BEEP_TX_NONE        0x00
#define BEEP_TX_START       0x01
#define BEEP_TX_STOP        0x02

extern int settingsCurrentChannelNumber;
extern int *nextKeyBeepMelody;
extern struct_codeplugChannel_t settingsVFOChannel[2];
extern struct_codeplugGeneralSettings_t settingsCodeplugGeneralSettings;

typedef enum
{
	BIT_INVERSE_VIDEO               = (1 << 0),
	BIT_PTT_LATCH                   = (1 << 1),
	BIT_TRANSMIT_TALKER_ALIAS       = (1 << 2),
	BIT_BATTERY_VOLTAGE_IN_HEADER   = (1 << 3),
	BIT_SETTINGS_UPDATED            = (1 << 4),
	BIT_TX_RX_FREQ_LOCK             = (1 << 5),
	BIT_ALL_LEDS_DISABLED           = (1 << 6),
	BIT_SCAN_ON_BOOT_ENABLED        = (1 << 7),
	BIT_POWEROFF_SUSPEND            = (1 << 8),
	BIT_SATELLITE_MANUAL_AUTO       = (1 << 9),
} bitfieldOptions_t;

typedef struct
{
	int 			magicNumber;
	// The following settings won't be reset default from magicNumber 0x4761
	uint32_t		locationLat;// fixed point encoded as 1 sign bit, 8 bits integer, 23 bits as decimal
	uint32_t		locationLon;// fixed point encoded as 1 sign bit, 8 bits integer, 23 bits as decimal
	uint8_t			timezone;// Lower 7 bits are the timezone. 64 = UTC, values < 64 are negative TZ values.  Bit 8 is a flag which indicates TZ/UTC. 0 = UTC
	// -----------------------------------------------
	uint16_t		vfoSweepSettings; // 3bits: channel step | 5 bits: RSSI noise floor | 7bits: gain
	uint32_t		overrideTG;
	uint32_t		vfoScanLow[2]; // low frequency for VFO Scanning
	uint32_t		vfoScanHigh[2]; // High frequency for VFO Scanning
	int16_t			currentChannelIndexInZone;
	int16_t			currentChannelIndexInAllZone;
	int16_t			currentIndexInTRxGroupList[3]; // Current Channel, VFO A and VFO B
	int16_t			currentZone;
	uint16_t		keypadTimerLong;
	uint16_t		keypadTimerRepeat;
	uint16_t		userPower;
	uint16_t		bitfieldOptions; // see bitfieldOptions_t
	uint8_t			txPowerLevel;
	uint8_t			txTimeoutBeepX5Secs;
	uint8_t			beepVolumeDivider;
	uint8_t			beepOptions;
	uint8_t			micGainDMR;
	uint8_t			micGainFM;
	uint8_t			backlightMode; // see BACKLIGHT_MODE enum
	uint8_t			backLightTimeout; // 0 = never timeout. 1 - 255 time in seconds
	int8_t			displayContrast;
	int8_t			displayBacklightPercentage;
	int8_t			displayBacklightPercentageOff; // backlight level when "off"
	uint8_t			initialMenuNumber;
	uint8_t			extendedInfosOnScreen;
	uint8_t			txFreqLimited;
	uint8_t			scanModePause;
	uint8_t			scanDelay;
	uint8_t			scanStepTime;
	uint8_t			squelchDefaults[RADIO_BANDS_TOTAL_NUM]; // VHF, 200Mhz and UHF
	uint8_t			currentVFONumber;
	uint8_t			languageIndex;
	uint16_t		tsManualOverride;
	uint8_t			dmrDestinationFilter;
	uint8_t			dmrCaptureTimeout;
	uint8_t			dmrCcTsFilter;
	uint8_t			analogFilterLevel;
	uint8_t			hotspotType;
	uint8_t    		privateCalls;
	uint8_t			contactDisplayPriority;
	uint8_t			splitContact;
	uint8_t			voxThreshold; // 0: disabled
	uint8_t			voxTailUnits; // 500ms units
	uint8_t			audioPromptMode;
	int8_t			temperatureCalibration;// Units of 0.5 deg C
	uint8_t			batteryCalibration; // Units of 0.01V (NOTE: only the 4 lower bits are used)
	uint8_t			ecoLevel;// Power saving / economy level
} settingsStruct_t;

typedef enum DMR_DESTINATION_FILTER_TYPE
{
	DMR_DESTINATION_FILTER_NONE = 0,
	DMR_DESTINATION_FILTER_TG,
	DMR_DESTINATION_FILTER_DC,
	DMR_DESTINATION_FILTER_RXG,
	NUM_DMR_DESTINATION_FILTER_LEVELS
} dmrDestinationFilter_t;

// Bit patterns
#define DMR_CC_FILTER_PATTERN  0x01
#define DMR_TS_FILTER_PATTERN  0x02

// NOTE. THIS ENUM IS USED AS BIT PATTERNS, DO NOT CHANGE THE DEFINED VALUES WITHOUT UPDATING ANY CODE WHICH USES THIS ENUM
typedef enum DMR_CCTS_FILTER_TYPE
{
	DMR_CCTS_FILTER_NONE = 0,
	DMR_CCTS_FILTER_CC = DMR_CC_FILTER_PATTERN,
	DMR_CCTS_FILTER_TS = DMR_TS_FILTER_PATTERN,
	DMR_CCTS_FILTER_CC_TS = DMR_CC_FILTER_PATTERN | DMR_TS_FILTER_PATTERN,
	NUM_DMR_CCTS_FILTER_LEVELS
} dmrCcTsFilter_t;

typedef enum ANALOG_FILTER_TYPE
{
	ANALOG_FILTER_NONE = 0,
	ANALOG_FILTER_CSS,
	NUM_ANALOG_FILTER_LEVELS
} analogFilter_t;

typedef enum AUDIO_PROMPT_MODE
{
	AUDIO_PROMPT_MODE_SILENT = 0,
	AUDIO_PROMPT_MODE_BEEP,
	AUDIO_PROMPT_MODE_VOICE_LEVEL_1,
	AUDIO_PROMPT_MODE_VOICE_LEVEL_2,
	AUDIO_PROMPT_MODE_VOICE_LEVEL_3 ,
	NUM_AUDIO_PROMPT_MODES
} audioPromptMode_t;

typedef enum PROMPT_AUTOPLAY_THRESHOLD
{
	PROMPT_THRESHOLD_1 = AUDIO_PROMPT_MODE_VOICE_LEVEL_1,
	PROMPT_THRESHOLD_2,
	PROMPT_THRESHOLD_3,
	PROMPT_THRESHOLD_NEVER_PLAY_IMMEDIATELY
} audioPromptThreshold_t;

typedef struct
{
	volatile bool   triggered;
	volatile bool	isEnabled;
	volatile bool	qsoInfoUpdated;
	volatile bool   dmrIsValid;
	int				dmrTimeout;
	uint8_t			dmrFrameSkip;
	int 			savedRadioMode;
	uint8_t			savedSquelch;
	int 			savedDMRCcTsFilter;
	int 			savedDMRDestinationFilter;
	int 			savedDMRCc;
	int 			savedDMRTs;
} monitorModeSettingsStruct_t;

extern settingsStruct_t nonVolatileSettings;
extern struct_codeplugChannel_t *currentChannelData;
extern struct_codeplugChannel_t channelScreenChannelData;
extern struct_codeplugContact_t contactListContactData;
extern struct_codeplugDTMFContact_t contactListDTMFContactData;
extern int contactListContactIndex;
extern volatile int settingsUsbMode;
extern monitorModeSettingsStruct_t monitorModeData;

// Do not use the following settingsSet<TYPE>(...) functions, use settingsSet() instead
void settingsSetBOOL(bool *s, bool v);
void settingsSetINT8(int8_t *s, int8_t v);
void settingsSetUINT8(uint8_t *s, uint8_t v);
void settingsSetINT16(int16_t *s, int16_t v);
void settingsSetUINT16(uint16_t *s, uint16_t v);
void settingsSetINT32(int32_t *s, int32_t v);
void settingsSetUINT32(uint32_t *s, uint32_t v);

// Do not use the following settingsInc/Dec<TYPE>(...) functions, use settingsIncrement/Decrement() instead
void settingsIncINT8(int8_t *s, int8_t v);
void settingsIncUINT8(uint8_t *s, uint8_t v);
void settingsIncINT16(int16_t *s, int16_t v);
void settingsIncUINT16(uint16_t *s, uint16_t v);
void settingsIncINT32(int32_t *s, int32_t v);
void settingsIncUINT32(uint32_t *s, uint32_t v);

void settingsDecINT8(int8_t *s, int8_t v);
void settingsDecUINT8(uint8_t *s, uint8_t v);
void settingsDecINT16(int16_t *s, int16_t v);
void settingsDecUINT16(uint16_t *s, uint16_t v);
void settingsDecINT32(int32_t *s, int32_t v);
void settingsDecUINT32(uint32_t *s, uint32_t v);

// Workaround for Eclipse's CDT parser angriness because it doesn't support C11 yet
#ifdef __CDT_PARSER__
#define settingsSet(S, V) do { /* It uses C11's _Generic() at compile time */ S = V; } while(0)
#else
#define settingsSet(S, V) _Generic((S),   \
	bool:     settingsSetBOOL,            \
	int8_t:   settingsSetINT8,            \
	uint8_t:  settingsSetUINT8,           \
	int16_t:  settingsSetINT16,           \
	uint16_t: settingsSetUINT16,          \
	int32_t:  settingsSetINT32,           \
	uint32_t: settingsSetUINT32           \
	)(&S, V)
#endif

#ifdef __CDT_PARSER__
#define settingsIncrement(S, V) do { /* It uses C11's _Generic() at compile time */ S += V; } while(0)
#else
#define settingsIncrement(S, V) _Generic((S),   \
	int8_t:   settingsIncINT8,            \
	uint8_t:  settingsIncUINT8,           \
	int16_t:  settingsIncINT16,           \
	uint16_t: settingsIncUINT16,          \
	int32_t:  settingsIncINT32,           \
	uint32_t: settingsIncUINT32           \
	)(&S, V)
#endif

#ifdef __CDT_PARSER__
#define settingsDecrement(S, V) do { /* It uses C11's _Generic() at compile time */ S -= V; } while(0)
#else
#define settingsDecrement(S, V) _Generic((S),   \
	int8_t:   settingsDecINT8,            \
	uint8_t:  settingsDecUINT8,           \
	int16_t:  settingsDecINT16,           \
	uint16_t: settingsDecUINT16,          \
	int32_t:  settingsDecINT32,           \
	uint32_t: settingsDecUINT32           \
	)(&S, V)
#endif

void settingsSetOptionBit(bitfieldOptions_t bit, bool set);
bool settingsIsOptionBitSet(bitfieldOptions_t bit);

void settingsSetDirty(void);
void settingsSetVFODirty(void);
void settingsSaveIfNeeded(bool immediately);
bool settingsSaveSettings(bool includeVFOs);
bool settingsLoadSettings(void);
void settingsRestoreDefaultSettings(void);
void settingsEraseCustomContent(void);
void settingsInitVFOChannel(int vfoNumber);
void enableVoicePromptsIfLoaded(bool enableFullPrompts);
int settingsGetScanStepTimeMilliseconds(void);

#endif
