#ifndef __MULTI
#define __MULTI

#define SERVER 1
#define CLIENT 2

#define ADVERTISE_IP	"230.3.3.3"
#define ADVERTISE_PORT	59000
#define FTRANSFER_PORT	59001
#define SERVER_IP	"127.0.0.1"
#define SERVER_PORT	50000
#define DEFAULT_IP	"231.0.0."
#define INTERVAL        5               /* advertise interval */
#define MAXBUF		1024
#define MAXCON		16
#define MAXCLIENT	255
#define EMPTY		MAXCLIENT
#define IDLENGTH	32
#define LOCKTIME	10
#define CALC_INTERVAL	3000		/* calcrate_interval */
#define RESEND_INTERVAL	10000		/* resend_interval */

#define ROW_MAX		4
#define COLUMN_MAX	4
#define TAB_MAX		16
#define TABGROUP_MAX	32
#define WINDOW_WIDTH	800
#define WINDOW_HEIGHT	600
#define EXWINDOW_WIDTH	600
#define EXWINDOW_HEIGHT 400
#define CONFIG_FILE	"/etc/multivnc/multivnc_server.conf"
#define CAST_PK_SIZE	1400
#define INPUT_PRIORITY	120
#define STRLENGTH	64
// save to *.swf file (recorded file) in this directory
// char limit is IDLENGTH * 2 = 32 char
#define REC_PATH	"/tmp/"
#define SWF_DATA	1024
#define SLEEP		2

#define START		1
#define STOP		0
#define CONTINUE	-1

/* client state */
#define STAT_FIRST	0
#define STAT_ADV	1
#define STAT_VNC	2
#define STAT_CUT	3
#define STAT_REC	4
#define STAT_FILE	5

/* casting state */
#define CAST_WAIT       0
#define CAST_SEND       1
#define CAST_STOP       2

/* state parameter */
#define RESENDSTATE	0x01	/* クライアントからの全画面の要求 */
#define RECSTATE	0x02	/* 録画中 */
#define CTRLSTATE	0x04	/* 画面操作 */
#define VIEWSTATE	0x08	/* 画面拡大表示 */
#define FILESTATE	0x10	/* ファイル転送 */
#define SENDSTATE	0x20    /* 画面配信の送信者 */
#define RECVSTATE	0x40	/* 画面配信の受信者 */
#define LOCKSTATE	0x80	/* ロック中 */

#if 1
/* for server */
#define GETLOCK(Num)		(server_CB.client_grp[(Num)]->state & LOCKSTATE)?1:0
#define SETLOCK(Num, Flag)	(Flag)?(server_CB.client_grp[(Num)]->state |= LOCKSTATE):\
					(server_CB.client_grp[(Num)]->state &= ~LOCKSTATE)
#define GETRECV(Num)		(server_CB.client_grp[(Num)]->state & RECVSTATE)?1:0
#define SETRECV(Num, Flag)	(Flag)?(server_CB.client_grp[(Num)]->state |= RECVSTATE):\
                                        (server_CB.client_grp[(Num)]->state &= ~RECVSTATE)
#define GETSEND(Num)		(server_CB.client_grp[(Num)]->state & SENDSTATE)?1:0
#define SETSEND(Num, Flag)	(Flag)?(server_CB.client_grp[(Num)]->state |= SENDSTATE):\
                                        (server_CB.client_grp[(Num)]->state &= ~SENDSTATE)
#define GETVIEW(Num)		(server_CB.client_grp[(Num)]->state & VIEWSTATE)?1:0
#define SETVIEW(Num, Flag)	(Flag)?(server_CB.client_grp[(Num)]->state |= VIEWSTATE):\
                                        (server_CB.client_grp[(Num)]->state &= ~VIEWSTATE)
#define GETCTRL(Num)		(server_CB.client_grp[(Num)]->state & CTRLSTATE)?1:0
#define SETCTRL(Num, Flag)	(Flag)?(server_CB.client_grp[(Num)]->state |= CTRLSTATE):\
                                        (server_CB.client_grp[(Num)]->state &= ~CTRLSTATE)
