/*
 * This file contains platform independent code only.
 */
#include <stdio.h>
#include <syslog.h>
#include <stdarg.h>
#include <stdlib.h>

#include "libvoice.h"
#include "libvoice-priv.h"

struct terminal_info_t terminal_info = { .num_voice_ports = 0, };
struct line_t *lines = NULL; // Array of phone lines including FXS and DECT
struct connection_t *connections = NULL;
int max_num_connections = 0;

const struct voice_event_t event_map[] = { // List of events from the voice engine
	{ .name = "DTMF0",         .event = VOICE_EVT_DTMF0       },
	{ .name = "DTMF1",         .event = VOICE_EVT_DTMF1       },
	{ .name = "DTMF2",         .event = VOICE_EVT_DTMF2       },
	{ .name = "DTMF3",         .event = VOICE_EVT_DTMF3       },
	{ .name = "DTMF4",         .event = VOICE_EVT_DTMF4       },
	{ .name = "DTMF5",         .event = VOICE_EVT_DTMF5       },
	{ .name = "DTMF6",         .event = VOICE_EVT_DTMF6       },
	{ .name = "DTMF7",         .event = VOICE_EVT_DTMF7       },
	{ .name = "DTMF8",         .event = VOICE_EVT_DTMF8       },
	{ .name = "DTMF9",         .event = VOICE_EVT_DTMF9       },
	{ .name = "DTMFS",         .event = VOICE_EVT_DTMFS       },
	{ .name = "DTMFH",         .event = VOICE_EVT_DTMFH       },
	{ .name = "DTMFA",         .event = VOICE_EVT_DTMFA       },
	{ .name = "DTMFB",         .event = VOICE_EVT_DTMFB       },
	{ .name = "DTMFC",         .event = VOICE_EVT_DTMFC       },
	{ .name = "DTMFD",         .event = VOICE_EVT_DTMFD       },
	{ .name = "OFFHOOK",       .event = VOICE_EVT_OFFHOOK     },
	{ .name = "ONHOOK",        .event = VOICE_EVT_ONHOOK      },
	{ .name = "FLASH",         .event = VOICE_EVT_FLASH       },
	{ .name = "",              .event = VOICE_EVT_END         }
};

const struct dect_event_t dect_event_map[] = { // List of events from the dectmngr
	{ .name = "SWITCH",        .event = DECT_EVT_SWITCH       },
	{ .name = "JOIN",          .event = DECT_EVT_JOIN         },
	{ .name = "RELEASE",       .event = DECT_EVT_RELEASE      },
	{ .name = "",              .event = DECT_EVT_END          }
};

const struct voice_signal_t signal_map[] = { // List of signals requested by Asterisk
	{ .name = "dial",           .signal = VOICE_SIG_DIAL },
	{ .name = "ringback",       .signal = VOICE_SIG_RINGBACK },
	{ .name = "stutter",        .signal = VOICE_SIG_STUTTER },
	{ .name = "unobtainable",   .signal = VOICE_SIG_UNOBTAINABLE },
	{ .name = "callwt",         .signal = VOICE_SIG_CALL_WAITING },
	{ .name = "busy",           .signal = VOICE_SIG_BUSY },
	{ .name = "ringing",        .signal = VOICE_SIG_RINGING },
	{ .name = "callid_ringing", .signal = VOICE_SIG_CALLID_RINGING },
	{ .name = "callid",         .signal = VOICE_SIG_CALLID },
	{ .name = "congestion",     .signal = VOICE_SIG_NETBUSY },
	{ .name = "dtmf0",          .signal = VOICE_SIG_DTMF0 },
	{ .name = "dtmf1",          .signal = VOICE_SIG_DTMF1 },
	{ .name = "dtmf2",          .signal = VOICE_SIG_DTMF2 },
	{ .name = "dtmf3",          .signal = VOICE_SIG_DTMF3 },
	{ .name = "dtmf4",          .signal = VOICE_SIG_DTMF4 },
	{ .name = "dtmf5",          .signal = VOICE_SIG_DTMF5 },
	{ .name = "dtmf6",          .signal = VOICE_SIG_DTMF6 },
	{ .name = "dtmf7",          .signal = VOICE_SIG_DTMF7 },
	{ .name = "dtmf8",          .signal = VOICE_SIG_DTMF8 },
	{ .name = "dtmf9",          .signal = VOICE_SIG_DTMF9 },
	{ .name = "dtmf#",          .signal = VOICE_SIG_DTMFH },
	{ .name = "dtmf*",          .signal = VOICE_SIG_DTMFS },
	{ .name = "dtmfA",          .signal = VOICE_SIG_DTMFA },
	{ .name = "dtmfB",          .signal = VOICE_SIG_DTMFB },
	{ .name = "dtmfC",          .signal = VOICE_SIG_DTMFC },
	{ .name = "dtmfD",          .signal = VOICE_SIG_DTMFD },
	{ .name = "keypad",         .signal = VOICE_SIG_INGRESS_DTMF },
	{ .name = "answer",         .signal = VOICE_SIG_ANSWER },
	{ .name = "k-break",        .signal = VOICE_SIG_K_BREAK },
	{ .name = "",               .signal = VOICE_SIG_LAST },
};

