/********************************************************************\
 * dialog-sxsincelast.c - "since last run" dialog.                  *
 * Copyright (c) 2001 Joshua Sled <jsled@asynchronous.org>          *
 *                                                                  *
 * 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; if not, contact:                        *
 *                                                                  *
 * Free Software Foundation           Voice:  +1-617-542-5942       *
 * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
 * Boston, MA  02111-1307,  USA       gnu@gnu.org                   *
\********************************************************************/

#include "config.h"

#include <gnome.h>
#include <glib.h>

#include "gnc-engine-util.h"
#include "FileDialog.h"
#include "gnc-book.h"
#include "Transaction.h"
#include "Group.h"
#include "gnc-numeric.h"
#include "SchedXaction.h"
#include "gnc-component-manager.h"
#include "SplitLedger.h"
#include "gnc-ui-util.h"
#include "gnc-exp-parser.h"
#include "dialog-utils.h"

#include "dialog-sxsincelast.h"

#define DIALOG_SXSINCELAST_CM_CLASS "dialog-sxsincelast"

static short module = MOD_SX;

typedef struct _toCreateTransaction {
        SchedXaction *sx;
        GDate *date;

        gint clistRow;
} toCreateTransaction;

typedef struct _sxSinceLastData {
        GtkWidget *sxsincelastDlg;
        GladeXML *gxml;
        GList /* <toCreateTransaction*> */ *transList;
} sxSinceLastData;

typedef struct _reminderTuple {
        GDate	*endDate;
        GDate	*occurDate;
} reminderTuple;

static void sxsincelast_init( sxSinceLastData *sxsld );
static void sxsincelast_populate( sxSinceLastData *sxsld );
static void sxsincelast_close_handler( gpointer ud );
static void sxsincelast_ok_clicked( GtkButton *b, gpointer ud );
static void sxsincelast_cancel_clicked( GtkButton *b, gpointer ud );

static void sxsincelast_destroy( GtkObject *o, gpointer ud );

static void _create_transactions_on( SchedXaction *sx, GDate *gd );

static void processAutoCreateList( GList *, sxSinceLastData *sxsld, SchedXaction * );
static void processToCreateList( GList *, sxSinceLastData *sxsld, SchedXaction * );
static void processReminderList( GList *, sxSinceLastData *sxsld, SchedXaction * );

/* int parse_vars_from_formula( const char *formula, GHashTable *varHash ); */

void
gnc_ui_sxsincelast_guile_wrapper( char *foo )
{
        gnc_ui_sxsincelast_dialog_create();
}

void
gnc_ui_sxsincelast_dialog_create(void)
{
        sxSinceLastData        *sxsld = g_new0( sxSinceLastData, 1 );
        sxsld->gxml = gnc_glade_xml_new( "sched-xact.glade", "Real Since-Last-Run Dialog" );
        sxsld->sxsincelastDlg = glade_xml_get_widget( sxsld->gxml, "Real Since-Last-Run Dialog" );

        sxsincelast_init( sxsld );
}

static void
sxsincelast_init( sxSinceLastData *sxsld )
{
        GtkWidget        *o;
        int                i;
        struct widgetSignalHandlerTuple {
                char *name;
                char *signal;
                void (*handlerFn)();
        } widgets[] = {
                { "ok_button",     "clicked", sxsincelast_ok_clicked },
                { "cancel_button", "clicked", sxsincelast_cancel_clicked },
                { NULL,            NULL,      NULL }
        };

        gnc_register_gui_component( DIALOG_SXSINCELAST_CM_CLASS,
                                    NULL,
                                    sxsincelast_close_handler,
                                    sxsld->sxsincelastDlg );
        
        gtk_signal_connect( GTK_OBJECT(sxsld->sxsincelastDlg), "destroy",
                            GTK_SIGNAL_FUNC( sxsincelast_destroy ), sxsld );

        for ( i=0; widgets[i].name != NULL ; i++ ) {
                o = glade_xml_get_widget( sxsld->gxml, widgets[i].name );
                gtk_signal_connect( GTK_OBJECT(o), widgets[i].signal,
                                    GTK_SIGNAL_FUNC(widgets[i].handlerFn),
                                    sxsld );
                
        }

        sxsincelast_populate( sxsld );

        gtk_widget_show_all( sxsld->sxsincelastDlg );
}