#define GETCTRL(Num)		(server_CB.client_grp[(Num)]->state & CTRLSTATE)?1:0
#define SETCTRL(Num, Flag)	(Flag)?(server_CB.client_grp[(Num)]->state |= CTRLSTATE):\
                                        (server_CB.client_grp[(Num)]->state &= ~CTRLSTATE)
#define GETRESEND(Num)		(server_CB.client_grp[(Num)]->state & RESENDSTATE)?1:0
#define SETRESEND(Num, Flag)	(Flag)?(server_CB.client_grp[(Num)]->state |= RESENDSTATE):\
                                        (server_CB.client_grp[(Num)]->state &= ~RESENDSTATE)
#define GETREC(Num)		(server_CB.client_grp[(Num)]->state & RECSTATE)?1:0
#define SETREC(Num, Flag)	(Flag)?(server_CB.client_grp[(Num)]->state |= RECSTATE):\
                                        (server_CB.client_grp[(Num)]->state &= ~RECSTATE)

#define GETFILE(Num)		(server_CB.client_grp[(Num)]->state & FILESTATE)?1:0
#define SETFILE(Num, Flag)	(Flag)?(server_CB.client_grp[(Num)]->state |= FILESTATE):\

/* for client */
#define GETLOCK_C		(client_CB.state & LOCKSTATE)?1:0
#define SETLOCK_C(Flag)		(Flag)?(client_CB.state |= LOCKSTATE):(client_CB.state &= ~LOCKSTATE)
#define GETRECV_C		(client_CB.state & RECVSTATE)?1:0
#define SETRECV_C(Flag)		(Flag)?(client_CB.state |= RECVSTATE):(client_CB.state &= ~RECVSTATE)
#define GETRESEND_C		(client_CB.state & RESENDSTATE)?1:0
#define SETRESEND_C(Flag)	(Flag)?(client_CB.state |= RESENDSTATE):(client_CB.state &= ~RESENDSTATE)
#define GETREC_C		(client_CB.state & RECSTATE)?1:0
#define SETREC_C(Flag)		(Flag)?(client_CB.state |= RECSTATE):(client_CB.state &= ~RECSTATE)
#define GETFILE_C		(client_CB.state & FILESTATE)?1:0
#define SETFILE_C(Flag)		(Flag)?(client_CB.state |= FILESTATE):(client_CB.state &= ~FILESTATE)

#endif

typedef struct {
	CARD8	type;
	CARD8	length;
	CARD16	server_port;
	CARD32	server_ip;
	CARD8	server_ID[IDLENGTH];
} ServerAdv;

typedef struct {
	CARD8	type;
	CARD8	length;
	CARD8	client_ID[IDLENGTH];
} ClientAdv;

typedef struct {
	CARD8	type;
	CARD8	flag;
	CARD16	casting_port;
	CARD32	casting_ip;
	CARD8	fullscreen;
	CARD8	src_ID[IDLENGTH];
	rfbServerInitMsg serverInitMsg;
	rfbPixelFormat pixelFormat;
} CastAdv;

typedef struct {
	CARD8	type;
	CARD8	flag;
	CARD8	rectime;
	CARD8	fps;
	CARD8	geometry[IDLENGTH];
} RecAdv;

typedef struct {
	CARD8	type;
	CARD8	flag;
	size_t	fsize;
	CARD8	fname[STRLENGTH];
	CARD8	data[MAXBUF];
} FileAdv;

typedef struct {
	CARD8	type;
	CARD8	flag;
	CARD8	locktime;
	CARD8	pading;
} LockAdv;

typedef struct {
	CARD8 type;
	CARD8 flag;
} AllowAdv;

typedef struct {
	CARD8 type;
	CARD8 flag;
} ExistAdv;

typedef struct {
	CARD8 type;
	CARD8 flag;
} VncConnAdv;