// Callback function which is invoked when an event is detected from the voice engine
void (*voice_cb_event_report)(int line, const char *event, int data) = NULL;
// Callback function which is invoked when an encoded media packet is generated by the voice engine
void (*voice_cb_egress_media)(const struct media_packet_t *packet, int size) = NULL;

void voice_syslog(int level, const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	vsyslog(level, fmt, ap);
	va_end(ap);
}

int voice_connection_find(int line, int connection)
{
	int conIdx;

	for(conIdx = 0; conIdx < max_num_connections; conIdx++) {
		// If connection is -1, it means any connection on the line
		if(connections[conIdx].line == line && (connections[conIdx].connection_id == connection || connection == -1)) {
			return conIdx;
		}
	}

	return -1;
}

// Pre-initialization of data structures
int voice_line_preinit(void) {
	int i;

	if(terminal_info.num_voice_ports <= 0) {
		ENDPT_DBG("terminal_info.num_voice_ports = %d\n", terminal_info.num_voice_ports);
		return -1;
	}

	// Initialize all contents as 0 by calloc
	lines = calloc(terminal_info.num_voice_ports, sizeof(struct line_t));
	if(!lines) {
		ENDPT_ERR("%s: out out memory\n", __func__);
		return -1;
	}
	for(i = 0; i < terminal_info.num_voice_ports; i++) {
		lines[i].type = terminal_info.voice_ports[i];
		ENDPT_DBG("lines[%d].type=%d\n", i, lines[i].type);
		lines[i].pcm_callid[PCM_0] = CALLID_INVALID;
		lines[i].pcm_callid[PCM_1] = CALLID_INVALID;
	}

	return 0;
}

// Shut down and free resources
int voice_line_deinit(void) {
	char *digits;
	int i;

	// Free all line resources we have allocated
	for(i = 0; i < terminal_info.num_voice_ports; i++) {
		if(lines[i].pending_digits) {
			do {
				digits = pe_list_get(lines[i].pending_digits);
				free(digits);
			} while(digits);
			free(lines[i].pending_digits);
			lines[i].pending_digits = NULL;
		}

		voice_line_close(i);

		if(lines[i].line_conf.name) {
			free(lines[i].line_conf.name);
			lines[i].line_conf.name = NULL;
		}
		if(lines[i].priv) {
			free(lines[i].priv);
			lines[i].priv = NULL;
		}
	}
	free(lines);
	lines = NULL;

	return 0;
}

// Register the callback function for event report
int voice_register_cb_event_report(void (*cb_event_report)(int line, const char *event, int data)) {
	voice_cb_event_report = cb_event_report;

	return 0;
}

// Register the callback function for handling an encoded media packet from the voice engine
int voice_register_cb_egress_media(void (*cb_egress_media)(const struct media_packet_t *packet, int size)) {
	voice_cb_egress_media = cb_egress_media;

	return 0;
}

const char *voice_event2name(enum VOICE_EVENT evt)
{
	const struct voice_event_t *item;

	for (item = event_map; item->event != evt && item->event != VOICE_EVT_END; item++)
		continue;

	return item->name;
}