static void
_generate_instances( SchedXaction *sx,
                     GDate *end,
                     GList **instanceList )
{
        GDate gd, *gdToReturn;
        char tmpBuf[26];

        gd = xaccSchedXactionGetNextInstance( sx );
        while ( g_date_valid(&gd)
                && g_date_compare( &gd, end ) <= 0 ) {

                g_date_strftime( tmpBuf, 25, "%a, %b %e, %Y", &gd );
                DEBUG( "Adding instance %s", tmpBuf );

                gdToReturn = g_date_new();
                *gdToReturn = gd;
                *instanceList = g_list_append( *instanceList, gdToReturn );

                gd = xaccSchedXactionGetInstanceAfter( sx, &gd );
        }
        if ( ! g_date_valid( &gd ) ) {
                PERR( "Should be added to dead-list..." );
        }
}

static void
_free_gdate_list_elts( gpointer data, gpointer user_data )
{
        g_date_free( (GDate*)data );
}

static void
_free_reminderTuple_list_elts( gpointer data, gpointer user_data )
{
        g_date_free( ((reminderTuple*)data)->occurDate );
        g_free( (reminderTuple*)data );
}

static void
processAutoCreateList( GList *autoCreateList, sxSinceLastData *sxsld, SchedXaction *sx )
{
        char tmpBuf[26];
        int row;
        GtkCList *cl;
        gboolean autoCreateState, notifyState;
        char *rowText[2];

        row = 0;

        /*
          get the "automagically created and notification requested"
          register, and create the entires.
          For now, this is a clist...
        */
        cl = GTK_CLIST( glade_xml_get_widget( sxsld->gxml, "auto_create_clist" ) );
        gtk_clist_freeze( cl );
        while ( autoCreateList ) {
                g_date_strftime( tmpBuf, 25, "%a, %b %e, %Y",
                                 (GDate*)autoCreateList->data );
                xaccSchedXactionGetAutoCreate( sx, &autoCreateState, &notifyState );

                _create_transactions_on( sx, (GDate*)autoCreateList->data );

                if ( notifyState ) {
                        rowText[0] = xaccSchedXactionGetName( sx );
                        rowText[1] = malloc( sizeof(gchar) * 26 ); /* FIXME */
                        g_date_strftime( rowText[1], 25, "%a, %b %e, %Y",
                                         (GDate*)autoCreateList->data );
                        gtk_clist_insert( cl, row++, rowText );
                }

                autoCreateList = autoCreateList->next;
        }
        gtk_clist_thaw( cl );

}

static void
processToCreateList( GList *toCreateList, sxSinceLastData *sxsld, SchedXaction *sx )
{
        GtkCList *clist;
        int row;
        char *rowText[2];

        row = 0;
        if ( toCreateList == NULL )
                return;

        clist = GTK_CLIST( glade_xml_get_widget( sxsld->gxml, "to_create_clist" ) );
        do {
                /* add to clist [ahem... register... ahem] */
                rowText[0] = xaccSchedXactionGetName( sx );
                rowText[1] = malloc( sizeof(char) * 25 ); /* FIXME */
                g_date_strftime( rowText[1], 25, "%a, %b %e, %Y", (GDate*)toCreateList->data );
                gtk_clist_insert( clist, row++, rowText );
        } while ( (toCreateList = toCreateList->next) );
}

static void
processReminderList( GList *reminderList, sxSinceLastData *sxsld, SchedXaction *sx )
{
        GtkCList *clist;
        int row;
        char *rowText[3];
        reminderTuple *rt;

        /* . need
             . orig end date
             . this instance date
             . sx
        */

        row = 0;

        if ( reminderList == NULL )
                return;

        clist = GTK_CLIST( glade_xml_get_widget( sxsld->gxml, "reminders_clist" ) );

        do {
                rt = (reminderTuple*)reminderList->data;
                /* add to clist [ahem... register... ahem] */
                rowText[0] = xaccSchedXactionGetName( sx );
                rowText[1] = malloc( sizeof(gchar) * 25 ); /* FIXME */
                g_date_strftime( rowText[1], 25, "%a, %b %e, %Y", rt->occurDate );
                rowText[2] = malloc( sizeof(gchar) * 5 ); /* FIXME */
                sprintf( rowText[2], "%d",
                         (g_date_julian(rt->occurDate) - g_date_julian(rt->endDate)) );

                gtk_clist_insert( clist, row++, rowText );
        } while ( (reminderList = reminderList->next) );
}


