#ifndef	__MDA_H__
#define	__MDA_H__

#define __STDC_FORMAT_MACROS
#define _GNU_SOURCE

#ifdef WIN32
# define _WIN32_WINNT 0x0500
# define DEFAULT_MAP_NAME "Global\\Millistream Database Application Perfcounters"
#else
# define DEFAULT_MAP_NAME "/millistream-mda-map"
#endif

#define	DATABASE_SIZE		100000		// instruments with orderbook
#define	QUEUEINDEX_SIZE		100000		// hashsize for strangling
#define	TABLEDEFINITION_SIZE	100
#define	DATABASE_MAX_DISCONNECTED_TIME	60	// 10 minuter
#define	SQLSTRING_MINSIZE	1024
#define NUM_QUEUES 4
#define	MDA_VERSION	"0.9.59"


# ifndef WIN32
#include <zlib.h>
#include <mdf/mdf.h>
#include <mdf/mdf_fields.h>
#include <hashit.h>

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/utsname.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h> 
#include <pthread.h>
#include <sys/time.h>
#include <sys/select.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <inttypes.h>
#include <semaphore.h>
#include <ctype.h>
#include <syslog.h>
#include <pwd.h>
#include <grp.h>
#include <termios.h>
# ifdef HAVE_LIBSYSTEMD
#  include <systemd/sd-daemon.h>
# endif
# else
#include <winsock2.h>
#include <windows.h>
#include <sddl.h>
#include <time.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <process.h>
#include <direct.h>
#include <zlib.h>
#include <mdf/mdf.h>
#include <mdf/mdf_fields.h>
#include <hashit.h>
#include <limits.h>

#define uint8_t	unsigned char
#define uint32_t unsigned __int32
#define uint64_t unsigned __int64
#define PRIu32	"u"
#define PRIu64  "I64u"
#define PRIu8	"hu"

#ifndef UINT64_MAX
#define UINT64_MAX 1844674407370955161
#endif

# endif

#include <stdbool.h>
#include "mdamodule.h"
#include "files.h"
#include "log.h"

# ifndef WIN32
void signal_handler ( int sig );
# define MUTEX_LOCK(A) pthread_mutex_lock(A)
# define MUTEX_UNLOCK(A) pthread_mutex_unlock(A);
# else 
# define MUTEX_LOCK(A) EnterCriticalSection(A)
# define MUTEX_UNLOCK(A) LeaveCriticalSection(A)
BOOL signal_handler(DWORD fdwCtrlType) ;
struct tm *gmtime_r (const time_t *clock, struct tm *result);
struct tm *localtime_r (const time_t *clock, struct tm *result);
# endif

#define	MDA_SQL_ONETRY		0
#define	MDA_SQL_UPDATEFIRST	1
#define	MDA_SQL_INSERTFIRST	2
#define	MDA_SQL_FAIL_ON_0	3

