#include "rds.h"
#include "lib.h"
#include "lua_rds.h"

uint16_t get_next_af(RDSEncoder* enc) {
	uint16_t out;

	if (enc->data[enc->program].af.num_afs) {
		if (enc->state[enc->program].af_state == 0) {
			out = (AF_CODE_NUM_AFS_BASE + enc->data[enc->program].af.num_afs) << 8 | enc->data[enc->program].af.afs[0];
			enc->state[enc->program].af_state++;
		} else {
			out = enc->data[enc->program].af.afs[enc->state[enc->program].af_state] << 8;
			if (enc->data[enc->program].af.afs[enc->state[enc->program].af_state + 1]) out |= enc->data[enc->program].af.afs[enc->state[enc->program].af_state + 1];
			else out |= AF_CODE_FILLER;
			enc->state[enc->program].af_state += 2;
		}
		if (enc->state[enc->program].af_state >= enc->data[enc->program].af.num_entries) enc->state[enc->program].af_state = 0;
	} else out = AF_CODE_NUM_AFS_BASE << 8 | AF_CODE_FILLER;

	return out;
}

uint16_t get_next_af_eon(RDSEncoder* enc, uint8_t eon_index) {
	uint16_t out;

	if (enc->data[enc->program].eon[eon_index].af.num_afs) {
		if (enc->state[enc->program].eon_states[eon_index].af_state == 0) {
			out = (AF_CODE_NUM_AFS_BASE + enc->data[enc->program].af.num_afs) << 8 | enc->data[enc->program].eon[eon_index].af.afs[0];
			enc->state[enc->program].eon_states[eon_index].af_state += 1;
		} else {
			out = enc->data[enc->program].eon[eon_index].af.afs[enc->state[enc->program].eon_states[eon_index].af_state] << 8;
			if (enc->data[enc->program].eon[eon_index].af.afs[enc->state[enc->program].eon_states[eon_index].af_state + 1]) out |= enc->data[enc->program].eon[eon_index].af.afs[enc->state[enc->program].eon_states[eon_index].af_state + 1];
			else {
				out |= AF_CODE_FILLER;
				enc->state[enc->program].eon_states[eon_index].af_state += 2;
			}
		}
		if (enc->state[enc->program].eon_states[eon_index].af_state >= enc->data[enc->program].eon[eon_index].af.num_entries) enc->state[enc->program].eon_states[eon_index].af_state = 0;
	} else out = AF_CODE_NUM_AFS_BASE << 8 | AF_CODE_FILLER;

	return out;
}

void get_rds_ps_group(RDSEncoder* enc, RDSGroup *group) {
	if(enc->state[enc->program].ps_csegment == 0) {
		if(enc->state[enc->program].ps_update) {
			memcpy(enc->state[enc->program].ps_text, enc->data[enc->program].ps, PS_LENGTH);
			enc->state[enc->program].ps_update = 0;
		}

		if(enc->state[enc->program].tps_update) {
			memcpy(enc->state[enc->program].tps_text, enc->data[enc->program].tps, PS_LENGTH);
			enc->state[enc->program].tps_update = 0;
		}
	}

	group->b |= enc->data[enc->program].ta << 4;
	if(enc->state[enc->program].ps_csegment == 0) group->b |= enc->data[enc->program].dpty << 2;
	group->b |= enc->state[enc->program].ps_csegment;

	if(enc->data[enc->program].af.num_afs) group->c = get_next_af(enc);
	else {
		group->b |= 1 << 11; // set to b
		group->is_type_b = 1;
	}

	if(enc->data[enc->program].ta && enc->state[enc->program].tps_text[0] != '\0') group->d = enc->state[enc->program].tps_text[enc->state[enc->program].ps_csegment * 2] << 8 | enc->state[enc->program].tps_text[enc->state[enc->program].ps_csegment * 2 + 1];
	else group->d = enc->state[enc->program].ps_text[enc->state[enc->program].ps_csegment * 2] << 8 |  enc->state[enc->program].ps_text[enc->state[enc->program].ps_csegment * 2 + 1];

	enc->state[enc->program].ps_csegment++;
	if (enc->state[enc->program].ps_csegment == 4) enc->state[enc->program].ps_csegment = 0;
}

