/* CSL - Common Sound Layer
 * Copyright (C) 2000-2001 Stefan Westerfeld and Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#include	"artsmcopmarshal.h"

#include	"cslutils.h"
#include	"artsbinbuffer.h"
#include	<string.h>


/* --- functions --- */
void
_arts_mcop_message_free (ArtsMcopMessage *msg)
{
  if (!msg)
    return;
  
  switch (msg->type)
    {
    case ARTS_MCOP_SERVER_HELLO:
      csl_free (msg->body.server_hello.mcop_version);
      csl_free (msg->body.server_hello.server_id);
      csl_strfreevn (msg->body.server_hello.n_auth_protocols,
		     msg->body.server_hello.auth_protocols);
      csl_free (msg->body.server_hello.auth_seed);
      break;
    case ARTS_MCOP_CLIENT_HELLO:
      csl_free (msg->body.client_hello.server_id);
      csl_free (msg->body.client_hello.auth_protocol);
      csl_free (msg->body.client_hello.auth_data);
      break;
    case ARTS_MCOP_AUTH_ACCEPT:
      csl_strfreevn (msg->body.auth_accept.n_hints, msg->body.auth_accept.hints);
      break;
    case ARTS_MCOP_INVOCATION:
    case ARTS_MCOP_ONEWAY_INVOCATION:
    case ARTS_MCOP_RETURN:
    default:
      break;
    }
  csl_free (msg);
}

ArtsMcopMessage*
_arts_mcop_message_demarshal (ArtsBinBuffer *buffer)
{
  ArtsMcopMessage *msg = csl_malloc (sizeof (*msg));
  
  msg->mcop_magic = _arts_bin_buffer_get_int (buffer);
  msg->message_length = _arts_bin_buffer_get_int (buffer);
  msg->type = _arts_bin_buffer_get_int (buffer);
  
  switch (msg->type)
    {
    case ARTS_MCOP_SERVER_HELLO:
      msg->body.server_hello.mcop_version = _arts_bin_buffer_get_string (buffer);
      msg->body.server_hello.server_id = _arts_bin_buffer_get_string (buffer);
      msg->body.server_hello.auth_protocols = _arts_bin_buffer_get_string_seq (buffer,
									     &msg->body.server_hello.n_auth_protocols);
      msg->body.server_hello.auth_seed = _arts_bin_buffer_get_string (buffer);
      break;
    case ARTS_MCOP_CLIENT_HELLO:
      msg->body.client_hello.server_id = _arts_bin_buffer_get_string (buffer);
      msg->body.client_hello.auth_protocol  = _arts_bin_buffer_get_string (buffer);
      msg->body.client_hello.auth_data  = _arts_bin_buffer_get_string (buffer);
      break;
    case ARTS_MCOP_AUTH_ACCEPT:
      msg->body.auth_accept.hints = _arts_bin_buffer_get_string_seq (buffer, &msg->body.auth_accept.n_hints);
      break;
    case ARTS_MCOP_INVOCATION:
      msg->body.invocation.object_id = _arts_bin_buffer_get_int (buffer);
      msg->body.invocation.method_id = _arts_bin_buffer_get_int (buffer);
      msg->body.invocation.request_id = _arts_bin_buffer_get_int (buffer);
      break;
    case ARTS_MCOP_ONEWAY_INVOCATION:
      msg->body.oneway_invocation.object_id = _arts_bin_buffer_get_int (buffer);
      msg->body.oneway_invocation.method_id = _arts_bin_buffer_get_int (buffer);
      break;
    case ARTS_MCOP_RETURN:
      msg->body.return_body.request_id = _arts_bin_buffer_get_int (buffer);
      break;
    default:
      msg->type = ARTS_MCOP_MESSAGE_INVALID;
      break;
    }
  if (buffer->error)
    {
      _arts_mcop_message_free (msg);
      return NULL;
    }
  return msg;
}

