//This code is copyright Andrew Story (Kaslai/Aslai) All rights reserved.
//This and derivative works can be distributed as seen fit,
//so long as this notice remains unchanged and present

#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "fileParse.h"

#define getArg(a) args[(a)]

    AParse::AParse()
    {
        funcs = 0;
        funcCount = 0;

    }

    int AParse::strcmpl( const char* str1, const char* str2 )
    {
        char* a = (char*) malloc( strlen( str1 ) + 1 );
        char* b = (char*) malloc( strlen( str2 ) + 1 );
        strcpy( a, str1 );
        strcpy( b, str2 );
        strlwr( a );
        strlwr( b );
        int c = strcmp( a, b );
        free( a );
        free( b );
        return c;
    }
    int AParse::charToInt( const char* in , const char* terminators, int termlen )
    {
        int ret = 0;
        int end = 0;

        while( true )
        {
            int i = 0;

            for( i = 0; i < termlen; i++ )
            {
                if( in[end] == terminators[i] )
                    break;
            }

            if( in[end] == terminators[i] )
                break;

            end ++;
        }

        for( int i = end - 1, mult = 10; i >= 0; i --, mult *= 10 )
            if( in[i] <= '9' && in[i] >= '0' )
                ret += ( in[i] - '0' ) * mult / 10;
            else
                mult /= 10;

        if( in[0] == '-' )
            ret *= -1;

        return ret;
    }
    char* AParse::readWord( char* in, int* length, bool copy, const char* terminators, int termlen, int terminate, int dead )
    {
        int len = 0;

        while( true )
        {
            if( len >= dead )
            {
                int i = 0;

                for( i = 0; i < termlen; i++ )
                {
                    if( in[len] == terminators[i] )
                        break;
                }

                if( in[len] == terminators[i] )
                    break;
            }

            len ++;
        }

        if( !copy )
        {
            if( terminate )
                in[len] = 0;
            if( length != 0 )
                *length = len;
            return in;
        }
        else
        {
            char* ret = ( char* ) malloc( len + 1 );

            for( int i = 0; i < len; i ++ )
                ret[i] = in[i];

            ret[len] = 0;
            if( length != 0 )
                *length = len;
            return ret;
        }
    }


    void AParse::addFunc( char* id, char* format, void ( *func )( void* data, int* func ), void* userdata)
    {
        if( funcs == 0 )
            funcs = ( function* ) malloc( 0 );

        funcs = ( struct function* ) realloc(( void* ) funcs, ( funcCount + 1 ) * sizeof( function ) );
        funcs[funcCount].id = id;
        funcs[funcCount].format = format;
        funcs[funcCount].func = func;
        funcs[funcCount].userdata = userdata;

        funcCount++;
    }
    void AParse::clearFuncs()
    {
        free( funcs );
        funcs = 0;
        funcCount = 0;
    }
    bool AParse::parseScipt( const char* fname )
    {
        FILE* blockTXT = fopen( fname, "r" );
        if( blockTXT <= 0 )
        {
            printf( "Unable to open \"%s\"\n", fname );
            return false;
        }
        else
        {
            int len = 0;
            char* input = ( char* ) malloc( 0 );
            int a = 0;

            while( !feof( blockTXT ) )
            {
                len += 512;
                input = ( char* ) realloc(( void* ) input, len );

                for( ; a < len; a++ )
                {
                    input[a] = fgetc( blockTXT );
                    if( feof( blockTXT ) )
                        len = a;
                }
            }
            input = ( char* ) realloc(( void* ) input, len );
            parseScipt( input, len );
            free( input );
            fclose( blockTXT );
            return true;
        }
    }

    bool AParse::parseScipt( void* inputt, int len )
    {
        //printf("%x", inputt );
        char* input = (char*) inputt;
            char* nextword = ( char* ) malloc( 0 );
            int l = 0;
    #define getword(atmp)             while( input[a] == ' ' || input[a] == '\r' || input[a] == '\n' || input[a] == '\t' ){ a ++;} \
        if ( input[a] == '[' ) { readWord(input + a, &l, false, "]\0", 2 ); a += l+1; atmp; continue; } \
        nextword = (input[a] != '\"') ? readWord(input + a, &l, true, "\r\n\t \0", 5 ) : readWord(input + a + 1, &l, true, "\"\0", 2); if ( input[a] == '\"' ) a +=2;  a += l

            for( int a = 0; a < len; )
            {
                //printf("haha %i\n", a);
                getword();
                bool k = false;
                for( int i = 0; i < funcCount; i ++ )
                {
                    if( strcmpl( nextword, funcs[i].id ) == 0 )
                    {
                        k = true;
                        int len;
                        for( len = 0; funcs[i].format[len] != 0; len ++ );
                        int arg = 0;
                        int* tmp = ( int* ) malloc( len * sizeof( int ) );
                        for( int k = 0; funcs[i].format[k] != 0; k ++ )
                        {
                            getword(k--);
                            if( funcs[i].format[k] == 'i' )
                            {
                                tmp[arg++] = charToInt( nextword, "\0", 1 );
                            }
                            else
                            {
                                int t = *((int*)(&nextword));
                                tmp[arg++] = t;
                            }
                        }
                        funcs[i].func( funcs[i].userdata, tmp );
                        free( tmp );
                        break;
                    }
                }
                if( k == false )
                {
                    //printf( "a:%i %i\tUnknown function: %s\n", a, len, nextword );

                }
            }

        }
#undef getword(atmp)