#ifndef _Conn_h
#define _Conn_h 1

#include "Conn_config.h"

#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/socket.h>

struct Conn;
struct Conn_wpool;
struct Conn_split;
struct Conn_ws;

/* Parameters */
enum CONN_PARA {
        CONN_PARA_AUTO_RECONNECT = 0,
	CONN_PARA_RECONNECT_DELAY,
	CONN_PARA_IDLE_TIME,
	CONN_PARA_READ_TIMEOUT,
	CONN_PARA_CONN_TIMEOUT,
	CONN_PARA_TRIGGER,
	CONN_PARA_IBUF,
	CONN_PARA_OBUF
};

/* Callbacks */
enum CONN_CB {
	CONN_CB_ACCEPT = 0,
	CONN_CB_RECV,
	CONN_CB_SEND,
	CONN_CB_DATA,
	CONN_CB_CLOSE,
	CONN_CB_TRIGGER,
	CONN_CB_ERROR,
	CONN_CB_CONNECTED,
	CONN_CB_ACCEPT_ERROR
};

/* misc */
void		Log(const unsigned short level, char *format, ...);
char		*Conn_dump(const void *buf_src0, const size_t len_src);
char		*Conn_dumphex(const void *buf_src0, const size_t len_src);
void		Conn_debug(int fd, const unsigned short debug);

/* split */
void			Conn_split_free(struct Conn_split **s);
struct Conn_split	*Conn_split(const char *line0);
char			*Conn_split_get_size(const struct Conn_split *s,
					const char *left, unsigned int *size);
char			*Conn_split_get_e(const struct Conn_split *s,
					const char *l);
char			*Conn_split_get(const struct Conn_split *s,
					const char *l);
unsigned long		Conn_split_get_ul(const struct Conn_split *s,
					const char *l, unsigned int base);
unsigned long long	Conn_split_get_ull(const struct Conn_split *s,
					const char *l, unsigned int base);
double			Conn_split_get_d(const struct Conn_split *s,
					const char *l);

/* conn */
unsigned long long	Conn_lifetime(struct Conn *C);
char			*Conn_strerror(void);
long long		Conn_time_diff(const struct timeval *t1,
				const struct timeval *t2);
char			*Conn_errno(const struct Conn *C);
char			*Conn_status(const unsigned int flags);

void			Conn_set_private(struct Conn *C, void *priv);
void			*Conn_get_private(struct Conn *C);
unsigned int		Conn_iqlen(const struct Conn *C);
unsigned int		Conn_oqlen(const struct Conn *C);
unsigned int		Conn_qlen(const struct Conn *C);
int			Conn_nodelay(const struct Conn *C);
void			Conn_rollback(struct Conn *C, const unsigned int bytes);
char			*Conn_ibuf(const struct Conn *C);
char			*Conn_obuf(const struct Conn *C);
unsigned long long	Conn_getid(const struct Conn *C); /* Obsolete */
unsigned long long	Conn_get_id(const struct Conn *C);
struct Conn		*Conn_get(const unsigned long long id);
void			Conn_last_time(const struct Conn *C, struct timeval *tv);
int			Conn_set_cb(struct Conn *C, const unsigned int cb_type,
				void (*f)(struct Conn *));
char			*Conn_ostrstr(struct Conn *C, const unsigned int off,
				const char *str, const unsigned int flags);
char			*Conn_strstr(struct Conn *C, const char *str);
char			*Conn_strcasestr(struct Conn *C, const char *str);
char			*Conn_get_line(struct Conn *C);
void			Conn_for_every_line(struct Conn *C,
				void (*cb)(struct Conn *C, char *line));
int			Conn_printf(struct Conn *C, const char *format, ...);
void			Conn_eat(struct Conn *C, const unsigned int bytes);
void			Conn_eatall(struct Conn *C);
void			Conn_send_done(struct Conn *C);
void			Conn_close(struct Conn *C);
void			Conn_stop(void);
void			Conn_set(struct Conn *C, const unsigned int var,
				const int val);
char			*Conn_addr_local(struct Conn *C);
char			*Conn_addr_remote(struct Conn *C);
int			Conn_port_local(struct Conn *C);
int			Conn_port_remote(struct Conn *C);
int			Conn_addr_family(const char *addr);

/* wpool */
struct Conn_wpool	*Conn_wpool_create(const unsigned short workers);
int			Conn_wpool_destroy(struct Conn_wpool *wp);
void			Conn_set_wp(struct Conn *C, struct Conn_wpool *wp);
void			Conn_del_wp(struct Conn *C, struct Conn_wpool *wp);

/* conn 2 */
int		Conn_init(const unsigned int max);
int		Conn_shutdown(void);
int		Conn_enqueue_wait(struct Conn *C, const void *buf,
			const unsigned int count);
int		Conn_enqueue(struct Conn *C, const void *buf,
			const unsigned int count);
void		Conn_kick(struct Conn *C);
struct Conn	*Conn_alloc(void);
int		Conn_set_socket_domain(struct Conn *C, const int domain);
int		Conn_set_socket_type(struct Conn *C, const int type);
int		Conn_set_socket_protocol(struct Conn *C, const int proto);
int		Conn_set_socket_bind_addr(struct Conn *C, const char *addr);
int		Conn_set_socket_addr(struct Conn *C, const char *addr);
int		Conn_set_socket_bind_port(struct Conn *C, const int port);
int		Conn_set_socket_port(struct Conn *C, const int port);
int		Conn_commit(struct Conn *C);
struct Conn	*Conn_socket_addr(const int domain, const int type,
			const char *addr, const int port);
struct Conn	*Conn_socket(const int domain, const int type,
			const int port);
struct Conn	*Conn_connect(const int domain, const int type,
			const char *addr, const int port);
int		Conn_band(struct Conn *C, const unsigned int width,
			const unsigned int factor);
int		Conn_poll(const int timeout);

/* web server */
int		Conn_web_create(struct Conn *C);
int		Conn_web_script(struct Conn *C, const char *url,
			void(*cb)(struct Conn *C));
int		Conn_web_path(struct Conn *C, const char *url,
			const char *path);
char		*Conn_web_header(const struct Conn *C);
int		Conn_web_header_lookup(char *out, const size_t out_size,
			const struct Conn *C, const char *h);


/* web server - websocket */
struct Conn_web_ws
{
	unsigned char		fin:1;
	unsigned char		opcode:4;
	unsigned char		mask:1;
	unsigned char		maskkey[4];
	unsigned long long	len;
};

char		Conn_web_is_ws(const struct Conn *C);
void		Conn_web_ws_negociate(struct Conn *C);
void		Conn_web_ws_enqueue(struct Conn *C,
			const unsigned char opcode, const unsigned char final,
			const char *s, const unsigned int len);
void		Conn_web_ws_log(const struct Conn_web_ws *w);
int		Conn_web_ws_parse(struct Conn_web_ws *w, struct Conn *C);

#endif
