/*
 * Copyright (c) 2001-2003 Shiman Associates Inc. All Rights Reserved.
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#include <stdio.h>
#include <string.h>
#include "mas_internal.h"
#include "mas/mas_dpi.h"

/*
  Use these interfaces.  You'll regret it if you don't.  They go
  beyond convience.  I'm talking life-saving stuff here.
  
  There's nothing special, actually.  You can do all this on your
  own.  It's just that there's a few gotchas with memory management
  and handling of missing package members that these routines do
  easily. 
*/

int32
masd_get_pre( void* predicate, int32* retport_r, char** key_r, struct mas_package* arg_r )
{
    struct mas_package predpack;

    /* must have memory allocated for arg_r */
    if ( arg_r == NULL )
        return mas_error(MERR_NULLPTR);
    
    /* 1. Pull the key out of the predicate package.  DO NOT copy the
          string - keep it in the predicate. */
    masc_setup_package( &predpack, predicate, 0, MASC_PACKAGE_STATIC|MASC_PACKAGE_EXTRACT );
    masc_pullk_string( &predpack, "key", key_r, FALSE );

    /* 2. Test to see if there's an arg.  if there isn't, we've gotta
          correctly handle that.  Do not copy the package contents -
          keep them in the predicate. */
    arg_r->contents = 0;
    if ( masc_test_key( &predpack, "arg" ) == 0 )
        masc_pullk_package( &predpack, "arg", arg_r, FALSE );

    /* see where the response will go - THIS IS LIKELY TO CHANGE */
    *retport_r = 0;
    if ( masc_test_key( &predpack, "retport" ) > 0 )
        masc_pullk_int32( &predpack, "retport", retport_r );

    return 0;
}

int32
masd_get_post( int32 reaction, int32 retport, char* key, struct mas_package* arg, struct mas_package* r_package )
{
    struct mas_data* data;

    mas_assert( r_package != 0, "can't use null package" );

    /* Gotta use dynamically allocated memory.  Sorry! */
    if ( r_package->flags & MASC_PACKAGE_STATIC )
        return mas_error(MERR_INVALID);
    
    /* post the reply depending on the value of retport */
    if ( retport == 0 )
    {
        masd_reaction_queue_response( reaction, r_package->contents, r_package->size );
    }
    else /* its not just a response */
    {
        data = MAS_NEW( data );
        r_package->flags |= MASC_PACKAGE_NOFREE; /* just to make sure */
        data->segment = r_package->contents;
        data->length = r_package->size;
        data->allocated_length = r_package->allocated_size;
        masd_post_data( retport, data );
    }

    masc_strike_package( r_package );
    if ( arg->contents != NULL ) masc_strike_package( arg );

    return 0;    
}

int32
masd_set_pre( void* predicate, char** key_r, struct mas_package* arg_r )
{
    struct mas_package predpack;
    
    /* must have memory allocated for arg_r */
    if ( arg_r == NULL )
        return mas_error(MERR_NULLPTR);
    
    /* 1. Pull the key out of the predicate package.  DO NOT copy the
          string - keep it in the predicate. */
    masc_setup_package( &predpack, predicate, 0, MASC_PACKAGE_STATIC|MASC_PACKAGE_EXTRACT );
    masc_pullk_string( &predpack, "key", key_r, FALSE );

    /* 2. Test to see if there's an arg.  if there isn't, we've gotta
          correctly handle that.  Do not copy the package contents -
          keep them in the predicate. */
    arg_r->contents = 0;
    if ( masc_test_key( &predpack, "arg" ) == 0 )
        masc_pullk_package( &predpack, "arg", arg_r, FALSE );

    return 0;
}

int32
masd_set_post( char* key, struct mas_package* arg )
{
    int32 err = 0;

    if ( arg != NULL && arg->contents != NULL )
        err = masc_strike_package( arg );
    return err;
}

#if 0 /* not working */
int32
masd_subscribe_get_nugget_pre( void* predicate, char** key_r, struct mas_package** arg_r, uint32* period_us_r )
{
    struct mas_package* package;
    char* key;
    void* payload;
    uint32 payload_len;
    int got_arg = FALSE;
    
    /* pull the key out of the predicate package */
    masc_make_package_from_payload( &package, predicate );
    masc_pullk_string( package, "key", &key );

    /* test to see if there's an arg.  if there isn't, we've gotta
       correctly handle that */
    if ( masc_test_key( package, "arg" ) == 0 )
    {
        got_arg = TRUE;
        masc_pullk_payload( package, "arg", &payload, &payload_len  );
    }

    /* get the updating period */
    masc_pullk_int32( package, "period", period_us_r );

    /* create the arg package - reuse package */
    package->contents = 0;
    if ( got_arg )
    {
        /* form argument package */
        masc_reset_package( package );
        masc_alloc_package_from_payload( package, payload );
    }
    else
    {
        /* package is null */
        masc_destroy_package( package );
        package = 0;
    }

    *key_r = key;
    *arg_r = package;

    package->contents = 0;
    masc_destroy_package( package );
    
    return 0;
}

int32
masd_subscribe_get_nugget_post( int32 reaction, int32 portnum, char* key, struct mas_package* arg )
{
    struct mas_package* r_package;

    masc_make_package( &r_package, 0 );
    masc_pushk_int32( r_package, "portnum", portnum );
    masc_finalize_package( r_package );

    /* post the reply depending on the value of retport */
    masd_reaction_queue_response( reaction, r_package->contents, r_package->size );

    /* free up the key string */
    if (key != 0) masc_rtfree( key );
    
    /* don't free the contents of the return package - recipient does
     * that. */
    if ( r_package != 0 )
    {
        r_package->contents = 0;
        masc_destroy_package( r_package );
    }

    /* don't free the contents of the argument package - scheduler
     * does that. */
    if ( arg != 0 )
    {
        arg->contents = 0;
        masc_destroy_package( arg );
    }

    return 0;    
}

#endif
