
/*******************************************************************************/
/* Copyright (C) 2008 Jonathan Moore Liles                                     */
/*                                                                             */
/* This program is free software; you can redistribute it and/or modify it     */
/* under the terms of the GNU General Public License as published by the       */
/* Free Software Foundation; either version 2 of the License, or (at your      */
/* option) any later version.                                                  */
/*                                                                             */
/* This program 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 General Public License for   */
/* more details.                                                               */
/*                                                                             */
/* You should have received a copy of the GNU General Public License along     */
/* with This program; see the file COPYING.  If not,write to the Free Software */
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
/*******************************************************************************/

#include "Log_Entry.H"

// #include "const.h"
#include "debug.h"

Log_Entry::Log_Entry ( )
{
    _sa = (char**)malloc( sizeof( char * ) );
    *_sa = NULL;
    _i = 0;
}

Log_Entry::Log_Entry ( char **sa )
{
    _sa = sa;
    _i = 0;

    if ( _sa )
        while ( _sa[ _i ] ) ++_i;

}

Log_Entry::Log_Entry ( const char *s )
{
    _i = 0;
    _sa = s ? parse_alist( s ) : NULL;

    if ( _sa )
        while ( _sa[ _i ] ) ++_i;
}

Log_Entry::~Log_Entry ( )
{
    if ( ! _sa )
        return;

    for ( _i = 0; _sa[ _i ]; ++_i )
    {
        free( _sa[ _i ] );
    }

    free( _sa );
}


/** remove escapes from string /s/ in-place */
static void
unescape ( char *s )
{
    char *r = s;
    for ( ; *s; s++, r++ )
    {
        if ( '\\' == *s )
        {
            switch ( *(++s) )
            {
                case 'n':
                    *r = '\n';
                    break;
                case '"':
                    *r = '"';
                    break;
                default:
                    break;
            }
        }
        else
            *r = *s;
    }

    *r = '\0';
}

/** return a dynamically allocated string representing this log entry */
char *
Log_Entry::print ( void ) const
{
    /* FIXME: gross over-allocation */
    char *r = (char*)malloc( 1024 );

    r[0] = 0;

    for ( int i = 0; i < size(); ++i )
    {
        const char *s, *v;

        get( i, &s, &v );

        /* FIXME: arbitrary limit */
        char t[1024];
        snprintf( t, sizeof( t ), "%s %s%s", s, v, size() == i + 1 ? "" : " " );

        strcat( r, t );
    }

    char *r2 = (char*)malloc( strlen( r ) + 1 );

    strcpy( r2, r );

    free( r );

    return r2;
}

/** sigh. parse a string of ":name value :name value" pairs into an
 * array of strings, one per pair */
// FIXME: doesn't handle the case of :name ":foo bar", nested quotes
// or other things it should.
char **
Log_Entry::parse_alist( const char *s )
{

// FIXME: bogus over allocation...

    int tl = strlen( s );
    char **r = (char**)malloc( sizeof( char* ) * tl );

    bool quote = false;
    bool value = false;
    const char *c = NULL;
    int i = 0;
    for ( ; ; s++ )
    {
        switch ( *s )
        {
            case '\0':
            case ' ':
                if ( ! quote && c )
                {
                    if ( ! value )
                    {
                        value = true;
                        break;
                    }

                    int l = s - c;

                    char *pair = (char*)malloc( l + 1 );

                    /* remove trailing space */
                    if ( c[ l  - 1 ] == ' ' )
                        --l;

                    strncpy( pair, c, l );

                    pair[ l ] = '\0';

                    r[ i++ ] = pair;

                    /* split */

                    strtok( pair, " " );

                    /* remove quotes */
                    char *v = pair + strlen( pair ) + 1;

                    unescape( v );

                    if  ( *v == '"' )
                    {
//                    v++;
                        if ( v[ strlen( v ) - 1 ] != '"' )
                            WARNING( "invalid quoting in log entry!" );
                        else
                        {
                            v[ strlen( v ) - 1 ] = '\0';
                            memmove( v, v + 1, strlen( v ) + 1 );
                        }
                    }

                    c = NULL;
                }
                break;
            case ':':                                           /* this is a key */
                if ( ! quote && ! c )
                {
                    c = s;
                    value = false;
                }
                break;
            case '"':
                quote = !quote;
                break;
            case '\\':
                s++;
                break;
        }

        if ( *s == '\0' )
            break;

    }

    r[ i ] = NULL;

    return r;
}

/** compare elements of dumps s1 and s2, removing those elements
    of dst which are not changed from src */
bool
Log_Entry::diff ( Log_Entry *e1, Log_Entry *e2 )
{

    if ( ! e1 )
        return true;

    char **sa1 = e1->_sa;
    char **sa2 = e2->_sa;

    if ( ! sa1 )
        return true;

    int w = 0;
    for ( int i = 0; sa1[ i ]; ++i )
    {
        const char *v1 = sa1[ i ] + strlen( sa1[ i ] ) + 1;
        const char *v2 = sa2[ i ] + strlen( sa2[ i ] ) + 1;

        if ( ! strcmp( sa1[ i ], sa2[ i ] ) && ! strcmp( v1, v2 ) )
        {
            free( sa2[ i ] );
            free( sa1[ i ] );
        }
        else
        {
            sa2[ w ] = sa2[ i ];
            sa1[ w ] = sa1[ i ];

            w++;
        }
    }

    sa1[ w ] = NULL;
    sa2[ w ] = NULL;

    e1->_i = w;
    e2->_i = w;

    return w == 0 ? false : true;
}

void
Log_Entry::grow (  )
{
    _sa = (char**)realloc( _sa, sizeof( char * ) * (_i + 2) );
    _sa[ _i + 1 ] = NULL;
}

int
Log_Entry::size ( void ) const
{
    return _i;
}

void
Log_Entry::get ( int n, const char **name, const char **value ) const
{
    *name = _sa[ n ];
    *value = *name + strlen( *name ) + 1;
}


void
Log_Entry::remove ( const char *name )
{
    for ( int i = 0; i < _i; i++ )
    {
        if ( !strcmp( _sa[ i ], name ) )
        {
            free( _sa[i] );
            _sa[i] = NULL;
        }
    }
}

char **
Log_Entry::sa ( void )
{
    return _sa;

/*   char **sa = _sa; */

/* //    _sa = NULL; */

/*     return sa; */
/* } */

}