struct server_cb {
	struct client_grp *client_grp[MAXCLIENT];	/* クライアント情報 */
	CARD32 advertise_ip;				/* サーバ起動通知アドレス */
	CARD16 advertise_port;				/* サーバ起動通知ポート */
	CARD32 cstdsp[MAXCLIENT];			/* 画面送信ディスクリプタ */
	CARD32 casting_ip[MAXCLIENT];			/* 画面送信アドレス */
	CARD16 casting_port;				/* 画面送信ポート */
	CARD8 server_ID[IDLENGTH];			/* サーバID */
	CARD16 server_port;				/* listenポート */
	CARD32 lsndsp;					/* listenディスクリプタ */
	CARD32 g_lsndsp;				/* listenディスクリプタ(gtk) */
	CARD8 user_num;					/* クライアント接続数 */
	//CARD32 testdsp;
	//CARD8 flag;
	CARD8 processingNum;
	CARD8 cast_src[MAXCLIENT];			/* 画面送信グループの送信元クライアント番号 */
	struct timeval basetime;			/* RTT計測の基準となる時間 */
	CARD8 DB_Host[16];
	CARD32 DB_Port;
	CARD8 DB_Name[16];
	CARD8 DB_Pass[16];
	CARD8 DB_Database[16];
};

struct client_grp {
	CARD8 client_ID[IDLENGTH];
	CARD32 client_ip;
	CARD16 client_port;
	CARD8 state;
	CARD32 vncdsp;
	CARD32 ctldsp;
	CARD32 g_vncdsp;
	CARD32 g_ctldsp;
	CARD8 cast_grp;
	CARD8 recv_grp;
	rfbServerInitMsg serverInitMsg;
	int draw_page;
	int draw_area;
	unsigned int r_time;
	gint calcrate_tag;
	gint resend_tag;
	int shm_id;
	FILE *fp;
};

struct client_cb {
	CARD8 client_ID[IDLENGTH];
	CARD8 server_ID[IDLENGTH];
	CARD32 server_ip;
	CARD16 server_port;
	CARD8 state;

	CARD32 advertise_ip;
	CARD16 advertise_port;
	CARD32 casting_ip;
	CARD16 casting_port;
	CARD32 mltdsp;
	CARD32 g_mltdsp;
	FILE *vncdsp;
	CARD32 ctldsp;
	CARD32 g_ctldsp;
	CARD32 cstdsp;
	CARD32 g_cstdsp;
	CARD32 connectstate;
	rfbServerInitMsg serverInitMsg;
	rfbPixelFormat serverFormat;
	CARD16 del_pk_num;				/* 画面送信で破棄されたパケット数 */
};

struct Draw_Info {
        int row;
        int column;
	char group_name[16];
        int client_num[TABGROUP_MAX];
};


/* multi.c */
int clientNum;
extern void AdvInit ();
extern int SendAdv ();
extern int ConnectAdv ();
extern void ConnectCTL (struct sockaddr_in, int, int);
extern void ConnectVNC (struct sockaddr_in, int, int);
int CreateMultiSockToSend (unsigned int ip, int port);
extern void SendCastMsg (char flag, int clientNum, char fullscreen);
extern void SendLockMsg (char flag, int clientNum);
extern void SendRecMsg (char flag, int clientNum, int rectime,int fps,char* geometry);
extern void SendAllowMsg (int clientNum, char *buf);
extern void CutVNC (int clientNum);
extern void SendVncMsg (int clientNum);
extern void CheckLockClient(void);
extern void sem_init (void);
extern void sem_lock (void);
extern void sem_unlock (void);
extern struct Shm_asym *shm_asym[MAXCLIENT];
extern void resendCallback (gpointer cnum);

#include <sys/shm.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sched.h>

/* sockets.c */
extern gint gdksock;
//extern int buffered;
static int buffered = 0;

/* vncviewer.c */
extern int vnc_main(int argc, char **argv);
struct server_cb server_CB;

