#ifdef WIN32
#include <windows.h>
#else
#include <errno.h>
#endif
#include <time.h>
#include <stdlib.h>
#include "lib.h"
#ifdef REGANS_THREADS
#	include "../adt/thread.h"
#else
#	include "thread.h"
#endif
#include "lprintf.h"
#include "smslib.h"

struct sms_mode_fn_pointers {
	void *(*initfn)(Sms *, void *, int *);
	void (*freefn)(void **);
	int (*recvfn)(void *, void *);
	int (*sendfn)(void *, void *, char *, char *, char *);
	void *(*waitfn)(void *, long, int *);
	char *(*errorfn)(void *, int, char *, int);
	char *(*fromipfn)(void *, void *);
	char *(*fromfn)(void *, void *);
	char *(*tofn)(void *, void *);
	char *(*bodyfn)(void *, void *);
	int (*rejectfn)(void *, void *, int, char *);
	int (*acceptfn)(void *, void *, int, char *);	
	void (*msgfreefn)(void *, void **);
};

struct sms_mode_fn_pointers _functions[] = {
	{sms_gsm_init,(void (*)(void **))sms_gsm_free,sms_gsm_recv,sms_gsm_send,sms_gsm_wait,
		sms_gsm_error,sms_gsm_fromip,sms_gsm_from,sms_gsm_to,sms_gsm_body,sms_gsm_reject,
		sms_gsm_accept,(void (*)(void *,void **))sms_gsm_msgfree},

	{sms_smpp_init,(void (*)(void **))sms_smpp_free,sms_smpp_recv,sms_smpp_send,sms_smpp_wait,
		sms_smpp_error,sms_smpp_fromip,sms_smpp_from,sms_smpp_to,sms_smpp_body,sms_smpp_reject,
		sms_smpp_accept,(void (*)(void *,void **))sms_smpp_msgfree},
	
	{sms_xml_init,(void (*)(void **))sms_xml_free,sms_xml_recv,sms_xml_send,sms_xml_wait,
		sms_xml_error,sms_xml_fromip,sms_xml_from,sms_xml_to,sms_xml_body,sms_xml_reject,
		sms_xml_accept,(void (*)(void *,void **))sms_xml_msgfree},
	
	{sms_smtp_init,(void (*)(void **))sms_smtp_free,sms_smtp_recv,sms_smtp_send,sms_smtp_wait,
		sms_smtp_error,sms_smtp_fromip,sms_smtp_from,sms_smtp_to,sms_smtp_body,sms_smtp_reject,
		sms_smtp_accept,(void (*)(void *,void **))sms_smtp_msgfree},
	
	{sms_robot_init,(void (*)(void **))sms_robot_free,sms_robot_recv,sms_robot_send,sms_robot_wait,
		sms_robot_error,sms_robot_fromip,sms_robot_from,sms_robot_to,sms_robot_body,sms_robot_reject,
		sms_robot_accept,(void (*)(void *,void **))sms_robot_msgfree}
};

struct sms {
	int (*cb)(Sms *, SMSSTATE, void *, void *);
	void *data,*cb_data;
	SMSMODE mode;
};

typedef struct sms_wait_data {
	SmsMessage *msg;
	Sms *sms;
} SmsWaitData;

Sms *sms_init(SMSMODE x, void *data, int *errcode) {
	Sms *sms = NULL;

	if (x > SMSMODE_MAX) return NULL;

	sms = calloc(1,sizeof(Sms));
	sms->mode = x;

	if (errcode) *errcode = SMS_NO_ERROR;

	sms->data = _functions[sms->mode].initfn(sms,data,errcode);
	if (!sms->data) {
		myfree(sms);
		return NULL;
	}
	return sms;
}
void sms_free(Sms **sms) {
	if (sms && *sms) {
		_functions[(*sms)->mode].freefn(&(*sms)->data);
		myfree(*sms);
	}
}

SMSMODE sms_mode(Sms *sms) {
	if (sms) return sms->mode;
	//not sure what to do here
	return SMS_GSM;
}