void
_arts_mcop_message_marshal (ArtsMcopMessage *msg,
			   ArtsBinBuffer   *buffer)
{
  _arts_bin_buffer_put_int (buffer, msg->mcop_magic);
  _arts_bin_buffer_put_int (buffer, msg->message_length);
  _arts_bin_buffer_put_int (buffer, msg->type);
  switch (msg->type)
    {
    case ARTS_MCOP_SERVER_HELLO:
      _arts_bin_buffer_put_string (buffer, msg->body.server_hello.mcop_version);
      _arts_bin_buffer_put_string (buffer, msg->body.server_hello.server_id);
      _arts_bin_buffer_put_string_seq (buffer,
				     msg->body.server_hello.n_auth_protocols,
				     msg->body.server_hello.auth_protocols);
      break;
    case ARTS_MCOP_CLIENT_HELLO:
      _arts_bin_buffer_put_string (buffer, msg->body.client_hello.server_id);
      _arts_bin_buffer_put_string (buffer, msg->body.client_hello.auth_protocol);
      _arts_bin_buffer_put_string (buffer, msg->body.client_hello.auth_data);
      break;
    case ARTS_MCOP_AUTH_ACCEPT:
      _arts_bin_buffer_put_string_seq (buffer, msg->body.auth_accept.n_hints, 
				     msg->body.auth_accept.hints);
      break;
    case ARTS_MCOP_INVOCATION:
      _arts_bin_buffer_put_int (buffer, msg->body.invocation.object_id);
      _arts_bin_buffer_put_int (buffer, msg->body.invocation.method_id);
      _arts_bin_buffer_put_int (buffer, msg->body.invocation.request_id);
      break;
    case ARTS_MCOP_ONEWAY_INVOCATION:
      _arts_bin_buffer_put_int (buffer, msg->body.oneway_invocation.object_id);
      _arts_bin_buffer_put_int (buffer, msg->body.oneway_invocation.method_id);
      break;
    case ARTS_MCOP_RETURN:
      _arts_bin_buffer_put_int (buffer, msg->body.return_body.request_id);
      break;
    default:
      msg->type = ARTS_MCOP_MESSAGE_INVALID;
      break;
    }
}

void
_arts_mcop_object_reference_free (ArtsMcopObjectReference *oref)
{
  csl_return_if_fail (oref != NULL);

  csl_free (oref->server_id);
  csl_strfreevn (oref->n_urls, oref->urls);
  csl_free (oref);
}

ArtsMcopObjectReference*
_arts_mcop_object_reference_demarshal (ArtsBinBuffer *buffer)
{
  ArtsMcopObjectReference *oref = csl_malloc (sizeof (ArtsMcopObjectReference));
  
  oref->server_id = _arts_bin_buffer_get_string (buffer);
  oref->object_id = _arts_bin_buffer_get_int (buffer);
  oref->urls = _arts_bin_buffer_get_string_seq (buffer, &oref->n_urls);
  
  if (buffer->error)
    {
      _arts_mcop_object_reference_free (oref);
      oref = NULL;
    }
  
  return oref;
}

void
_arts_mcop_object_reference_marshal (ArtsMcopObjectReference *oref,
				    ArtsBinBuffer           *buffer)
{
  _arts_bin_buffer_put_string (buffer, oref->server_id);
  _arts_bin_buffer_put_int (buffer, oref->object_id);
  _arts_bin_buffer_put_string_seq (buffer, oref->n_urls, oref->urls);
}

ArtsMcopObjectReference*
_arts_mcop_object_reference_from_hexurl (const char *hex_url)
{
  ArtsBinBuffer buffer;
  ArtsMcopObjectReference *oref;

  if (!hex_url || strncmp (hex_url, "MCOP-Object:", 12))
    return NULL;
  _arts_bin_buffer_setup_writable (&buffer, 0);
  _arts_bin_buffer_put_hex (&buffer, hex_url + 12);
  _arts_bin_buffer_rewind (&buffer);
  oref = _arts_mcop_object_reference_demarshal (&buffer);
  _arts_bin_buffer_free_writable (&buffer);
  
  return oref;
}