static void
sxsincelast_populate( sxSinceLastData *sxsld )
{

        GList *sxList, *instanceList;
        GList *autoCreateList, *toCreateList, *reminderList;
        SchedXaction *sx;
        GDate end, endPlusReminders;
        GDate *instDate;
        gint daysInAdvance;
        gboolean autocreateState, notifyState;
        gchar *rowText[3];
        GtkWidget *w;
        gint autoCreateRow, toCreateRow, remindersRow;
        reminderTuple *rt;

        autoCreateList = toCreateList = reminderList = NULL;
        autoCreateRow  = toCreateRow  = remindersRow = 0;

        sxList = gnc_book_get_schedxactions( gncGetCurrentBook() );

        if ( sxList == NULL ) {
                DEBUG( "No scheduled transactions to populate." );
                return;
        }

        do {
                sx = (SchedXaction*)sxList->data;
                g_date_set_time( &end, time(NULL) );
                daysInAdvance = xaccSchedXactionGetAdvanceCreation( sx );
                g_date_add_days( &end, daysInAdvance );
                
                endPlusReminders = end;
                daysInAdvance = xaccSchedXactionGetAdvanceReminder( sx );
                g_date_add_days( &endPlusReminders, daysInAdvance );
                
                
                if (0) {
                        char tmpBuf[26];

                        g_date_strftime( tmpBuf, 25, "%a, %b %e, %Y", &end );
                        DEBUG( "We'll generate the appropriate instances, now for "
                               "SX \"%s\" with end time %s...",
                               xaccSchedXactionGetName(sx),
                               tmpBuf );
                }
                instanceList = NULL;
                _generate_instances( sx, &endPlusReminders, &instanceList );

                if ( instanceList == NULL )
                        continue;

                xaccSchedXactionGetAutoCreate( sx, &autocreateState, &notifyState );
                do {
                        instDate = (GDate*)instanceList->data;
                        if ( 0 ) {
                                char tmpBuf[26];
                                g_date_strftime( tmpBuf, 25, "%a, %b %e, %Y", instDate );
                                DEBUG( "SX \"%s\" instance on %s",
                                       xaccSchedXactionGetName(sx), tmpBuf );
                        }

                        if ( (g_date_compare( &end, &endPlusReminders ) != 0)
                             && (g_date_compare( &end, instDate ) <= 0) ) {
                                /* DEBUG( "\tIs a reminder" ); */
                                rt = g_new0( reminderTuple, 1 );
                                rt->endDate = &end;
                                rt->occurDate = instDate;
                                reminderList = g_list_append( reminderList, rt );
                        } else {
                                if ( autocreateState ) {
                                        /* DEBUG( "\tauto-create" ); */
                                        autoCreateList = g_list_append( autoCreateList,
                                                                        instDate );
                                } else {
                                        /* DEBUG( "\tAdding to create list" ); */
                                        toCreateList = g_list_append( toCreateList,
                                                                      instDate );
                                }
                        }
                } while ( (instanceList = instanceList->next) );

                /* process the lists */
                processAutoCreateList( autoCreateList, sxsld, sx );
                processToCreateList  ( toCreateList,   sxsld, sx );
                processReminderList  ( reminderList,   sxsld, sx );

                g_list_foreach( autoCreateList, _free_gdate_list_elts, NULL );
                g_list_free( autoCreateList );

                g_list_foreach( reminderList, _free_reminderTuple_list_elts, NULL );
                g_list_free( reminderList );

                /* FIXME: freeup the toCreate list at a more appropriate
                   time. */

        } while ( (sxList = sxList->next) );
}

static void
sxsincelast_close_handler( gpointer ud )
{
        gnome_dialog_close( GNOME_DIALOG( ((sxSinceLastData*)ud)->sxsincelastDlg ) );
}

static void
free_elts( gpointer data, gpointer user_data )
{
        g_free( data );
}