void get_rds_fasttuning_group(RDSEncoder* enc, RDSGroup *group) {
	group->b |= 15 << 12;
	group->b |= 1 << 11;
	group->is_type_b = 1;

	group->b |= enc->data[enc->program].ta << 4;
	if(enc->state[enc->program].fasttuning_state == 0) group->b |= enc->data[enc->program].dpty << 2;
	group->b |= enc->state[enc->program].fasttuning_state;
	group->d = group->b;

	enc->state[enc->program].fasttuning_state++;
	if (enc->state[enc->program].fasttuning_state == 4) enc->state[enc->program].fasttuning_state = 0;
}

void get_rds_rt_group(RDSEncoder* enc, RDSGroup *group) {
	if (enc->state[enc->program].rt_update && enc->data[enc->program].rt_enabled) {
		memcpy(enc->state[enc->program].rt_text, enc->data[enc->program].rt, RT_LENGTH);
		enc->state[enc->program].rt_update = 0;
		enc->state[enc->program].rt_state = 0;
	}

	group->b |= 2 << 12;
	group->b |= enc->state[enc->program].rt_ab << 4;
	group->b |= enc->state[enc->program].rt_state;
	group->c =  enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4] << 8;
	group->c |= enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4 + 1];
	group->d =  enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4 + 2] << 8;
	group->d |= enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4 + 3];

	enc->state[enc->program].rt_state++;
	if (enc->state[enc->program].rt_state >= enc->state[enc->program].rt_segments || enc->state[enc->program].rt_state >= 16) {
		lua_call_tfunction("rt_transmission");
		enc->state[enc->program].rt_state = 0;
	}
}

void get_rdsp_ct_group(RDSGroup *group, time_t now) {
	struct tm *utc, *local_time;
	uint8_t l;
	uint32_t mjd;
	int16_t offset;

	utc = gmtime(&now);

	l = utc->tm_mon <= 1 ? 1 : 0;
	mjd = 14956 + utc->tm_mday + (uint32_t)((utc->tm_year - l) * 365.25f) + (uint32_t)((utc->tm_mon + (1+1) + l * 12) * 30.6001f);

	group->b |= 4 << 12 | (mjd >> 15);
	group->c = (mjd << 1) | (utc->tm_hour >> 4);
	group->d = (utc->tm_hour & 0xf) << 12 | utc->tm_min << 6;

	local_time = localtime(&now);
	offset = local_time->tm_gmtoff / (30 * 60);
	if (offset < 0) group->d |= 1 << 5;
	group->d |= abs(offset);
}

void get_rds_lps_group(RDSEncoder* enc, RDSGroup *group) {
	if (enc->state[enc->program].lps_state == 0 && enc->state[enc->program].lps_update) {
		memcpy(enc->state[enc->program].lps_text, enc->data[enc->program].lps, LPS_LENGTH);
		enc->state[enc->program].lps_update = 0;
	}

	group->b |= 15 << 12 | enc->state[enc->program].lps_state;
	group->c =  enc->state[enc->program].lps_text[enc->state[enc->program].lps_state * 4] << 8;
	group->c |= enc->state[enc->program].lps_text[enc->state[enc->program].lps_state * 4 + 1];
	group->d =  enc->state[enc->program].lps_text[enc->state[enc->program].lps_state * 4 + 2] << 8;
	group->d |= enc->state[enc->program].lps_text[enc->state[enc->program].lps_state * 4 + 3];

	enc->state[enc->program].lps_state++;
	if (enc->state[enc->program].lps_state >= enc->state[enc->program].lps_segments) enc->state[enc->program].lps_state = 0;
}

void get_rds_ecc_group(RDSEncoder* enc, RDSGroup *group) {
	group->b |= 1 << 12;
	group->c = enc->state[enc->program].eon_linkage << 15;
	group->c |= enc->data[enc->program].ecc;
}

void get_rds_slcdata_group(RDSEncoder* enc, RDSGroup *group) {
	group->b |= 1 << 12;
	group->c = enc->state[enc->program].eon_linkage << 15;
	group->c |= 0x6000;
	group->c |= enc->data[enc->program].slc_data;
}

