
#ifndef __VNCSERV_H__
#define __VNCSERV_H__

#include "areas.h"
#include "config.h"
#include "vncproto.h"
#include "proto2.h"
#include "task.h"

#define RAW_ENCODING                    0
#define COPY_ENCODING                   1
#define HEXTILE_ENCODING                5
#define ZLIB_ENCODING                   6
#define ZRLE_ENCODING                   16
#define HEXTILEDITHER8_ENCODING         0x00221000
#define DESKTOPSIZE_ENCODING            -223
#define CURSOR_ENCODING                 -239
#define XCURSOR_ENCODING                -240

typedef unsigned char  CARD8;
typedef unsigned short CARD16;
typedef unsigned int   CARD32;

typedef struct vncserv_s vncserv;


// status codes to be returned by io functions
#define VNCSERV_OK                      0
#define VNCSERV_CLIENT_HAS_GONE         -1
#define VNCSERV_FAILED_TO_READ          -2
#define VNCSERV_FAILED_TO_WRITE         -3
#define VNCSERV_FATAL_ERROR             -4

typedef struct vncservio_t {
  // read() should return no. of bytes read or VNCSERV_???
  int (* read      )(const vncserv *serv, void *buffer, int bytes, void *meta);
  int (* write     )(const vncserv *serv, const void *buffer, int bytes, void *meta);
  int (* keypress  )(const vncserv *serv, int key, int down, void *meta);
  int (* pointer   )(const vncserv *serv, int x, int y, int buttons, void *meta);
  int (* cuttext   )(const vncserv *serv, const char *text, int len, int remain, void *meta);
  // error() may be called with serv=NULL during vncserver_create()
  int (* error     )(const vncserv *serv, const char *msg, void *meta);
  int (* get_tx_space)(const vncserv *serv, void *meta);
  void (* exclusive )(const vncserv *serv, void *meta);
} vncservio;

/* Struct used to track the state of a standard framebuffer update rectangle */
typedef struct {
  area rect; /* Original rectangle */
  int x; /* Current encoder x, y position. Initialised to -1, -1, on first call. Once this reaches the end of the rectangle the job is complete */
  int y;
} send_rect_state;

// create a new server
vncserv *vncserver_create(const server_config_t *config, vncservio *io, void *meta);

// set buffer size - should be set to a little bit larger than the
// largest amount of text the client will ever pass in a 'cut text' message
int vncserver_set_buffer_size(vncserv *serv, int size);

// inform the server that the connection to the client is open
void vncserv_started(vncserv *serv);

// set 8bpp palette (if not RGB332)
void vncserv_set_8bpp_palette(vncserv *cl, const unsigned int *palette);

// poll the server, should be called as often as possible
// returns VNCSERV_OK or VNCSERV_FATAL_ERROR
int vncserv_poll(vncserv *serv, int timeout_in_centiseconds);

// inform the server that part of the framebuffer has changed
// coords are in pixels, with 0,0 being the top left corner
void vncserv_framebuffer_changed(vncserv *serv, area *ar);
void vncserv_framebuffer_area_moved(vncserv *serv, area *from, area *to);

// shutdown the server
void vncserv_closedown(vncserv *serv);

// paste text to the client
int vncserv_cut_text(vncserv *serv, clipboard_text *text);

// ring the bell on the client
void vncserv_bell(vncserv *serv);

// Returns true if it's safe to call vncserv_desktopsize
bool vncserv_can_desktopsize(vncserv *serv);

// Call to update desktop parameters
int vncserv_desktopsize(vncserv *serv, servscreen *servscreen);

void vncserv_update_cursor(vncserv *serv, const pointer_shape *cursor);

void vncserv_async_send_poll(vncserv *serv);

#define Swap16IfLE(s)  ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
#define Swap32IfLE(l)  ((((l) & 0xff000000) >> 24) |         \
		        (((l) & 0x00ff0000) >> 8)  |         \
		        (((l) & 0x0000ff00) << 8)  |         \
		        (((l) & 0x000000ff) << 24))


static inline bool send_rect_is_complete(const send_rect_state *state)
{
  return (state->x == state->rect.x + state->rect.w) && (state->y == state->rect.y + state->rect.h);
}

#endif