#define	MDA_TYPE_TRADE					1        // hashid = insref:0x01:tradereference
#define	MDA_TYPE_QUOTE					2        
#define	MDA_TYPE_PRICEHISTORY				4        
#define	MDA_TYPE_BASICDATA				6	 
#define	MDA_TYPE_ORDERBOOKFLUSH			7
#define	MDA_TYPE_INSTRUMENTRESET			8
#define	MDA_TYPE_INSTRUMENTDELETE			9
#define	MDA_TYPE_CORPORATEACTION			11
#define	MDA_TYPE_LISTMAPPING				12
#define	MDA_TYPE_NEWS					13
#define	MDA_TYPE_BIDORDER				14	// Special for orderbooks 3 messages -> 1 message
#define	MDA_TYPE_ASKORDER				15	// Special for orderbooks 3 messages -> 1 message
#define	MDA_TYPE_FUNDAMENTALS				16
//#define	MDA_TYPE_TRADESTATE				17	// not used, availible for new message
#define	MDA_TYPE_PERFORMANCE				18
#define	MDA_TYPE_KEYRATIOS				19
#define	MDA_TYPE_ESTIMATES				20
#define	MDA_TYPE_ESTIMATESHISTORY			21
#define	MDA_TYPE_NETORDERIMBALANCE			22
#define	MDA_TYPE_CONSTITUENTS				23
#define	MDA_TYPE_TICKSIZES				24
#define	MDA_TYPE_BROKERS				25
#define	MDA_TYPE_CI					26
#define	MDA_TYPE_CIHISTORY				27
#define	MDA_TYPE_INTERNALSTATUS			30
#define	MDA_TYPE_L10N    				32
#define	MDA_TYPE_PRIIP    				33
#define	MDA_TYPE_MIFID    				34
#define	MDA_TYPE_MIFIDHISTORY  			35
#define	MDA_TYPE_MAPPINGS  				36
#define	MDA_TYPE_GREEKS  				37
#define	MDA_TYPE_MBO	  				38
#define	MDA_TYPE_QUOTEBBO  				39
#define	MDA_TYPE_QUOTEEX  				40
#define MDA_TYPE_EET                                    41
#define MDA_TYPE_AGGTRADE                               245
#define	MDA_TYPE_COMBOLEGS				246
#define	MDA_TYPE_QUOTEBBOFLUSH				247
#define	MDA_TYPE_SECTORS				248
#define	MDA_TYPE_NEWSTAGS				249
#define	MDA_TYPE_UNDERLYINGS				250
#define	MDA_TYPE_ORDERBOOK				251
#define	MDA_TYPE_ADJUSTEDPRICEHISTORY			252
#define	MDA_TYPE_ADJUSTHISTORY				253
#define	MDA_TYPE_DIFFCALC				254
#define	MDA_TYPE_NEWSCODING				255

#define	MDA_OPTION_NOHASH				0
#define	MDA_OPTION_HASH				1
#define	MDA_OPTION_CANCELTRADE				2
#define	MDA_OPTION_EMPTY				4
#define	MDA_OPTION_NEWSHASHEADLINE			8
#define	MDA_OPTION_NEWS_LASTBLOCK			16
#define	MDA_OPTION_BIDORDERINSERT			32
#define	MDA_OPTION_BIDORDERUPDATE			64
#define	MDA_OPTION_BIDORDERDELETE			128
#define	MDA_OPTION_ASKORDERINSERT			256
#define	MDA_OPTION_ASKORDERUPDATE			512
#define	MDA_OPTION_ASKORDERDELETE			1024
#define	MDA_OPTION_CLOSEPRICE				2048
#define	MDA_OPTION_CLOSEYIELD				4096
#define	MDA_OPTION_CLOSEBIDPRICE			8192
#define	MDA_OPTION_CLOSEBIDYIELD			16384
#define	MDA_OPTION_DELETERECORD			32768
#define	MDA_OPTION_NEWSHAVECODING			65536
#define	MDA_OPTION_TRADESTATE				131072 /* since TradeState have no type of their own in MDA */
#define	MDA_OPTION_NEWSHAVECODINGTAGS			262144
#define	MDA_OPTION_UPDATEFIRST				524288
#define	MDA_OPTION_DELETEFIRST				1048576
#define	MDA_OPTION_FLUSH_MBL				2097152
#define	MDA_OPTION_FLUSH_MBO				4194304

#define MDF_F_UNIXTIME  4294967295

#define	SQL_DEFAULT_ADDLEN			50

typedef struct	Orderbook_s {	// size 24
	struct	Orderbook_s	*next;
	struct	Orderbook_s	*previous;
	char	*price;
} Orderbook;

typedef	struct	Instrument_s {		// size 32
	uint64_t insref;
	struct	Orderbook_s *askorders;
	struct	Orderbook_s *bidorders;
	uint32_t numbidorders;
	uint32_t numaskorders;
} Instrument;

typedef struct PriceType_s {
	uint64_t insref;
	int type;
} PriceType;