void get_rds_ptyn_group(RDSEncoder* enc, RDSGroup *group) {
	if (enc->state[enc->program].ptyn_state == 0 && enc->state[enc->program].ptyn_update) {
		memcpy(enc->state[enc->program].ptyn_text, enc->data[enc->program].ptyn, PTYN_LENGTH);
		TOGGLE(enc->state[enc->program].ptyn_ab);
		enc->state[enc->program].ptyn_update = 0;
	}

	group->b |= 10 << 12 | enc->state[enc->program].ptyn_state;
	group->b |= enc->state[enc->program].ptyn_ab << 4;
	group->c =  enc->state[enc->program].ptyn_text[enc->state[enc->program].ptyn_state * 4] << 8;
	group->c |= enc->state[enc->program].ptyn_text[enc->state[enc->program].ptyn_state * 4 + 1];
	group->d =  enc->state[enc->program].ptyn_text[enc->state[enc->program].ptyn_state * 4 + 2] << 8;
	group->d |= enc->state[enc->program].ptyn_text[enc->state[enc->program].ptyn_state * 4 + 3];

	enc->state[enc->program].ptyn_state++;
	if (enc->state[enc->program].ptyn_state == 2) enc->state[enc->program].ptyn_state = 0;
}

void get_rds_eon_group(RDSEncoder* enc, RDSGroup *group) {
	RDSEON eon;
	eon = enc->data[enc->program].eon[enc->state[enc->program].eon_index];
	while(1) {
		group->b |= 14 << 12;
		group->b |= eon.tp << 4;

		switch (enc->state[enc->program].eon_state)
		{
		case 0:
		case 1:
		case 2:
		case 3:
			group->c = eon.ps[enc->state[enc->program].eon_state*2] << 8;
			group->c |= eon.ps[enc->state[enc->program].eon_state*2+1];
			group->b |= enc->state[enc->program].eon_state;
			break;
		case 4:
			group->c = get_next_af_eon(enc, enc->state[enc->program].eon_index);
			group->b |= enc->state[enc->program].eon_state;
			break;
		case 5: // 13
			group->c = eon.pty << 11;
			if(eon.tp) group->c |= eon.ta;
			group->b |= 13;
			break;
		case 6: // 15
			group->c = eon.data;
			group->b |= 15;
			break;
		}

		group->d = eon.pi;

		if(enc->state[enc->program].eon_state == 6) {
			enc->state[enc->program].eon_index++;

			uint8_t i = 0;
			while(i < 4 && !enc->data[enc->program].eon[enc->state[enc->program].eon_index].enabled) {
				enc->state[enc->program].eon_index++;
				if(enc->state[enc->program].eon_index >= EONs) enc->state[enc->program].eon_index = 0;
				eon = enc->data[enc->program].eon[enc->state[enc->program].eon_index];
				i++;
			}

			enc->state[enc->program].eon_state = 0;
		} else {
			enc->state[enc->program].eon_state++;
			break;
		}
	}
}

uint8_t get_rds_custom_groups(RDSEncoder* enc, RDSGroup *group) {
	if(enc->state[enc->program].custom_group[0] == 1) {
		enc->state[enc->program].custom_group[0] = 0;
		group->a = enc->data[enc->program].pi;
		group->b = enc->state[enc->program].custom_group[1];
		group->c = enc->state[enc->program].custom_group[2];
		group->d = enc->state[enc->program].custom_group[3];
		group->is_type_b = (IS_TYPE_B(group->b) != 0);
		return 1;
	}
	return 0;
}
uint8_t get_rds_custom_groups2(RDSEncoder* enc, RDSGroup *group) {
	if(enc->state[enc->program].custom_group2[0] == 1) {
		enc->state[enc->program].custom_group2[0] = 0;
		group->a = enc->state[enc->program].custom_group2[1];
		group->b = enc->state[enc->program].custom_group2[2];
		group->c = enc->state[enc->program].custom_group2[3];
		group->d = enc->state[enc->program].custom_group2[4];
		group->is_type_b = (group->a == 0 && IS_TYPE_B(group->b));
		return 1;
	}
	return 0;
}
int get_rdsp_lua_group(RDSGroup *group, const char grp) {
	int generated = lua_group(group, grp);
	if(generated) group->is_type_b = (IS_TYPE_B(group->b) != 0);
	return generated;
}