#ifndef EVOLUTION_SYNC_H
#define EVOLUTION_SYNC_H

#include <bonobo/bonobo-main.h>
#include <cal-client/cal-client.h>
#include <cal-client/cal-client-types.h>
#include <cal-util/cal-component.h>
#include <ebook/e-book.h>
#include <ebook/e-card-simple.h>

#include <multisync.h>

typedef enum {
  EVO_ADDR_MODE_WAITING = 0,
  EVO_ADDR_MODE_GETVIEW = 1,
  EVO_ADDR_MODE_GETCHANGES = 2,
  EVO_ADDR_MODE_MODIFIED = 3,
  EVO_ADDR_MODE_REMOVINGCHANGE = 4,
  EVO_ADDR_MODE_GOT_CHANGE = 5,
  EVO_ADDR_MODE_GETALL = 6,
  EVO_ADDR_MODE_REMOVECHANGES = 7
} evo_addr_mode;


struct _evolution_connection;
typedef void (*evo_sync_cb) (gpointer data, struct _evolution_connection *conn);

struct _evolution_connection {
  client_connection commondata;
  sync_pair *sync_pair;
  CalClient *cal_client;
  CalClient *todo_client;
  gboolean cal_opened;
  gboolean todo_opened;
  char *changedbname;
  connection_type conntype;
  GList *internal_changes;
  char *calendarpath;
  char *todopath;
  char *addressbookpath;
  EBook *ebook;
  EBookView *ebookview;
  evo_sync_cb callback;
  int nodbs, nodbsloaded;
  sync_object_type newdbs;

  // For modifications
  evo_addr_mode addr_mode;
  GList *addr_changes;
  GList *modify_results;
  GList *modify_objects;
  int modify_no; // Which entry in the modify list we are at
  gboolean modifying; // TRUE when in modify mode

};

typedef struct _evolution_connection evolution_connection;

typedef struct {
  evolution_connection *conn;
  char *comp;
  char *uid;
  char *uidret;
  int *uidretlen;
  sync_object_type objtype;
} obj_modify_args;

typedef struct {
  changed_object obj;
  gboolean reported; // TRUE if this change has been reported to sync engine
} internal_changed_object;


#define INTERNAL_CHANGE_FILE "evolutionchanges"
#define EVOLUTIONFILE "evolution"

GModule* load_evolution_lib(char* startdir, char *lib, int depth);
int load_evolution_libs(void);
void evo_load_state(evolution_connection *conn);
void evo_save_state(evolution_connection *conn);
CalClient* create_client (evolution_connection *conn, const char *uri, 
			  gboolean only_if_exists);
evolution_connection* sync_connect(sync_pair* handle, connection_type type,
				   sync_object_type object_types);
gboolean evo_do_disconnect(gpointer data);
void sync_disconnect(evolution_connection *conn);
void get_changes(evolution_connection* conn, sync_object_type newdbs);
gboolean evo_get_changes(gpointer data);
GList *evo_cal_get_all (GList *changes, evolution_connection *conn);
GList *evo_todo_get_all (GList *changes, evolution_connection *conn);
GList *evo_cal_get_changes(GList *changes, evolution_connection *conn);
GList *evo_todo_get_changes(GList *changes, evolution_connection *conn);
char *evo_replace(char *str, char *from, char* to);

void evo_get_changes_done(gpointer data, evolution_connection *conn);
gboolean cal_connect(gpointer data);
void evo_sync_loaddbs_cb(gpointer data, evolution_connection *conn);
gboolean do_cal_modify(gpointer data);
void syncobj_modify(evolution_connection *conn, 
		    char *comp, 
		    char *uid, sync_object_type objtype, 
		    char *uidret, int *uidretlen);
void syncobj_delete(evolution_connection *conn, char *uid, 
		    sync_object_type objtype, int softdelete);
gboolean cal_recur_instance (CalComponent *comp, time_t instance_start,
			     time_t instance_end, gpointer data);
gboolean do_cal_get_recurring(gpointer data);
void syncobj_get_recurring(evolution_connection *conn, 
			   changed_object *obj);
void sync_done(evolution_connection *conn, gboolean success);

sync_object_type object_type_from_component(CalComponent *comp);
void add_internal_changes(GList *changes, evolution_connection *conn);
GList *get_internal_changes(evolution_connection *conn);
void remove_internal_changes(evolution_connection *conn);
void load_internal_changes(evolution_connection *conn);
void save_internal_changes(evolution_connection *conn);
char *evo_encode_string_to_line(char* instr);
char* evo_decode_line_to_string(char *line);
GList *evo_append_change(GList *changelist, changed_object *change);
gboolean evo_check_change(evolution_connection *conn, char *id,
			  int change_type);


// Synchronous methods
gboolean always_connected(void);
char* short_name(void);
char* long_name(void);
sync_object_type object_types(void);
void plugin_init(void);
char* plugin_info(void);

#endif