typedef	struct	Tabledef_s {	// size 38
	char	*tablename;
	char	*fieldname;
	char	*fieldname2;
	char	*factor;
	char	*hashkey;
	char 	*fieldnumber;
	char	*messages;
	char	*type;
	char	*len;
	size_t	maxlen;
	uint32_t messagenumber;
	int     numerical; /* set to 1 if field is numerical, i.e it doesn't need sql escaping etc */
	uint8_t	keyvalue;
	uint8_t insertfirst;
	uint8_t	nullable;
	uint8_t _unsigned;
	uint8_t calc; /* 0 (no), 1 (value/price), 2 (price/value), 3 (price*value) */
} Tabledef;

typedef struct Sqlstring_s {	// size 48
	char	*sqlstring;
	char	*whereclause;
	size_t	sqlused;
	size_t	sqlsize;
	size_t	whereused;
	size_t	wheresize;
} Sqlstring;

typedef struct Queuefield_s {	// size 28
	struct		Queuefield_s *next;
	struct 		Queuefield_s *previous;
	char		*value;
	uint32_t	field;
} Queuefield;

typedef	struct Queueitem_s {	// 95 bytes
	struct		Queueitem_s *next;
	struct		Queueitem_s *previous;
	struct		Queuefield_s *fields;
	struct		Queueitem_s *bidorders;
	struct		Queueitem_s *askorders;
	char		*key;
	char		*orderprice;		// change to price and use for lastprice in quotes for performance to stop useing queueitems for diffcalc
	char		*orderyield;		// use for lastyield in quotes for performance to stop useing queueitems for diffcalc
	char		*bidprice;
	char		*bidyield;
	uint64_t	insref;
	uint64_t	orderid;
	time_t		timestamp;		// used for wait time in queue
	uint32_t	option;
	uint8_t		type;
	uint8_t		haslastprice;
	uint8_t		hasbidprice;
	uint8_t		haslastyield;
	uint8_t		hasbidyield;
} Queueitem;

typedef struct {
	uint64_t	items;
	uint64_t	empty;
	uint64_t	updates;
	uint64_t	dedup;
	uint64_t	failed;
} Queuestats;

typedef struct {
	Queueitem	*head;
	Queueitem	*tail;
	Queueitem	*nowaitptr;
	Sqlstring	*sqlbuildstring;
	char		*transaction;
	void		*dbhandle;
	hash_t		queueindex;
	Queuestats	*stats;
#ifndef WIN32
	pthread_mutex_t	lock;
	void		*modhandle;
	sem_t		itemevent;
#else
	CRITICAL_SECTION lock;
	HINSTANCE	modhandle;
	HANDLE		itemevent;
#endif
	long		mintimebetweenupdates;
	int		dbstatus;
	int		num_transactions;
	int		pos;
	uint8_t		upsert;
} Queue;

typedef struct {
	char		*newsid;
	char		*orderprice;
	char		*orderlevel;
	uint64_t	insref;
	uint64_t	orderid;
	char		tmpkey[256];
	uint32_t	keylen;
	uint32_t	option;
	uint8_t		adjustmentfactor;
	uint8_t		mdatype;

} MessageInfo;

