#ifndef MISC_H
#define MISC_H
#include "cygwin.h"
#include <db.h>
#include <zlib.h>

extern char		*db_server;
extern char		*db_client;
extern char		*db_files ;
extern char		 currentTime_str[32];

void Start_Timer (unsigned int idx);
void Print_Timer (unsigned int idx, const char *msg_str, int msg_int);
void  Ende_Timer (unsigned int idx, const char *msg_str, int msg_int);
void unblock_fd (int fd);
uint32_t IP4Name(const char *host);
z_stream *init_Infalte (void);
z_stream *ende_Infalte (z_stream *ZIP);
int Infalte (z_stream *ZIP,char *in, int in_cnt, char *out, int *out_cnt);

typedef uint8_t tHash[16];
extern char *such_file;
const unsigned char	*md4		(char *txt, size_t len);

#define Free2(dat) 	  free(dat); dat = NULL;

bool 			 nextServer     (struct in_addr *IP, uint16_t *PORT);
bool 			 messageWrite 	(const char *fileName, const char *message);
const unsigned char 	*hash_bin2hex 	(const uint8_t *hash);
const unsigned char	*hash_hex2bin 	(const char *hash_str);

// This implementation assumes an ascii character map for the order of digits.
inline int HexDigit2Int( char hexDigit ) {
	if(hexDigit >= '0' && hexDigit <= '9') return hexDigit - '0';
	if(hexDigit >= 'a' && hexDigit <= 'f') return hexDigit - 'a' + 10;
	if(hexDigit >= 'A' && hexDigit <= 'F') return hexDigit - 'A' + 10;
	printf("HexDigit2Int: bad hex digit: %c\n", hexDigit);
	return -1;
	}

extern DB *dat_hash;
extern DB *dat_idx;

void db_warn  (const char *file, int line, int err);
void db_error (const char *file, int line, int err);
void misc_init(void);

void 	 read_IP_list	(const char *name);
bool     IP_is_OK	(struct in_addr ip);
void 	 ende_IP_list	(void);
void 	 IP_block	(struct in_addr ip);

/* {{{ Source handling
2 B+Tree for eSources
- search for IP
- search for next_time
*/
extern DB  *src_time;

struct eSources {	// size = 4+4+2+16+1+4
	uint8_t		hash[16];
	uint8_t		hash_dl[16];
	struct in_addr	ip;		// <= UNIQUE !!!
	long		ratio;		// + (recv - send) data_bytes
	int 		aktive;
	time_t	 	next_time;
	uint16_t 	port;
	uint16_t	udp_port;
	uint8_t  	prio;
	uint8_t		padding;
	int		version;
	};
void 			 open_Sources       (void);
void 			 close_Sources      (void);
void 			 Delete_src 	    (struct in_addr ip);
void 			 sync_Sources       (void);
void  			 setSource_timeout  (struct in_addr  IP, time_t zeit);
time_t			 addSource 	    (struct in_addr  ip, uint16_t PORT, unsigned version, bool usefull = false);
void 			 delSource 	    (struct in_addr  ip, int err);
bool 			 getSource	    (struct in_addr *ip, unsigned short *port);
void 			 setSources_version (struct in_addr  ip, int    version);
struct eSources 	*Source_ip          (struct in_addr  ip);
int      		 cntSources_aktive  (struct in_addr  IP); // get aktive
void     		 setSources_hash    (struct in_addr  IP, uint8_t *h);
void     		 setSources_hash_dl (struct in_addr  IP, uint8_t *h);
void     		 setSources_udp     (struct in_addr  IP, uint16_t u);
void     		 setSources_aktive  (struct in_addr  IP); // aktive++
void     		 endSources_aktive  (struct in_addr  IP); // aktive--
void   			 chgSources_ratio   (struct in_addr  IP, long ratio);
long   			 getSources_ratio   (struct in_addr  IP            );

// }}}

/* {{{ File list
2 B+Trees for eFiles
- search for IP   and walk through each HASH
- search for HASH and walk through each IP
*/
struct eFiles {
	time_t		since;
	char		hash[16];
	struct in_addr	ip;
	size_t		info_len;
	unsigned char	info[1];
	};
void     close_Files (void);

void 			 insertFiles        	(tHash &hash, struct in_addr ip, size_t info_len, const unsigned char *info);
void 			 deleteFiles_ip  	(struct in_addr ip);
void 			 deleteFiles_hash	(char *hash);
const struct eFiles 	*nextFile 		(const tHash &hash, bool first);
struct eFiles *File_idx (tHash &hash, struct in_addr ip);
// }}}

/* {{{ Server list
1 B+Tree for eServers
- search for IP
*/
struct eServers {
	uint32_t id;
	struct in_addr	 ip;
	uint32_t user;
	uint32_t file;
	size_t	 user_max;
	uint32_t file_max;
	time_t	 next_time;
	time_t	 last_action;
	size_t	 ping_fail;
	time_t   last_ping;
	char	 name[32];
	char	 desc[64];
	uint16_t port;
	uint8_t  prio;
	uint8_t  padding;
	};
void 			  open_Servers  (void);
void 			 close_Servers  (void);
void 			  sync_Servers  (void);
void 			 delServer 	(struct in_addr  ip, uint16_t  port, int err);
bool 			 setServer_prio (struct in_addr  ip, uint16_t  port, uint8_t prio);
bool 			 pongServer	(struct in_addr  ip);
bool 			 saveServer 	(struct in_addr  ip, uint16_t  port,unsigned int files, unsigned int user, bool gui);
bool 			 nextPing 	(struct in_addr *ip, uint16_t *port, uint32_t *challange);
bool 			 actionServer   (struct in_addr  ip, uint16_t  port);
bool   			 setServer_name (struct in_addr  ip, uint16_t  port, const char *name);
bool   			 setServer_desc (struct in_addr  ip, uint16_t  port, const char *desc);
const struct eServers 	*nextServers    (bool first);
      struct eServers 	*Server_ip      (struct in_addr  ip);

// }}}

class cServer_list {
	public:
static	void	Save (void);
static	void	Load (void);
	};
      
extern int cursor_count;

unsigned cntFiles    (void);
unsigned cntSource   (void);
unsigned cntServer   (void);
bool encode64(const char *_in, unsigned inlen, char *_out, size_t  outmax, size_t *outlen);
bool decode64(const char * in, unsigned inlen, char * out, size_t *outlen);


// vim:fdm=marker
#endif
