// HSA 2.1.1 include by Hauke Marquardt alias |-|auke - 06.04.2012
/*
License:
        This code is free: 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 3 of the License, or
        (at your option) any later version.

        This code 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, see <http://www.gnu.org/licenses/>.
        You´re not allowed to copy any code from this, into your code without
        naming authors name in credits!
*/

#if defined _hsa_included
    #endinput
#endif

#define _hsa_included

#if !defined _hsa_max_file_name_offset
    #define _hsa_max_file_name_offset   	0
#endif

#if !defined _hsa_max_files_cache_offset
    #define _hsa_max_files_cache_offset 	0
#endif

#if !defined _hsa_entries_per_file_offset
    #define _hsa_entries_per_file_offset	0
#endif

#if !defined _hsa_max_key_lenght_offset
    #define _hsa_max_key_lenght_offset 		0
#endif

#if !defined _hsa_max_value_lenght_offset
    #define _hsa_max_value_lenght_offset 	0
#endif

#define _MAX_FILE_NAME_LENGHT           	32 + _hsa_max_file_name_offset
#define _MAX_FILES                			20 + _hsa_max_files_cache_offset
#define _MAX_ENTRIES                		50 + _hsa_entries_per_file_offset
#define _MAX_KEY_LENGHT     				24 + _hsa_max_key_lenght_offset
#define _MAX_VALUE_LENGHT   				128 + _hsa_max_value_lenght_offset
#define _MAX_LINE_CACHE                 	_MAX_KEY_LENGHT + _MAX_VALUE_LENGHT + 3

#if !defined _h_library_norm_included
    #define PAWN_TYPE_INT                   1
    #define PAWN_TYPE_FLOAT                 2
    #define PAWN_TYPE_ARRAY                 3
    #define _h_library_norm_included
#endif

#define getInt:%1(%2)                   	_GetInt(%1,%2)
#define getFloat:%1(%2)                 	_GetFloat(%1,%2)
#define getString:%1(%2)                	_GetArray(%1,%2)
#define setInt:%1(%2,%3)                	_SetInt(%1,%2,%3)
#define setFloat:%1(%2,%3)              	_SetFloat(%1,%2,%3)
#define setString:%1(%2,%3)     			_SetArray(%1,%2,%3)
#define Save(%1)                         	_WriteFile(%1)
#define SaveAll(%1)                         _WriteAll(%1)

new _CachedFiles[ _MAX_FILES ][ _MAX_FILE_NAME_LENGHT ];
enum _LineCache
{
	_Key[ _MAX_KEY_LENGHT ],
	_Value[ _MAX_VALUE_LENGHT ]
}
new _FileCache[ _MAX_FILES ][ _MAX_ENTRIES ][ _LineCache ];

stock _GetInt ( File[ ] , Key[ ] ) {
    new Result[ _MAX_VALUE_LENGHT ];
    _GetData ( File , Key , Result , PAWN_TYPE_INT );
    return strval ( Result );
}

stock Float:_GetFloat ( File[ ] , Key[ ] ) {
    new Result[ _MAX_VALUE_LENGHT ];
    _GetData ( File , Key , Result , PAWN_TYPE_FLOAT );
    return floatstr ( Result );
}

stock _GetArray ( File[ ] , Key[ ] ) {
    new Result[ _MAX_VALUE_LENGHT ];
    _GetData ( File , Key , Result , PAWN_TYPE_ARRAY );
    return Result;
}

stock _SetInt ( File[ ] , Key[ ] , Value ) {
    new uValue[ _MAX_LINE_CACHE ];
    format ( uValue , _MAX_LINE_CACHE , "%d" , Value );
    _SetData ( File , Key , uValue );
}

stock _SetFloat ( File[ ] , Key[ ] , Float:Value ) {
    new uValue[ _MAX_LINE_CACHE ];
    format ( uValue , _MAX_LINE_CACHE , "%f" , Value );
    _SetData ( File , Key , uValue );
}

stock _SetArray ( File[ ] , Key[ ] , Value[ ] ) {
    _SetData ( File , Key , Value );
}