typedef struct
{
	mod_config	mod_config;
	char		*modulefile;
	char		*millistreamusername;
	char		*millistreampassword;
	char		*insrefs;
	char		*logfacility;
	char		*loghost;
	char		*logsqlpath;
# ifndef WIN32
	char		*applicationuser;		
	char		*applicationgroup;		
	char		*pidfile;
# else
	char		*domain;
	char		*domainuser;
	char		*domainpassword;
	char		*overridedomainuser;
	HANDLE		domaintoken;
# endif
	void		*dbhandle;				// handle to module lib file
	char		*quotefields;
	char		*quotebbofields;
	char		*noiifields;
	char		*greeksfields;
	char		*configfilename;
	char		*tabledeffile;
	char		*overrideusr;
	char		*import_fname;
	char		*map_name;
	FILE		*fd_sqllog;
	Tabledef        **keyratios;
	uint64_t	instrumentslimit;	/* max insref to check for delete if not received thru Basic Data */
	uint64_t	file_templates_ver;
	uint64_t	feed_templates_ver;
	unsigned int	databasehashsize;
	unsigned int	queuehashsize;
	uint32_t	quotefieldslen;
	uint32_t	quotefieldsused;
	uint32_t	quotefieldscount;
	uint32_t	quotebbofieldslen;
	uint32_t	quotebbofieldsused;
	uint32_t	quotebbofieldscount;
	uint32_t	noiifieldslen;
	uint32_t	noiifieldsused;
	uint32_t	noiifieldscount;
	uint32_t	greeksfieldslen;
	uint32_t	greeksfieldsused;
	uint32_t	greeksfieldscount;
	uint32_t	reconnectinterval;
	uint32_t	mintimebetweenupdates;
	uint32_t	databasekeepdeleted;
	uint32_t	maxdeletes;
	int             keyratios_num;
	int		currentday;
//	int		canceltrades;
	int		dbstatus;
	int		do_syslog;
	int		show_status;
	int		daemonize;
	int		requestTrades;
	int		requestOrderbooks;
	int		requestBasicdata;
	int		requestQuotes;
	int		requestQuotesBBO;
	int		requestQuotesEx;
	int		requestPricehistory;
	int		requestCorporateactions;
	int		requestNews;
	int		requestFundamentals;
	int		requestTradestate;
	int		requestPerformance;
	int		requestKeyratios;
	int		requestEstimates;
	int		requestNOII;
	int		requestL10N;
	int		requestCI;
	int		requestPRIIP;
	int		requestMIFID;
	int		requestMappings;
	int		requestGreeks;
	int		requestMBO;
	int		requestEET;
	int		checkdatabase; /* from config file */
	int		perform_check; /* from command line */
	int		perform_checktypes; /* from command line */
	int		silent;
	int		uselocaltime;
	int		useunixtime;
	int		upgradedb;
	int		transactions;
	int		max_timelen;
	int		debuglog;
	int		quoteExspecial;
	int		aggtrades;
	bool		disable_upsert;
# ifndef WIN32
	int		change_user_early;
# endif
}	settings;

typedef	struct {
	_Atomic uint64_t receivedmessages;
	_Atomic uint64_t connected_to_feed;
	Queuestats	queuestat[NUM_QUEUES];
	uint64_t	file_templates_ver;
	uint64_t	feed_templates_ver;
	size_t		database_hashsize_max;
	size_t		database_hashsize;
#ifndef WIN32
	time_t		last_update_stats;
	pid_t		pid;
#endif
}	statistics;

struct receiver {
	char *server;
	char *username;
	char *password;
	_Atomic time_t live;
	mdf_t handle;
	_Atomic bool connected;
	bool received_all_basicdata;
	bool r_ignore;
	bool r_trades;
	bool r_order;
	bool r_basic;
	bool r_quote;
	bool r_quotebbo;
	bool r_quoteex;
	bool r_ph;
	bool r_ca;
	bool r_news;
	bool r_fund;
	bool r_tradestate;
	bool r_perf;
	bool r_keyr;
	bool r_estimates;
	bool r_noii;
	bool r_l10n;
	bool r_ci;
	bool r_ept;
	bool r_emt;
	bool r_mappings;
	bool r_greeks;
	bool r_mbo;
	bool r_eet;
};

typedef struct	Modulefunctions_s {
	int (*init)();
	int (*exit)();
	int (*connect) (void *_handle);
	int (*disconnect)(void *_handle);
	int (*getlasterror)(void *_handle);
	char *(*geterrorstring)(void *_handle);
	int (*executesql)(void *_handle, char *_queary);
	char *(*add_value)(void *_handle, char *_value, size_t maxlen);
	void *(*create)(mod_config *cfg);
	int (*destroy)(void *_handle);
	uint8_t	(*get_status)(void *handle);
	void (*set_status)(void *handle, uint8_t status);
	Databaseinfo *(*get_databaseinfo)(void *handle);
	void *(*querysql)(void *_handle,char *_query, int *returncode);
	void (*freeresult)(void *_handle);
	void (*free_databaseinfo)(Databaseinfo *dbinfo);
	uint8_t (*add_column)(void *handle,char *table,char *column,char *type,char *len,uint8_t nullable,int _unsigned,int command);
	int (*get_info)(void *handle, mod_info *modinfo, int modinfolen);
	void (*reconnect)(void *handle);
} Modulefunctions;

