#include <cstdio>
#include <cstring>
#include <stdint.h>

#include "io/FileInStream.h"
#include "io/FileOutStream.h"
#include "io/NavChartDb.h"
#include "logger/LogEngine.h"
#include "logger/TextLogWriter.h"

Str parse_line( char* buffer, unsigned int length );

void show_usage()
{
    fprintf( stderr, "Usage: process_nav [configFileName|chartsConfig] \n"
             "  configFileName defaults to ./Config/Navigation.cfg, and is the file\n"
             "  from which the NavChartDb.charts variable is read\n"
             " If the first argument is not the name of a readable file,\n"
             "  then it is assumed to be the value of NavChartDb.charts" );
}

int main( int argc, char **argv )
{
    Str chartsCfg( "./Config/Navigation.cfg" );
    if( argc > 1 )
    {
        if( strcmp( argv[1], "-h" ) == 0 || strcmp( argv[1], "--help" ) == 0 )
        {
            show_usage();
            return 0;
        }
        chartsCfg = argv[1];
    }

    FileInStream in( chartsCfg.cStr() );
    if( in.isReadable() )
    {
        chartsCfg = Str::EMPTY_STR;
        printf( "Opening Config file at: %s\n", in.getName() );
        const unsigned int bufferSize( 256 );
        char buffer[bufferSize];
        while( !in.eof() && chartsCfg == Str::EMPTY_STR )
        {
            in.readLine( buffer, bufferSize );
            chartsCfg = parse_line( buffer, in.bytesRead() );
        }
        if( chartsCfg == Str::EMPTY_STR )
        {
            fprintf( stderr, "NavChartDb.charts not set in Config file at: %s\n", in.getName() );
            return 1;
        }
        printf( "NavChartDb.charts = \"%s\"\n", chartsCfg.cStr() );
    }

    LogEngine syslogEngine;
    NavChartDb navChartDb;
    // Declaring NavChartDb creates some critical errors. To ignore them,
    // run syslogEngine.processQueue before adding output association...
    syslogEngine.processQueue( Timespan::ZERO_TIMESPAN );
    FileOutStream stdOutStream( stdout );
    syslogEngine.addAssociation( new TextLogWriter( stdOutStream ),
                                 new TypeRule( LogEntry::SYSLOG_LOG_ENTRY ) );

    // this is a shortcut for setting the charts config value
    navChartDb.setChartsCfg( chartsCfg );
    navChartDb.initialize();

    // now we loop until things are configured.
    int maxLoops = 1000000;
    while( !navChartDb.ready() && maxLoops > 0 )
    {
        navChartDb.run();
        syslogEngine.processQueue( Timespan::ZERO_TIMESPAN );
        --maxLoops;
    }
    if( maxLoops <= 0 )
    {
        fprintf( stderr, "Too many iterations processing charts\n" );
        return 1;
    }

    return 0;
}

Str parse_line( char* buffer, unsigned int length )
{
    // Parse out three space, "equals", and colon delimited words.

    const char* delim( " =;" );
    char* word0 = strtok_r( buffer, delim, &buffer );
    while( *buffer == ' ' || *buffer == '=' )
    {
        ++buffer;
    }

    if( NULL == word0 || *word0 == '/' )
    {
        return Str::EMPTY_STR;
    }
    if( strcmp( word0, "NavChartDb.charts" ) != 0 )
    {
        return Str::EMPTY_STR;
    }
    if( NULL == buffer || *buffer == '/' || *buffer == 0 )
    {
        return Str::EMPTY_STR;
    }

    // Instace of foo = "bar";
    if( *buffer == '\"' )
    {
        unsigned int maxLen = strlen( buffer );
        unsigned int wordLen = 2;
        for( ; wordLen < maxLen; ++wordLen )
        {
            if( buffer[wordLen - 1] == '\"' )
            {
                break;
            }
        }
        if( maxLen > 1 && buffer[wordLen - 1] == '\"' )
        {
            Str quoted( buffer + 1, wordLen - 2 );
            return quoted;
        }
        else
        {
            fprintf( stderr, "Unterminated quote: %s\n", buffer );
            return Str::EMPTY_STR;
        }
    }
    else
    {
        fprintf( stderr, "Setting should be quoted: %s\n", buffer );
        return Str::EMPTY_STR;
    }

}