stock _GetData ( File[ ] , Key[ ] , Result[ ] , Type ) {
    new FileName[ _MAX_FILE_NAME_LENGHT ] , File:file;
    format ( FileName , _MAX_FILE_NAME_LENGHT , "%s.hsa" , File );
    if ( _GetFileCacheIndex ( File ) == -1 ) {
		new CacheSlot = _GetFreeCacheSlot ( ) , Line[ _MAX_LINE_CACHE  ] , readLine , rIdx = -1;
		format ( _CachedFiles[ CacheSlot ] , _MAX_FILE_NAME_LENGHT , File );
        file = fopen ( FileName , io_readwrite );
		while ( fread ( file , Line ) ) {
	        Line[ strlen ( Line ) -2 ] = '\0';
	        strmid ( _FileCache[ CacheSlot ][ readLine ][ _Key ] , Line , 0 , strfind ( Line , "=" , false ) , _MAX_KEY_LENGHT );
	        strmid ( _FileCache[ CacheSlot ][ readLine ][ _Value ] , Line , strfind ( Line , "=" , false ) + 1 , strlen ( Line ) , _MAX_VALUE_LENGHT );
	        if ( !strcmp ( _FileCache[ CacheSlot ][ readLine ][ _Key ] , Key ) && strlen ( _FileCache[ CacheSlot ][ readLine ][ _Key ] ) )
				rIdx = readLine;
	        readLine++;
		}
		fclose ( file );
		if ( rIdx != -1 )
			return format ( Result , _MAX_VALUE_LENGHT , _FileCache[ CacheSlot ][ rIdx ][ _Value ] );
		else {
		    format ( _FileCache[ CacheSlot ][ readLine ][ _Key ] , _MAX_KEY_LENGHT , Key );
		    switch ( Type ) {
		        case PAWN_TYPE_INT:
		            format ( _FileCache[ CacheSlot ][ readLine ][ _Value ] , _MAX_VALUE_LENGHT , "0" );
		        case PAWN_TYPE_FLOAT:
		            format ( _FileCache[ CacheSlot ][ readLine ][ _Value ] , _MAX_VALUE_LENGHT , "0.0" );
		        case PAWN_TYPE_ARRAY:
		            format ( _FileCache[ CacheSlot ][ readLine ][ _Value ] , _MAX_VALUE_LENGHT , "" );
		    }
		}
		return _FileCache[ CacheSlot ][ readLine ][ _Value ];
 	}
    else {
		new CacheSlot = _GetFileCacheIndex ( File ) , Idx;
		for ( ; Idx < _MAX_ENTRIES; Idx++ )
		    if ( !strcmp ( _FileCache[ CacheSlot ][ Idx ][ _Key ] , Key ) && strlen ( _FileCache[ CacheSlot ][ Idx ][ _Key ] ) )
		        return format ( Result , _MAX_VALUE_LENGHT , _FileCache[ CacheSlot ][ Idx ][ _Value ] );
	    new AppendEntry = _GetFreeEntry ( CacheSlot );
	    if ( AppendEntry == -1 )
	        return print ( "HSA ERROR: Entries set too low!" );
  		format ( _FileCache[ CacheSlot ][ AppendEntry ][ _Key ] , _MAX_KEY_LENGHT , Key );
        switch ( Type ) {
	        case PAWN_TYPE_INT:
	            format ( _FileCache[ CacheSlot ][ AppendEntry ][ _Value ] , _MAX_VALUE_LENGHT , "0" );
	        case PAWN_TYPE_FLOAT:
	            format ( _FileCache[ CacheSlot ][ AppendEntry ][ _Value ] , _MAX_VALUE_LENGHT , "0.0" );
	        case PAWN_TYPE_ARRAY:
	            format ( _FileCache[ CacheSlot ][ AppendEntry ][ _Value ] , _MAX_VALUE_LENGHT , "" );
	    }
	    return format ( Result , _MAX_VALUE_LENGHT , _FileCache[ CacheSlot ][ AppendEntry ][ _Value ] );
	}
}

