#pragma once
#include "common.h"
#define LUA_USER_DATA 	1280

/* The RDS error-detection code generator polynomial is
 * x^10 + x^8 + x^7 + x^5 + x^4 + x^3 + x^0
 */
#define POLY			0x1B9
#define POLY_DEG		10
#define BLOCK_SIZE		16

#define GROUP_LENGTH		4
#define BITS_PER_GROUP		(GROUP_LENGTH * (BLOCK_SIZE + POLY_DEG))
#define RDS_SAMPLE_RATE		4750

#define RT_LENGTH	64
#define PS_LENGTH	8
#define PTYN_LENGTH	8
#define LPS_LENGTH	32
#define DEFAULT_GRPSQC "002222XYOK"
#define MAX_AFS 25

#define AF_CODE_FILLER		205
#define AF_CODE_NUM_AFS_BASE	224
#define AF_CODE_LFMF_FOLLOWS	250

#define PROGRAMS 3
#define EONs 4

typedef struct {
	uint8_t num_entries : 6;
	uint8_t num_afs : 5;
	uint8_t afs[MAX_AFS];
} RDSAFs;
typedef struct {
	uint16_t pi;
	uint8_t enabled : 1;
	uint8_t ta : 1;
	uint8_t tp : 1;
	uint8_t pty : 5;
	char ps[8];
	RDSAFs af;
	uint16_t data : 16;
} RDSEON;
typedef struct {
	uint16_t pi;

	char ps[PS_LENGTH];
	char rt[RT_LENGTH];

	uint8_t ecc;
	uint16_t slc_data : 12;

	uint8_t ta : 1;
	uint8_t pty : 5;
	uint8_t tp : 1;
	uint8_t dpty : 1;

	char tps[PS_LENGTH];

	uint8_t rt_enabled : 1;

	uint8_t ptyn_enabled : 1;
	char ptyn[PTYN_LENGTH];

	RDSAFs af;

	uint8_t ct : 1;

	char lps[LPS_LENGTH];

	char grp_sqc[32];
	char grp_sqc_rds2[32];

	uint8_t udg1_len : 4;
	uint8_t udg2_len : 4;
	uint8_t udg1_len_rds2 : 4;
	uint8_t udg2_len_rds2 : 4;

	uint16_t udg1[8][3];
	uint16_t udg2[8][3];

	uint16_t udg1_rds2[8][4];
	uint16_t udg2_rds2[8][4];

	RDSEON eon[EONs];

	uint8_t lua_data[LUA_USER_DATA];
} RDSData;
typedef struct {
	uint8_t af_state : 6;
} RDSEONState;

typedef struct {
	uint8_t ps_update : 1;
	uint8_t tps_update : 1;
	char ps_text[PS_LENGTH];
	char tps_text[PS_LENGTH];
	uint8_t ps_csegment : 3;

	char rt_text[RT_LENGTH];
	uint8_t rt_state : 5;
	uint8_t rt_update : 1;
	uint8_t rt_ab : 1;
	uint8_t rt_segments : 5;

	char ptyn_text[PTYN_LENGTH];
	uint8_t ptyn_state : 1;
	uint8_t ptyn_update : 1;
	uint8_t ptyn_ab : 1;

	char lps_text[LPS_LENGTH];
	uint8_t lps_state : 4;
	uint8_t lps_update : 1;
	uint8_t lps_segments : 4;

	uint16_t custom_group[GROUP_LENGTH];
	uint16_t custom_group2[GROUP_LENGTH + 1];

	uint8_t data_ecc : 1;
	uint8_t grp_seq_idx[4];
	uint8_t udg_idxs[2];
	uint8_t udg_idxs_rds2[2];

	uint8_t fasttuning_state : 3;

	uint8_t last_minute : 6;
	uint8_t last_second : 6;

	uint8_t ta_timeout : 7;
	uint8_t ta_timeout_state : 7;

	uint8_t eon_index : 3;
	uint8_t eon_state : 4;
	RDSEONState eon_states[4];

	uint8_t af_state : 6;

	uint8_t eon_linkage : 1;

	uint16_t last_stream0_group[3];
	uint8_t last_stream0_group_type_b : 1;
} RDSState;

typedef struct {
	uint8_t rds2_mode : 2;
	// uint8_t rds2_buffer[16384];
} RDSEncoderData;
typedef struct {
	RDSEncoderData encoder_data;
	RDSData data[PROGRAMS];
	RDSState state[PROGRAMS];
	uint8_t program : 3;
	uint8_t enabled_streams : 3;
} RDSEncoder;
typedef struct {
	uint8_t file_starter; // Always is 225 first polish radio programme am frequency
	RDSData data[PROGRAMS];
	uint8_t file_middle; // Always is 160, average of both
	RDSEncoderData encoder_data;
	uint8_t program : 3;
	uint8_t enabled_streams : 3;
	uint8_t file_ender; // Always is 95 my freq
	uint16_t crc;
} RDSEncoderFile;

typedef struct
{
	uint16_t a;
	uint16_t b;
	uint16_t c;
	uint16_t d;
	uint8_t is_type_b : 1;
} RDSGroup;

#define IS_TYPE_B(b)	(b & 0x0800)

void reset_rds_state(RDSEncoder* enc, uint8_t program);
void set_rds_defaults(RDSEncoder* enc, uint8_t program);
void init_rds_encoder(RDSEncoder* enc);
void add_checkwords(RDSGroup *group, uint8_t *bits);
void get_rds_group(RDSEncoder* enc, RDSGroup *group, uint8_t stream);
void get_rds_bits(RDSEncoder* enc, uint8_t *bits, uint8_t stream);

void set_rds_rt(RDSEncoder* enc, const char *rt, uint8_t program);
void set_rds_ps(RDSEncoder* enc, const char *ps, uint8_t program);
void set_rds_tps(RDSEncoder* enc, const char *tps, uint8_t program);
void set_rds_lps(RDSEncoder* enc, const char *lps, uint8_t program);
void set_rds_ptyn(RDSEncoder *enc, const char *ptyn, uint8_t program);
void set_rds_grpseq(RDSEncoder* enc, const char *grpseq, uint8_t program);
void set_rds_grpseq2(RDSEncoder* enc, const char *grpseq2, uint8_t program);