static void
sxsincelast_ok_clicked( GtkButton *b, gpointer ud )
{
        sxSinceLastData *sxsld;
        GtkWidget *dlg;
        GtkWidget *o;
        GtkCList *cl;
        time_t gdeDate;
        GList *sxList;
        GNCBook *book;
        SchedXaction *sx;
        GDate gd, *endDate;
        gchar buf[1024];
        gint row;
        char *rowText[2];
        toCreateTransaction *tct;


        sxsld = (sxSinceLastData*)ud;

        sxsincelast_close_handler( sxsld );
        /* FIXME: the SX/date list already has been generated; we should use that. */
#if 0
        o = glade_xml_get_widget( sxsld->gxml, "next_date" );
        gdeDate = gnome_date_edit_get_date( GNOME_DATE_EDIT(o) );

        DEBUG( "Okay... I should run with a date of: %s", ctime(&gdeDate) );

        /* destroy the previous transactions
           destroy all the toCreateTransactions */
        if ( sxsld->transList != NULL ) {
                g_list_foreach( sxsld->transList, free_elts, NULL );
                g_list_free( sxsld->transList );
                sxsld->transList = NULL;
        }

        book = gncGetCurrentBook();
        sxList = gnc_book_get_schedxactions( book );
        if ( sxList == NULL ) {
                PERR( "No scheduled transactions to play with\n" );
                return;
        }
        
        endDate = g_date_new();
        g_date_set_time( endDate, gdeDate );

        o = glade_xml_get_widget( sxsld->gxml, "replace_with_register" );
        cl = GTK_CLIST(o);
        gtk_clist_clear( cl );

        g_date_clear( &gd, 1 );
        row = 0;
        do {
                sx = (SchedXaction*)sxList->data;
                // this is really "last-run-date", right?
                g_date_set_time( &gd, time(NULL) );
                
                gd = xaccSchedXactionGetInstanceAfter( sx, &gd );
                while ( g_date_compare( &gd, endDate ) <= 0
                        && g_date_valid( &gd ) ) {
                        
                        g_date_strftime( buf, 1023, "%a, %b %e, %Y", &gd );
                        /* add to clist [ahem... register... ahem] */
                        rowText[0] = xaccSchedXactionGetName( sx );
                        rowText[1] = malloc( sizeof(char) * 256 ); /* FIXME */
                        g_date_strftime( rowText[1], 255, "%a, %b %e, %Y", &gd );

                        tct = g_new0( toCreateTransaction, 1 );
                        tct->sx = sx;
                        tct->date = g_date_new();
                        *tct->date = gd;
                        tct->clistRow = row;
                        sxsld->transList = g_list_append( sxsld->transList, tct );

                        gtk_clist_insert( cl, row, rowText );
                        row += 1;
                        gd = xaccSchedXactionGetInstanceAfter( sx, &gd );
                }
        } while ( (sxList = sxList->next) );

        g_date_free( endDate );
#endif
}

static void
sxsincelast_cancel_clicked( GtkButton *o, gpointer ud )
{
        sxsincelast_close_handler( ud );
}

static void
sxsincelast_destroy( GtkObject *o, gpointer ud )
{
        DEBUG( "nuttin' doin...\n" );
}