stock _SetData ( File[ ] , Key[ ] , Value[ ] )
{
    new FileName[ _MAX_FILE_NAME_LENGHT ] , File:file;
    format ( FileName , _MAX_FILE_NAME_LENGHT , "%s.hsa" , File );
    if ( _GetFileCacheIndex ( File ) == -1 ) {
        new CacheSlot = _GetFreeCacheSlot ( ) , Line[ _MAX_LINE_CACHE  ] , readLine , rIdx = -1;
		format ( _CachedFiles[ CacheSlot ] , _MAX_FILE_NAME_LENGHT , File );
        file = fopen ( FileName , io_readwrite );
		while ( fread ( file , Line ) ) {
	        Line[ strlen ( Line ) -2 ] = '\0';
	        strmid ( _FileCache[ CacheSlot ][ readLine ][ _Key ] , Line , 0 , strfind ( Line , "=" , false ) , _MAX_KEY_LENGHT );
	        strmid ( _FileCache[ CacheSlot ][ readLine ][ _Value ] , Line , strfind ( Line , "=" , false ) + 1 , strlen ( Line ) , _MAX_VALUE_LENGHT );
	        if ( !strcmp ( _FileCache[ CacheSlot ][ readLine ][ _Key ] , Key ) && strlen ( _FileCache[ CacheSlot ][ readLine ][ _Key ] ) )
	            rIdx = readLine;
	        readLine++;
		}
		fclose ( file );
		if ( rIdx != -1 )
		    return format ( _FileCache[ CacheSlot ][ rIdx ][ _Value ] , _MAX_VALUE_LENGHT , Value );
		else {
		    format ( _FileCache[ CacheSlot ][ readLine ][ _Key ] , _MAX_KEY_LENGHT , Key );
		    return format ( _FileCache[ CacheSlot ][ readLine ][ _Value ] , _MAX_VALUE_LENGHT , Value );
		}
    }
    else {
        new CacheSlot = _GetFileCacheIndex ( File ) , Idx;
		for ( ; Idx < _MAX_ENTRIES; Idx++ )
		    if ( !strcmp ( _FileCache[ CacheSlot ][ Idx ][ _Key ] , Key ) && strlen ( _FileCache[ CacheSlot ][ Idx ][ _Key ] ) )
		        return format ( _FileCache[ CacheSlot ][ Idx ][ _Value ] , _MAX_VALUE_LENGHT , Value );
	    new AppendEntry = _GetFreeEntry ( CacheSlot );
	    if ( AppendEntry == -1 )
	        return print ( "HSA ERROR: Entries set too low!" );
  		format ( _FileCache[ CacheSlot ][ AppendEntry ][ _Key ] , _MAX_KEY_LENGHT , Key );
        return format ( _FileCache[ CacheSlot ][ AppendEntry ][ _Value ] , _MAX_VALUE_LENGHT , Value );
    }
}

stock _WriteFile ( File[ ] ) {
    new FileName[ _MAX_FILE_NAME_LENGHT ] , File:file , Line[ _MAX_LINE_CACHE ] , CacheSlot = _GetFileCacheIndex ( File );
    format ( FileName , _MAX_FILE_NAME_LENGHT , "%s.hsa" , File );
    if ( _GetFileCacheIndex ( File ) == -1 )
        return -1;
	fremove ( FileName );
    file = fopen ( FileName , io_append );
    for ( new Idx; Idx < _MAX_ENTRIES; Idx++ ) {
        if ( strlen ( _FileCache[ CacheSlot ][ Idx ][ _Key ] ) < 1 )
            break;
        format ( Line , _MAX_LINE_CACHE , "%s=%s\r\n" , _FileCache[ CacheSlot ][ Idx ][ _Key ] , _FileCache[ CacheSlot ][ Idx ][ _Value ] );
        fwrite ( file , Line );
    }
    return fclose ( file );
}

stock _WriteAll ( ) {
	for ( new Slot; Slot < _MAX_FILES; Slot++ )
	{
	    if ( strlen ( _CachedFiles[ Slot ] ) < 1 )
	        continue;
	    new FileName[ _MAX_FILE_NAME_LENGHT ] , File:file , Line[ _MAX_LINE_CACHE ];
	    format ( FileName , _MAX_FILE_NAME_LENGHT , "%s.hsa" , _CachedFiles[ Slot ] );
		fremove ( FileName );
	    file = fopen ( FileName , io_append );
	    for ( new Idx; Idx < _MAX_ENTRIES; Idx++ ) {
	        if ( strlen ( _FileCache[ Slot ][ Idx ][ _Key ] ) < 1 )
	            break;
	        format ( Line , _MAX_LINE_CACHE , "%s=%s\r\n" , _FileCache[ Slot ][ Idx ][ _Key ] , _FileCache[ Slot ][ Idx ][ _Value ] );
	        fwrite ( file , Line );
	    }
	    fclose ( file );
	}
}

stock _FreeCache ( ) {
    for ( new Slot; Slot < _MAX_FILES; Slot++ )
        _FreeSlot ( Slot );
}

stock _FreeSlot ( Slot ) {
    for ( new Idx; Idx < _MAX_ENTRIES; Idx++ ) {
		_FileCache[ Slot ][ Idx ][ _Key ][ 0 ] = '\0';
		_FileCache[ Slot ][ Idx ][ _Value ][ 0 ] = '\0';
	}
}

stock _GetFreeEntry ( Slot )
{
	for ( new Idx; Idx < _MAX_ENTRIES; Idx++ )
	    if ( strlen ( _FileCache[ Slot ][ Idx ][ _Key ] ) < 1 )
	        return Idx;
	return -1;
}

stock _GetFileCacheIndex ( File[ ] ) {
	for ( new Idx; Idx < _MAX_FILES; Idx++ )
	    if ( !strcmp ( _CachedFiles[ Idx ] , File ) && strlen ( _CachedFiles[ Idx ] ) )
	        return Idx;
	return -1;
}

stock _GetFreeCacheSlot ( )
{
    for ( new index; index < _MAX_FILES; index++ )
	    if ( strlen ( _CachedFiles[ index ] ) == 0 )
	        return index;
	return -1;
}