int sms_send(Sms *sms, void *data,char *from, char *to, char *message) {
	int x = SMS_PARAM_ERROR;
	if (sms) x = (_functions[sms->mode].sendfn(sms->data,data,from,to,message));
	return x;
}
int sms_wait_th(SmsWaitData *data) {
	srand(time(NULL)+clock());
	data->sms->cb(data->sms,SMS_INCOMING,data->msg,data->sms->cb_data);
	myfree(data);
	return 0;
}
void sms_wait_incoming(Sms *sms, SmsMessage *msg) {
	SmsWaitData *data;
	Thread *th;

	data = calloc(1,sizeof(SmsWaitData));
	data->sms = sms;
	data->msg = msg;	

	th = th_new((int (*)(void *))sms_wait_th,data);	
	th_free(&th);
}
int sms_wait(Sms *sms, long timeout_msec, int (*cb)(Sms *, SMSSTATE, void *, void *), void *cb_data) {
	int errcode = SMS_NO_ERROR;
	SmsMessage *msg;

	if (!sms || !cb) return SMS_PARAM_ERROR;

	sms->cb_data = cb_data;
	sms->cb = cb;	

	while(TRUE) {
		imsg("sms_wait: Wait for event from phone\n");
		msg = _functions[sms->mode].waitfn(sms->data,timeout_msec,&errcode);
		imsg("sms_wait: Got event %d - %p\n",errcode,msg);
		if (errcode) {
			if (!cb(sms,SMS_ERRORCODE,&errcode,cb_data))
				return errcode;
			errcode = 0;
			continue;
		}
		if (msg) {
			imsg("sms_wait: Calling sms_wait_incoming\n");
			sms_wait_incoming(sms,msg);
			imsg("sms_wait: Calling sms_wait_incoming - done\n");
			continue;
		}

		if (!cb(sms,SMS_WAITING,NULL,cb_data)) break;

		lib_msleep(1000);
	}
	return errcode;
}
int sms_msg_recv(Sms *sms, SmsMessage *msg) {
	if (sms && msg) return _functions[sms->mode].recvfn(sms->data,msg);
	return SMS_PARAM_ERROR;
}
int sms_msg_accept(Sms *sms, SmsMessage *msg, int code, char *reason) {
	if (sms && msg) return _functions[sms->mode].acceptfn(sms->data,msg,code,reason);
	return SMS_PARAM_ERROR;
}
int sms_msg_reject(Sms *sms, SmsMessage *msg, int code, char *reason) {
	if (sms && msg) return _functions[sms->mode].rejectfn(sms->data,msg,code,reason);
	return SMS_PARAM_ERROR;
}
char *sms_msg_fromip(Sms *sms, SmsMessage *msg) {
	if (sms && msg) return _functions[sms->mode].fromipfn(sms->data,msg);
	return NULL;
}
char *sms_msg_from(Sms *sms, SmsMessage *msg) {
	if (sms && msg) return _functions[sms->mode].fromfn(sms->data,msg);
	return NULL;
}
char *sms_msg_to(Sms *sms, SmsMessage *msg) {
	if (sms && msg) return _functions[sms->mode].tofn(sms->data,msg);
	return NULL;
}
char *sms_msg_body(Sms *sms, SmsMessage *msg) {
	if (sms && msg) return _functions[sms->mode].bodyfn(sms->data,msg);
	return NULL;
}
void sms_msg_free(Sms *sms, SmsMessage **msg) {
	if (sms && msg) _functions[sms->mode].msgfreefn(sms->data,msg);
}
char *sms_error(Sms *sms, int err, char *bf, int bfsz) {
	if (!sms) ncpy(bf,"Parameter incorrect or NULL",bfsz-1);
	else {
		if (err == SMS_NO_ERROR) ncpy(bf,"No Error Reported",bfsz-1);
		if (err == SMS_PARAM_ERROR) ncpy(bf,"Parameter incorrect or NULL",bfsz-1);
		else _functions[sms->mode].errorfn(sms->data,err,bf,bfsz);
	}	
	return bf;
}
