#ifndef _GSMLib_Header
#define _GSMLib_Header
#include <windows.h>

#define GSM_BFSZ 1024

struct gsm_struct;
typedef struct gsm_struct Gsm;

struct gsm_message;
typedef struct gsm_message GsmMsg;

struct gsm_message {	
	char memory[GSM_BFSZ];				/* only present if msg obtained by the notify callbk */

	int index;

	char status[GSM_BFSZ];
	char phone[GSM_BFSZ];
	char alpha[GSM_BFSZ];				/* optional, empty if not given */
	char timestamp[GSM_BFSZ];

	int type_of_originating_address;	/* optional, 0 if not given */
	int first_octet_of_sms;				/* optional, 0 if not given */
	int protocal_identifier;			/* optional, 0 if not given */
	int data_coding_sceme;				/* optional, 0 if not given */
	
	char service_center[GSM_BFSZ];		/* optional, empty if not given */
	int type_of_service_center;			/* optional, 0 if not given */

	int length;							/* optional, 0 if not given */
	
	char message[GSM_BFSZ];

	GsmMsg *next;
};

struct gsm_struct {
	char error[GSM_BFSZ], readbf[GSM_BFSZ];
	void (*callbk)(GsmMsg *);
	OVERLAPPED sync;
	HANDLE gsm;
	DCB dcb;
	COMMTIMEOUTS timeouts;
	int inlen;	
};

/* Create new blank gsm structure
*/
Gsm *gsm_new(void (*fn)(GsmMsg *));


/* Open com port
gsm             = gsm struct (gsm_new)
comport         = com port number ie. 1
*/
int gsm_open(Gsm *gsm, int comport);


/* Close com port
gsm             = gsm struct (gsm_new/gsm_open)
*/
int gsm_close(Gsm *gsm);


/* Free gsm struct
gsm             = gsm struct (gsm_new/gsm_open)
This fn will call gsm_close if reqd
*/
void gsm_free(Gsm **gsm);


/* Write to com port
gsm             = gsm struct (gsm_new/gsm_open)
string          = gsm command string
...             = additional args
*/
int gsm_write(Gsm *gsm, char *string, ...);


/* Read from com port, returns:
  -1 for timeout
  FALSE for error

gsm             = gsm struct (gsm_new/gsm_open)
bf              = buffer to read into
bfsz            = size of buffer
read_raw        = this flag causes the read to return an incoming message notification if it reads it
                  instead of notifying you via the callback and ignoring it.
milli           = timeout in milliseeconds, specify INFINITE to block
*/
int gsm_readline_raw(Gsm *gsm, char *bf, int bfsz, int milli, int read_raw);
#define gsm_readline(a,b,c,d) gsm_readline_raw(a,b,c,d,FALSE)


/* Reads from com port, clearing incoming and ring messages.
   Returns FALSE if it fails to read, -TRUE if it reads something that is not one of the above, and
   TRUE if all is well.
gsm             = gsm struct (gsm_new/gsm_open)
milli           = timeout in milliseeconds, specify INFINITE to block
*/
int gsm_poll(Gsm *gsm, int milli);


/* Ask for notification of new text messages
gsm             = gsm struct (gsm_new/gsm_open)
mode            = TRUE for on, FALSE for off
*/
int gsm_text_notify(Gsm *gsm, int mode, void (*fn)(GsmMsg *));


/* Reads a message sent to you by notify function
gsm             = gsm struct (gsm_new/gsm_open)
msg             = message passed by callbk of notify fn
*/
int gsm_text_recv(Gsm *gsm, GsmMsg *msg);

/* Reads all stored text messages, up to length
gsm             = gsm struct (gsm_new/gsm_open)
stored          = array of pointers to Gsm message structs
length          = length of the array
read            = number of elements read
*/
int gsm_text_stored(Gsm *gsm, GsmMsg *stored[], int length, int *read);


/* Delete a text message from memory
gsm             = gsm struct (gsm_new/gsm_open)
msg             = gsm message to delete
*/
int gsm_text_delete(Gsm *gsm, GsmMsg *msg);


/* Send a text message
gsm             = gsm struct (gsm_new/gsm_open)
phone           = phone number to deliver to
message         = message text
*/
int gsm_text_send(Gsm *gsm, char *phone, char *message);


/* Answers a ring and hangs up immediately
gsm             = gsm struct (gsm_new/gsm_open)
*/
int gsm_clear_ring(Gsm *gsm);


/* Free gsm message struct
msg             = pointer to gsm message struct
*/
void gsm_msg_free(GsmMsg **msg);


/* Returns true if bf contains a ring message
bf              = return string from gsm_read_raw with read_raw set to TRUE
*/
int gsm_isring(char *bf);


/* Returns msg struct if bf contains incoming message notification, otherwise NULL
bf              = return string from gsm_read_raw with read_raw set to TRUE
*/
GsmMsg *gsm_isincoming(char *bf);


/* Returns TRUE if bf contains an error return, set that error so gsm_error can return it nicely.
gsm             = gsm struct (gsm_new/gsm_open)
bf              = return string from gsm_read or gsm_read_raw
*/
int gsm_iserror(Gsm *gsm, char *bf);


/* Returns error code if present, -1 if not present and -2 if string is not an error.
bf              = return string from gsm_read or gsm_read_raw
*/
int gsm_errcode(char *bf);


/* Returns error string relating to last gsm fn that returned an error, or empty string for no error.
   Error string remains until replaced by another error or until gsm_clear_error is called.
gsm             = gsm struct (gsm_new/gsm_open)
*/
char *gsm_error(Gsm *gsm);


/* Clears error message from failed fn call
gsm             = gsm struct (gsm_new/gsm_open)
*/
void gsm_clear_error(Gsm *gsm);

#endif