static gboolean
_create_each_transaction( Transaction *t, void *d )
{
        Transaction        *newT;
        GDate                *gd;
        GList                *sList;
        GList                *osList;
        Split                *split;
        kvp_frame        *split_kvpf;
        kvp_value        *kvp_val;
        gboolean        errFlag;

        errFlag = FALSE;

        DEBUG( "I'm seeing Transaction \"%s\"",
                xaccTransGetDescription( t ) );

        gd = (GDate*)d;

        newT = xaccMallocTransaction();
        xaccTransBeginEdit( newT );
        /* the action and description/memo are in the template */
        gnc_copy_trans_onto_trans( t, newT, FALSE, FALSE );

        /* the date is new [gd] */
        xaccTransSetDate( newT,
                          g_date_day( gd ),
                          g_date_month( gd ),
                          g_date_year( gd ) );

        /* the accounts and amounts are in the kvp_frames of the splits. */
        osList = xaccTransGetSplitList( t );
        sList = xaccTransGetSplitList( newT );
        if ( (osList == NULL) || (sList == NULL) ) {
                PERR( "\tseen transaction w/o splits. :(" );
                return FALSE;
        }
        do {
                split = (Split*)sList->data;
                /* FIXME: Ick.  This assumes that the split lists will be
                   ordered identically. :( I think it's fair to say they
                   will, but I'd rather not have to count on it. --jsled */
                split_kvpf = xaccSplitGetSlots( (Split*)osList->data );

                DEBUG( "\tProcessing Split \"%s\"",
                        xaccSplitGetMemo( split ) );

                DEBUG( "\tkvp_frame: %s\n",
                        kvp_frame_to_string( split_kvpf ) );


                /* from-transaction of splits */
                {
                        GUID                *acct_guid;
                        Account                *acct;
                        /* contains the guid of the split's actual account. */
                        kvp_val = kvp_frame_get_slot( split_kvpf, "sched-xaction/xfrm" );
                        if ( kvp_val == NULL ) {
                                PERR( "Null kvp_val for xfrm" );
                        }
                        acct_guid = kvp_value_get_guid( kvp_val );
                        acct = xaccAccountLookup( acct_guid );
                        DEBUG( "Got account with name \"%s\"",
                                xaccAccountGetName( acct ) );
                        /* xaccSplitSetAccount( split, acct ); */
                        xaccAccountInsertSplit( acct, split );
                }
                /* credit/debit formulas */
                {
                        char                *str;
                        gnc_numeric        credit_num;
                        gnc_numeric        debit_num;
                        gnc_numeric        final;
                        int                gncn_error;

                        kvp_val = kvp_frame_get_slot( split_kvpf, "sched-xaction/credit_formula" );
                        str = kvp_value_get_string( kvp_val );
                        credit_num = gnc_numeric_create( 0, 1 );
                        if ( str != NULL ) {
                                /* parse_vars_from_formula( str, NULL ); */

                                xaccParseAmount( str, TRUE, &credit_num, NULL );
                                /* string_to_gnc_numeric( str, &credit_num ); */
                                DEBUG( "gnc_numeric::credit: \"%s\" -> \"%s\"",
                                        str, gnc_numeric_to_string( credit_num ) );
                        }
                        
                        kvp_val = kvp_frame_get_slot( split_kvpf, "sched-xaction/debit_formula" );
                        str = kvp_value_get_string( kvp_val );

                        debit_num = gnc_numeric_create( 0, 1 );
                        if ( str != NULL ) {
                                /* parse_vars_from_formula( str, NULL ); */

                                xaccParseAmount( str, TRUE, &debit_num, NULL );
                                /* string_to_gnc_numeric( str, &debit_num ); */
                                DEBUG( "gnc_numeric::debit: \"%s\" -> \"%s\"",
                                       str, gnc_numeric_to_string( debit_num ) );
                        }
                        
                        final = gnc_numeric_sub_fixed( credit_num, debit_num );
                        
                        gncn_error = gnc_numeric_check( final );
                        if ( gncn_error != GNC_ERROR_OK ) {
                                PERR( "Error %d in final gnc_numeric value", gncn_error );
                                errFlag = TRUE;
                                break;
                        }
                        DEBUG( "gnc_numeric::final: \"%s\"",
                               gnc_numeric_to_string( final ) );
                        xaccSplitSetValue( split, final );
                }
#if 0
                kvp_val = kvp_frame_get_slot( split_kvpf, "sched-xaction/shares" );
                kvp_val = kvp_frame_get_slot( split_kvpf, "sched-xaction/amnt" );
#endif /* 0 */
        } while ( (sList = sList->next) && (osList = osList->next) );

        if ( errFlag ) {
                PERR( "Some error in new transaction creation..." );
                xaccTransRollbackEdit( newT );
        } else {
                xaccTransCommitEdit( newT );
        }

        return TRUE;
        
}

static void
_create_transactions_on( SchedXaction *sx, GDate *gd )
{
        AccountGroup *ag;
        Account *acct;
        char *id;
        char tmpBuf[26];

        {
                g_date_strftime( tmpBuf, 25, "%a, %b %e, %Y", gd );
                DEBUG( "Creating transactions on %s for %s",
                       tmpBuf, xaccSchedXactionGetName( sx ) );
        }

        ag = gnc_book_get_template_group( gncGetCurrentBook() );
        id = guid_to_string( xaccSchedXactionGetGUID(sx) );
        acct = xaccGetAccountFromName( ag, id );
        DEBUG( "Got account \"%s\"\n",
               xaccAccountGetName( acct ) );
        g_free( id );

        xaccAccountForEachTransaction( acct,
                                       _create_each_transaction,
                                       gd );
        xaccSchedXactionSetLastOccurDate( sx, gd );

}

#if 0

/**
 * Parses in-fix mathematical formulas using the standard operators
 * [+-/%*], and '(', ')' grouping.
 *
 * Any strings are placed in the GHashTable as variables. The value of
 * each key in the hash-table is a struct of the form:
 * { const char *varStr;
 *   gint       idx;
 *   gint       len; };
 *
 **/
int
parse_vars_from_formula( const char *formula, GHashTable *varHash )
{
        gnc_numeric num_foo;
        char        *foo;
        GList        *list;

        gnc_exp_parser_init();
        if ( ! gnc_exp_parser_parse( formula, &num_foo, &foo ) ) {
                PERR( "Error parsing at \"%s\": %s\n",
                        foo, gnc_exp_parser_error_string() );
        }
        PINFO( "Successful parse...\n" );
        list = gnc_exp_parser_get_variable_names();
        if ( list == NULL ) {
                PINFO( "NULL variable list\n" );
        } else {
                do {
                        PINFO( "Variable \"%s\"\n",
                               list->data );
                } while ( (list = list->next) );
        }
        
        gnc_exp_parser_shutdown();
}
#endif /* 0 */