/* multivnc_client.c */
extern int client_main(int argc, char **argv);
extern struct client_cb client_CB;
extern void StartVNCServer (void);
extern void CloseVNCServer (void);
int adjustColorBitShift(short server_bits, short client_bits);
extern int auto_flag;
extern int notice_flag;
//void start_record(void);
void start_record(int framerate, char *geometry, char *path);
void stop_record(void);
void changeTwoDigit(char *string, int num);

/* listen.c */
extern void doListen();

/* draw.c */
extern int clientNum_ex;

/* rfbproto.c */
#include <zlib.h>
#include <jpeglib.h>
int da_num;
#define CAST_BUF_SIZE 5000000
//#define CALC_SIZE CAST_BUF_SIZE
#define CALC_SIZE 30000
//#define CAST_BUF_SIZE SHMMAX
//#define CAST_BUF_SIZE 4194304
//#define CAST_BUF_SIZE 307200
//extern char castBuf[CAST_BUF_SIZE];
//extern int cblen;
extern z_stream zlibStream[MAXCLIENT][4];
extern Bool zlibStreamActive[MAXCLIENT][4];

struct Shm_asym {
  int sem_fg;
  int flag;
  int start;
  int end;
  int sendrate;
  char castBuf[CAST_BUF_SIZE];
  short rec_size[CALC_SIZE];
  short rec_s;
  short rec_e;
  int ave_delay;
};

extern void calcRateCallback (gpointer cnum);


/* init_client.c */
void DesktopInitForClient(void);
void CreateImageInfoForClient(void);
void CopyDataToScreenForClient(char *buf, int x, int y, int width, int height);
void window_copy_area_for_client(GdkWindow *window, GdkGC *gc, gint x, gint y,
				 GdkWindow *source_window, gint source_x, gint source_y,
				 gint width, gint height);
void draw_rectangle_for_client(GdkDrawable *drawable, GdkGC *gc, gint filled,
			       gint x, gint y, gint width, gint height, int color);

/* main.c(server) */
GtkWidget *drawingarea[TAB_MAX][ROW_MAX * COLUMN_MAX];
struct Draw_Info draw_info[TAB_MAX];
int tab_num, current_page;
int page;
Bool chStateDB(int clientNum, int flag);
void makeTable( int p, int x, int y );
void ChangeLabel(int p, int d, char *name);
extern int exDB_flag;
extern int Resend_flag;

/* callbacks.c(server) */
GdkPixmap *gdkpixmap[TAB_MAX][ROW_MAX * COLUMN_MAX];
GtkWidget *drawingarea_ex;
GdkPixmap *pixmap_ex;
GdkImage *smallimage_ex;
extern GtkWidget *window_ex;

/* main.c(client) */
extern GtkIMContext *im_context;

/* callbacks.c(client) */
void open_dialog_recvAdv(char *);
void GetMultiVNCServerMsg (void *);
void create_lock_window (void);
void start_lock(void);
void stop_lock(void);
GtkWidget *create_mini_window (void);
void draw_string_to_mini_window(char *string);

/* interface.c(client) */
extern GtkWidget* create_drawing_window (void);
extern GtkWidget* create_dialog_IDinput (void);
extern GtkWidget* create_dialog_wait (void);
extern GtkWidget* create_dialog_recvAdv (void);
extern GtkWidget* create_dialog_inputmiss (void);
extern GtkWidget* create_dialog_exit (void);

#endif

/*
 * Standard gettext macros.
 */
#ifdef ENABLE_NLS
#  include <libintl.h>
#  undef _
#  define _(String) dgettext (PACKAGE, String)
#  define Q_(String) g_strip_context ((String), gettext (String))
#  ifdef gettext_noop
#    define N_(String) gettext_noop (String)
#  else
#    define N_(String) (String)
#  endif
#else
#  define textdomain(String) (String)
#  define gettext(String) (String)
#  define dgettext(Domain,Message) (Message)
#  define dcgettext(Domain,Message,Type) (Message)
#  define bindtextdomain(Domain,Directory) (Domain)
#  define _(String) (String)
#  define Q_(String) g_strip_context ((String), (String))
#  define N_(String) (String)
#endif