typedef struct FACILITYMAP_S {
	const char *name;
	int facility;
} FACILITYMAP;


extern settings config;
extern hash_t Tabledefinitions;
extern Modulefunctions modfunc;
extern Sqlstring *sqlbuildstring;
extern Queue *queues;

extern struct receiver *receivers;
extern int receivers_num;

int	init ();
# ifndef WIN32
void	*mda_database_update_thread (void	*_arg);
void	*status_thread (void	*_arg);
void	*mdf_receiver_thread (void	*_arg);
# else
void WINAPI ServiceMain (unsigned long argc, char **argv);
void	mdf_receiver_thread (void	*_arg);
void	mda_database_update_thread (void	*_arg);
void	status_thread (void	*_arg);
# endif

//	sqlbuilds.c 
int 	get_gmtime(char	*dest, uint8_t	_type );
int 	get_gmdate(char	*dest, uint8_t	_type );
int	build_internalstatus(Queue *queue,Queueitem	*_workitem,Tabledef *_def, statistics *stats);
int	build_orderbookflush (Queue *queue, Queueitem *_workitem);
int	build_instrumentdelete(Queue *queue,Queueitem *_workitem);
int	build_quotereset (Queue *queue,Queueitem *_workitem,Tabledef *_def);
int	build_quotebboreset (Queue *queue,Queueitem *_workitem,Tabledef *_def);
int	build_noiireset (Queue *queue,Queueitem *_workitem,Tabledef *_def);
int	build_greeksreset (Queue *queue,Queueitem *_workitem,Tabledef *_def);
int	build_tradecanceldelete2 (Queue *queue,Queueitem *_workitem,Tabledef *_def);
int	build_tradecancelinsert2 (Queue *queue,Queueitem *_workitem,Tabledef *_def);
int	build_updatestring2 (Queue *queue,Queueitem *_workitem,Tabledef *_def, const PriceType * const pt) ;
int	build_historicaldelete(Queue *queue,Queueitem *_workitem,Tabledef *_def);
int	build_upsert (Queue *queue,Queueitem *workitem, Tabledef *def, const PriceType * const pt);
int	build_insertstring2 (Queue *queue,Queueitem	*_workitem,Tabledef *_def, const PriceType * const pt);
int	build_newscoding (Queue *queue,Queueitem *_workitem,Tabledef *_def);
int	build_tabular (Queue *queue,Queueitem *_workitem, Tabledef *_def);
int	runAggTrade (Queue *queue, Queueitem *workitem, Tabledef *def);
int	build_newstags (Queue *queue, Queueitem *workitem, Tabledef *def);
int	build_sectors (Queue *queue, Queueitem *workitem, Tabledef *def);
int	build_listmappings (Queue *queue, Queueitem *workitem, Tabledef *def);
int	build_keyratios_calc (Queue * queue, Queueitem *workitem);
int	get_adjustmentfactor(Queue *queue,Queueitem *_workitem,Tabledef *_def);
int	adjusthistory(Queue *queue,Queueitem	*_workitem,Tabledef *_def);
int	build_orderbookstrings2(Queue *queue,Queueitem	*_workitem, Tabledef *_def);
char	*sql_getcloseprice(Queue *queue, uint64_t insref, int * const ret);
char	*sql_getlastprice(Queue *queue,uint64_t	_insref, const PriceType * const pt, int * const ret);
char	*sql_getlastyield(Queue *queue,uint64_t	_insref, int * const ret);
char	*sql_getbidprice(Queue *queue,uint64_t	_insref, int * const ret);
char	*sql_getbidyield(Queue *queue,uint64_t	_insref, int * const ret);
int 	build_diffcalc(Queue * queue,Queueitem *workitem);
int	build_diffex(Queue * queue,Queueitem *workitem);
int	clear_performancediffs(Queue *queue,Queueitem *_workitem);

int runSqlQuery(Queue *queue,uint8_t firstTry,const char * const fname, const int line);
mod_result *querySql(Queue *queue, int * const ret,const char * const fname, const int line);
#endif