#if 0
        GScanner        *varScanner;
        GTokenType        tok;

        varScanner = g_scanner_new( NULL );
        g_scanner_set_scope( varScanner, 0 );
        g_scanner_freeze_symbol_table( varScanner );
        g_scanner_scope_add_symbol( varScanner, 0, "(", (gpointer)"left-paren" );
        g_scanner_scope_add_symbol( varScanner, 0, ")", (gpointer)"right-paren" );
        g_scanner_scope_add_symbol( varScanner, 0, "+", (gpointer)"plus" );
        g_scanner_scope_add_symbol( varScanner, 0, "-", (gpointer)"minus" );
        g_scanner_scope_add_symbol( varScanner, 0, "/", (gpointer)"div" );
        g_scanner_scope_add_symbol( varScanner, 0, "*", (gpointer)"mult" );
        g_scanner_thaw_symbol_table( varScanner );
        
        g_scanner_input_text( varScanner, formula, strlen( formula ) );
        
        do {
                tok = g_scanner_get_next_token( varScanner );
                printf( "tok: " );
                switch ( varScanner->token ) {
                case G_TOKEN_EOF:
                        printf( "EOF" ); break;
                case G_TOKEN_LEFT_PAREN:
                        printf( "(" ); break;
                case G_TOKEN_RIGHT_PAREN:
                        printf( ")" ); break;
                case G_TOKEN_LEFT_CURLY:
                        printf( "{" ); break;
                case G_TOKEN_RIGHT_CURLY:
                        printf( "}" ); break;
                case G_TOKEN_LEFT_BRACE:
                        printf( "[" ); break;
                case G_TOKEN_RIGHT_BRACE:
                        printf( "]" ); break;
                case G_TOKEN_EQUAL_SIGN:
                        printf( "=" ); break;
                case G_TOKEN_COMMA:
                        printf( "," ); break;
                case G_TOKEN_NONE:
                        printf( "NONE" ); break;
                case G_TOKEN_ERROR:
                        printf( "ERROR(%d)", varScanner->value.v_error ); break;
                case G_TOKEN_CHAR:
                        printf( "CHAR(%c)", varScanner->value.v_char ); break;
                case G_TOKEN_BINARY:
                        printf( "BINARY" ); break;
                case G_TOKEN_OCTAL:
                        printf( "OCTAL(%ul)", varScanner->value.v_octal ); break;
                case G_TOKEN_INT:
                        printf( "INT(%ul)", varScanner->value.v_int ); break;
                case G_TOKEN_HEX:
                        printf( "HEX(%ul)", varScanner->value.v_hex ); break;
                case G_TOKEN_FLOAT:
                        printf( "FLOAT(%f)", varScanner->value.v_float ); break;
                case G_TOKEN_STRING:
                        printf( "STRING(%s)", varScanner->value.v_string ); break;
                case G_TOKEN_SYMBOL:
                        printf( "SYMBOL(%s)", (gchar*)varScanner->value.v_symbol ); break;
                case G_TOKEN_IDENTIFIER:
                        printf( "IDENT(%s)", varScanner->value.v_identifier ); break;
                case G_TOKEN_IDENTIFIER_NULL:
                        printf( "NULL_IDENT" ); break;
                case G_TOKEN_COMMENT_SINGLE:
                case G_TOKEN_COMMENT_MULTI:
                        printf( "COMMENT(%s)", varScanner->value.v_comment ); break;
                case G_TOKEN_LAST:
                        printf( "END" ); break;
                default:
                        printf( "UNK" ); break;
                };
                printf( "\n" );
        } while ( (varScanner->token != G_TOKEN_LAST) &&
                  (varScanner->token != G_TOKEN_EOF) &&
                  (varScanner->token != G_TOKEN_NONE) );
        return 1;
        /*
"0.33 * ( base + ld ) + (0.25 * internet)":

tok: FLOAT(0.330000)
tok: UNK
tok: )
tok: IDENT(base)
tok: UNK
tok: IDENT(ld)
tok: (
tok: UNK
tok: )
tok: FLOAT(0.250000)
tok: UNK
tok: IDENT(internet)
tok: (
tok: EOF
        */
          
#endif /* 0 */
