/*
 * 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 <stdlib.h>
#include <stdarg.h>
#include "mas/mas_common.h"

/***************************************************************************
 * masc_print_dc
 *
 *  Debug function.  Prints all key, value pairs for the specified dc.
 *  
 * returns: 0
 *
 ***************************************************************************/
int32
masc_print_dc( struct mas_data_characteristic* dc )
{
    int i;
#define TSTR_LEN 1024
    char as[TSTR_LEN]; /* temporary string */
    char bs[TSTR_LEN]; /* temporary string */
    int  remain = TSTR_LEN - 1;

    strcpy( as, "dc: [");

    for (i=0; i<dc->numkeys; i++)
    {
        if ( (i > 0) && (remain > 1) )
            strcat( as, ", " );
        
        remain = TSTR_LEN - strlen( as ) - 1;
        snprintf( bs, TSTR_LEN - 1, "(%s:%s)", dc->keys[i], dc->values[i]);
        strncat( as, bs, min( remain, strlen( bs ) ) );
        remain = TSTR_LEN - strlen( as ) - 1;
    }

    if ( remain > 1 )
        strcat( as, "]" );

    masc_log_message( 0, as );

    return 0;
}

/***************************************************************************
 * masc_get_index_of_key
 *
 *  Scans dc key strings for the specified key string.  If found,
 *  returns the index.
 *  
 * returns: int32 index of matching key in dc
 *          MERR_NOTDEF
 *          
 ***************************************************************************/
int32
masc_get_index_of_key( struct mas_data_characteristic* dc, char* key )
{
    int32 i;

    for (i=0; i<dc->numkeys; i++)
    {
	if ( strcmp( dc->keys[i], key ) == 0 ) return i;
    }

    return mas_error(MERR_NOTDEF);

}

/***************************************************************************
 * masc_setup_dc
 *
 *  Allocates memory for the internals of a data characteristic
 *  structure with "size" number of keys and values.  Zeroes out the
 *  allocated keys and values.
 * 
 * returns: error
 *
 ***************************************************************************/
int32
masc_setup_dc( struct mas_data_characteristic* dc, int16 size )
{
    /* do a quick bounds check */
    if ( ( size < 1 ) || ( size > 255 ) )
	return mas_error(MERR_INVALID);

    if ( dc == NULL )
        return mas_error(MERR_NULLPTR);
    
    memset( dc, 0, sizeof *dc );

    dc->keys = masc_rtalloc( size * sizeof (char*) );
    dc->values = masc_rtalloc( size * sizeof (char*) );

    memset( dc->keys, 0, size * sizeof (char*) );
    memset( dc->values, 0, size * sizeof (char*) );

    dc->allocated_keys = size;

    return 0;
}

/***************************************************************************
 * masc_copy_dc
 *
 *  Copy a data characteristic from dc_src to dc_dest.  This allocates
 *  memory for the destination key and value strings.  
 * 
 * returns: error
 *
 ***************************************************************************/
int32
masc_copy_dc( struct mas_data_characteristic* dc_dest, struct mas_data_characteristic* dc_src)
{
    int32 i;

    /* do a quick nullptr check */ 
    if ( dc_dest == 0 ) return mas_error( MERR_NULLPTR );
    if ( dc_src == 0 ) return mas_error( MERR_NULLPTR );
    
    if ( dc_src->numkeys > dc_dest->allocated_keys )
	return mas_error(MERR_INVALID);

    dc_dest->numkeys = dc_src->numkeys;
    
    for ( i=0; i<dc_dest->numkeys; i++)
    {
	dc_dest->keys[i] = masc_rtalloc( strlen(dc_src->keys[i]) + 1 );
        if ( dc_dest->keys[i] == 0 ) return mas_error(MERR_MEMORY);
        dc_dest->values[i] = masc_rtalloc( strlen(dc_src->values[i]) + 1 );
        if ( dc_dest->values[i] == 0 ) return mas_error(MERR_MEMORY);
	strcpy(dc_dest->keys[i], dc_src->keys[i]);
	strcpy(dc_dest->values[i], dc_src->values[i]);
    }

    return 0;
}

/***************************************************************************
 * masc_strike_dc
 *
 *  Free memory used by a data characteristic.
 *
 * returns: error
 *
 ***************************************************************************/
int32
masc_strike_dc( struct mas_data_characteristic* dc )
{
    int32 i;

    if ( dc == NULL )
        return mas_error(MERR_NULLPTR);
    
    /* free the strings!  free the strings! */
    for (i=0; i<dc->numkeys; i++)
    {
	if ( dc->keys[i] )
            masc_rtfree( dc->keys[i] );
        if ( dc->values[i] )
            masc_rtfree( dc->values[i] );
    }

    masc_rtfree( dc->keys ); 
    masc_rtfree( dc->values );

    memset( dc, 0, sizeof *dc );
    
    return 0;
}

/* this copies the strings */
int32
masc_append_dc_key_value( struct mas_data_characteristic* dc, const char* key, const char* value )
{
    int32 i;

    if ( dc->numkeys >= dc->allocated_keys )
	return mas_error(MERR_MEMORY);

    i = dc->numkeys;
    dc->numkeys++;
    
    dc->keys[i] = masc_rtalloc( strlen(key) + 1 );
    dc->values[i] = masc_rtalloc( strlen(value) + 1 );

    strcpy(dc->keys[i], key);
    strcpy(dc->values[i], value);

    return 0;
}

int32
masc_change_dc_value( struct mas_data_characteristic* dc, char* key, char* value )
{
    int i;
    int32 err;

    i = masc_get_index_of_key( dc, key );
    if ( i < 0 )
    {
        err = i;
        return err;
    }

    masc_rtfree( dc->values[i] );
    dc->values[i] = strdup( value );

    return 0;
}

int32
masc_pack_dc( struct mas_package* package, struct mas_data_characteristic* dc  )
{
    int  i;

    for (i=0; i<dc->numkeys; i++)
    {
	masc_pushk_string( package, dc->keys[i], dc->values[i] );
    }

    masc_finalize_package( package );
    
    return package->error;
}

int32
masc_unpack_dc( struct mas_package *package, struct mas_data_characteristic* dc )
{
    char *key;
    int i;

    dc->numkeys = package->members;
    dc->keys = masc_rtcalloc( dc->numkeys, sizeof (char *));
    dc->values = masc_rtcalloc( dc->numkeys, sizeof (char *));
    
    for (i = 0; i < dc->numkeys; i++)
    {
        masc_peek_key( package, &key );
        if ( key == NULL )
            continue;
        dc->keys[i] = masc_rtalloc( strlen( key ) + 1 );
        if ( dc->keys[i] == NULL )
            return mas_error(MERR_MEMORY);
        
        strcpy( dc->keys[i], key );
        
	masc_pull_string( package, &(dc->values[i]), TRUE );
    }

    dc->allocated_keys = dc->numkeys;

    return 0;
}

int32
masc_compare_dc( struct mas_data_characteristic* dc1, struct mas_data_characteristic* dc2 )
{
    int i, j;

    if ( dc1 == NULL || dc2 == NULL )
        return FALSE;
    
    for (i=0; i<dc1->numkeys; i++)
    {
        j = masc_get_index_of_key( dc2, dc1->keys[i] );
        if ( j < 0 )
            return FALSE;

        if ( strcmp( dc1->values[i], dc2->values[j] ) != 0 )
            return FALSE;
    }
    
    return TRUE;
}
