#include "opensync.h"
#include "opensync_internals.h"

int osync_marshal_get_size_changetype( OSyncChangeType changetype )
{
  return sizeof( int );
}

void osync_marshal_changetype( OSyncMessage *message, OSyncChangeType changetype )
{
  osync_message_write_int( message, (int)changetype );
}

void osync_demarshal_changetype( OSyncMessage *message, OSyncChangeType *changetype )
{
  int change_type = 0;

  osync_message_read_int( message, &change_type );
  *changetype =(OSyncChangeType)change_type;
}

int osync_marshal_get_size_change( OSyncChange *change )
{
  int size = 0;

  if ( !change )
    return size;

  size += strlen( change->uid );
  size += strlen( change->hash );
  size += sizeof( int ); // change->size
  size += change->size;  // change->data
  size += sizeof( int ); // change->has_data
  size += strlen( change->objtype_name );
  size += strlen( change->format_name );
  size += strlen( change->initial_format_name );
  size += osync_marshal_get_size_changetype( change->changetype );
  size += sizeof( long long int ); // change->id
  size += strlen( change->destobjtype );
  size += strlen( change->sourceobjtype );
  size += osync_marshal_get_size_member( change->sourcemember );

  return size;
}

void osync_marshal_changedata(OSyncMessage *message, OSyncChange *change)
{
	OSyncObjFormat *format = osync_change_get_objformat(change);
	char *data;
	int datasize;
	int free_data = 0;

	osync_message_write_int( message, change->has_data );

	if (change->data && format && format->marshall_func) {
		format->marshall_func(change->data, change->size, &data, &datasize, NULL);
		/*FIXME: Handle errors on marshall_func */
		free_data = 1;
	} else {
		/* If the format is a plain format, then we have to add
		 * one byte for \0 to the datasize. This extra byte will
		 * be removed by the osync_demarshal_changedata funciton.
		 */
		data = change->data;
		datasize = change->size;
		datasize++;
	}

	if (!data)
		datasize = 0;

	osync_message_write_int(message, datasize);
	if (datasize > 0)
		osync_message_write_data(message, data, datasize);

	if (free_data)
		g_free(data);
}

void osync_marshal_change( OSyncMessage *message, OSyncChange *change )
{
  osync_message_write_string( message, change->uid );
  osync_message_write_string( message, change->hash );

  char *format_name = change->format ? change->format->name : change->format_name;
  char *objtype_name = change->objtype ? change->objtype->name : change->objtype_name;
  char *initial_format_name = change->initial_format ? change->initial_format->name : change->initial_format_name;
  osync_message_write_string( message, objtype_name );
  osync_message_write_string( message, format_name );
  osync_message_write_string( message, initial_format_name );

  osync_marshal_changedata(message, change);

  osync_marshal_changetype( message, change->changetype );
  osync_message_write_long_long_int( message, change->id );
  osync_message_write_string( message, change->destobjtype );
  osync_message_write_string( message, change->sourceobjtype );
  osync_marshal_member( message, change->sourcemember );
}

void osync_demarshal_changedata(OSyncMessage *message, OSyncChange *change)
{
	OSyncObjFormat *format = osync_change_get_objformat(change);
	char *data;
	int datasize;

	osync_message_read_int( message, &( change->has_data ) );

	osync_message_read_int(message, &datasize);
	if (datasize > 0) {
		data = malloc(datasize);
		osync_message_read_data( message, data, datasize );

		if (format && format->demarshall_func) {
			char *newdata;
			int newsize;
			format->demarshall_func(data, datasize, &newdata, &newsize, NULL);
			/*FIXME: Handle errors on demarshall_func */
			free(data);
			data = newdata;
			datasize = newsize;
		} else {
			/* If the format is a plain, then we have to remove
			 * one from the datasize, since once one was added by 
		       	 * osync_marshall_changedata() for trailing newline.
			 */
			datasize--;
		}
	} else {
		data = NULL;
	}

	change->data = data;
	change->size = datasize;
}

void osync_demarshal_change( OSyncMessage *message, OSyncFormatEnv *conv_env, OSyncChange **change )
{
  OSyncChange *new_change = osync_change_new();

  osync_change_set_conv_env(new_change, conv_env);

  osync_message_read_string( message, &( new_change->uid ) );
  osync_message_read_string( message, &( new_change->hash ) );

  osync_message_read_string( message, &( new_change->objtype_name ) );
  osync_message_read_string( message, &( new_change->format_name ) );
  osync_message_read_string( message, &( new_change->initial_format_name ) );

  osync_demarshal_changedata(message, new_change);

  osync_demarshal_changetype( message, &( new_change->changetype ) );
  osync_message_read_long_long_int( message, &( new_change->id ) );
  osync_message_read_string( message, &( new_change->destobjtype ) );
  osync_message_read_string( message, &( new_change->sourceobjtype ) );
  osync_demarshal_member( message, &( new_change->sourcemember ) );

  new_change->member = 0;
  new_change->engine_data = 0;
  new_change->mappingid = 0;
  new_change->changes_db = 0;

  *change = new_change;
}

int osync_marshal_get_size_member( OSyncMember *member )
{
  return sizeof( int );
}

void osync_marshal_member( OSyncMessage *message, OSyncMember *member )
{
  if ( member ) {
    osync_message_write_int( message, member->id );
  } else {
    osync_message_write_int( message, -1 );
  }
}

void osync_demarshal_member( OSyncMessage *message, OSyncMember **member )
{
  int id;

  osync_message_read_int( message, &id );

  if ( id == -1 )
    *member = 0;
  else {
    //TODO: search in pool
  }
}

int osync_marshal_get_size_error( OSyncError **error )
{
  int size = 0;

  if ( !osync_error_is_set(error) )
    return size;

  size += sizeof( int );
  size += strlen( (*error)->message );

  return size;
}

void osync_marshal_error( OSyncMessage *message, OSyncError *error )
{
	if (error) {
		osync_message_write_int( message, 1 );
		osync_message_write_int( message, (int)error->type );
		osync_message_write_string( message, error->message );
	} else {
		osync_message_write_int( message, 0 );
	}
}

void osync_demarshal_error( OSyncMessage *message, OSyncError **error )
{
	int hasError = 0;

	osync_message_read_int( message, &hasError );
	
	if (hasError) {
		char *msg;
		int error_type;
		
		osync_message_read_int( message, &error_type );
		osync_message_read_string( message, &msg );
		
		osync_error_set( error, (OSyncErrorType)error_type, msg );
	} else
		osync_error_free(error);
}

/*FIXME: review these get_size_*() functions
 *
 * - check if the data is being marhsalled as specified in the functions
 * - check (proabably invalid) usage of strlen() without considering the
 *   string length bytes and the nul terminator
 */
int osync_marshal_get_size_message( OSyncMessage *message )
{
  int size = 0;

  if ( !message )
    return size;

  size += sizeof( int ); // message->cmd
  size += sizeof( long long int ); // message->id
  size += sizeof( int ); // has error

  return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1