#include <stdlib.h>

#include "mfsk.h"
#include "trx.h"
#include "fft.h"
#include "viterbi.h"
#include "prefs.h"
#include "varicode.h"
#include "interleave.h"
#include "misc.h"
#include "snd.h"

static inline complex mixer(struct trx *trx, complex in)
{
	struct mfsk *m = (struct mfsk *) trx->modem;
	complex z;
	float f;

	f = trx->frequency - (float) BaseTone * SampleRate / SymbolLen;
	f += prefs.txoffset;

	z.re = cos(m->phaseacc);
	z.im = sin(m->phaseacc);

	z = cmul(z, in);

	m->phaseacc -= 2.0 * M_PI * f / SampleRate;

	if (m->phaseacc > M_PI)
		m->phaseacc -= 2.0 * M_PI;
	else if (m->phaseacc < M_PI)
		m->phaseacc += 2.0 * M_PI;

	return z;
}

static void sendsymbol(struct trx *trx, int sym)
{
	struct mfsk *m = (struct mfsk *) trx->modem;
	complex in[SymbolLen], out[SymbolLen], z;
	float buf[SymbolLen];
	int i;

	memset(in , 0, sizeof(in));

	sym = grayencode(sym & (NumTones - 1));

	if (trx->reverse)
		sym = (NumTones - 1) - sym;

	in[sym + BaseTone].re = 1.0;

	fft(m->fft, in, out);

	for (i = 0; i < SymbolLen; i++) {
		z = mixer(trx, out[i]);
		buf[i] = z.re;
	}

	sound_write(buf, SymbolLen);
}

static void sendbit(struct trx *trx, int bit)
{
	struct mfsk *m = (struct mfsk *) trx->modem;
	int symbol;

	m->bitshreg = (m->bitshreg << 1) | !!bit;
	m->bitstate++;

	if (m->bitstate == 4) {
		symbol = interleave(m->bitshreg);
		sendsymbol(trx, symbol);
		m->bitstate = 0;
		m->bitshreg = 0;
	}
}

static void sendchar(struct trx *trx, unsigned char c)
{
	struct mfsk *m = (struct mfsk *) trx->modem;
	char *code;
	int data;

	code = varienc(c);

	while (*code) {
		data = encode27(&m->encstate, (*code - '0'));
		sendbit(trx, data & 2);
		sendbit(trx, data & 1);
		code++;
	}

	trx_put_echo_char(c);
}

static void sendidle(struct trx *trx)
{
	struct mfsk *m = (struct mfsk *) trx->modem;
	int i, data;

	sendchar(trx, 0);	/* <NUL> */

	data = encode27(&m->encstate, 1);
	sendbit(trx, data & 2);
	sendbit(trx, data & 1);

	/* extended zero bit stream */
	for (i = 0; i < 16; i++) {
		data = encode27(&m->encstate, 0);
		sendbit(trx, data & 2);
		sendbit(trx, data & 1);
	}
}

static void flushtx(struct trx *trx)
{
	struct mfsk *m = (struct mfsk *) trx->modem;
	int i, data;

	/* send one superfluous bit to flush the varicode decoder */
	data = encode27(&m->encstate, 1);
	sendbit(trx, data & 2);
	sendbit(trx, data & 1);

	/* generate encoder tail */
	for (i = 0; i < 8; i++) {
		data = encode27(&m->encstate, 0);
		sendbit(trx, data & 2);
		sendbit(trx, data & 1);
	}

	/* flush the interleaver */
	for (i = 0; i < 4 + 120 + 16; i++)
		sendbit(trx, 0);
}

int mfsk_txprocess(struct trx *trx)
{
	struct mfsk *m = (struct mfsk *) trx->modem;
	int i;

	if (trx->tune) {
		m->txstate = STATE_TUNE;
		trx->tune = 0;
	}

	switch (m->txstate) {
	case STATE_TUNE:
		sendsymbol(trx, 0);
		m->txstate = STATE_FINISH;
		break;

	case STATE_PREAMBLE:
		for (i = 0; i < 8; i++)
			sendsymbol(trx, 0);
		m->txstate = STATE_START;
		break;

	case STATE_START:
		sendchar(trx, '\r');
		sendchar(trx, 2);		/* STX */
		sendchar(trx, '\r');
		m->txstate = STATE_DATA;
		break;

	case STATE_DATA:
		i = trx_get_tx_char();
		if (i == -1)
			sendidle(trx);
		else
			sendchar(trx, i);
		if (trx->stopflag)
			m->txstate = STATE_END;
		break;

	case STATE_END:
		i = trx_get_tx_char();
		if (i == -1) {
			sendchar(trx, '\r');
			sendchar(trx, 4);		/* EOT */
			sendchar(trx, '\r');
			m->txstate = STATE_FLUSH;
		} else
			sendchar(trx, i);
		break;

	case STATE_FLUSH:
		flushtx(trx);
		/* note fallthrough */

	case STATE_FINISH:
		return -1;
	}

	return 0;
}
