/*
	nFile - a "file managing system"
	Author:		NeoPhoenix
	Date:   	30/12/2011
*/

////////Avoiding multiple includes//////
#if defined ___including_nfile
	#endinput
#endif
#define ___including_nfile
#define nfile:: nfile_
////////////////////////////////////////

//Debugging
//		#define __nfile__debug_error						//Will log all nfile errors
//		#define __nfile__debug_info							//Will log all nfile infos
//		#define __nfile__debug_console						//Will print all debugs in console
//nFile settings
        #include <a_samp>
		#include <a_http>
		#define MAX_GET 			(150)					//Key and Values
		#define MAX_FILE_NAME_LEN 	(50)					//Max len of a filename
		#define MAX_PATH_LEN    	(MAX_FILE_NAME_LEN+80)	//Max len of a whole path (excluding filename)
		#define STANDART_DELIM 		"="						//Key-Value deliminter (key=value\r\n)
		#define __debug__logfile    "/nfile/logs"			//Path for the debugging logfile
		#define __tmp_nfile_cache	"/nfile/tmp"			//Path for the temporal files (copying)



/*	Function overview:
		nfile_Init()
		nfile_Exists(filename[])
		nfile_Create(path[],bool:__switch=true)
		nfile_Delete(path[]="")
		nfile_Reset(path[]="")
		nfile_Copy(newpath[],oldpath[]="",bool:_rewrite=false)
		nfile_Open(path[])
		nfile_Switch(path[])
		nfile_Close()
		nfile_AddKey(key[],value[]="",path[]="",delim[]=STANDART_DELIM)
		nfile_ValidKey(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true)
		nfile_RemoveKey(key[],path[]="",delim[]=STANDART_DELIM)
		nfile_GetValue(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true,bool:_read_body=true)
		nfile_GetString(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true,bool:_read_body=true)
		nfile_GetInt(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true,bool:_read_body=true)
		nfile_GetBool(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true,bool:_read_body=true)
		nfile_GetFloat(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true,bool:_read_body=true)
		nfile_GetArray(key[],insert_array[][],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true,const a_size=sizeof(insert_array),const b_size=sizeof(insert_array[]))
		nfile_SetValue(key[],value[],path[]="",delim[]=STANDART_DELIM)
		nfile_SetString(key[],value[],path[]="",delim[]=STANDART_DELIM)
		nfile_SetInt(key[],value,path[]="",delim[]=STANDART_DELIM)
		nfile_SetBool(key[],bool:value,path[]="",delim[]=STANDART_DELIM)
		nfile_SetFloat(key[],Float:value,path[]="",delim[]=STANDART_DELIM)
		misc_string_GetKey(input[],delim[])
		misc_string_GetValue(input[],delim[])
		misc_GetFilenameFromPath(path[])
		debug_Log(insert_log[])	

		
					->
	//More detailed ->
					->
					
	native nfile_Init();
	//Checking for new updated... (internet connection required)
	@return
		int[1]

	native nfile_Create(path[],bool:__switch=true);
	//Creates a new file
	@return
		0  - already exists
		1  - success
		-1 - unknown error occured
		-2 - no path

	native nfile_Delete(path[]="");
	//Deletes a whole file
	@return
		0  - file does not exist
		1  - success
		-1 - fail
		-2 - no path

	native nfile_Reset(path[]="");
	//Empties a file
	@return
		1 - success
		0 - file does not exist

	native nfile_Copy(newpath[],oldpath[]="",bool:_rewrite=false);
	//Copies a file (source wont be deleted)
	@return
		-1 - no old path
		-2 - file does not exist
		-3 - newpath already exists
		-4 - no new path
		 1 - success

	native bool:nfile_Exists(filename[]);
	//Checks if the file "filename[]" exists
		bool[
				true 	- file exists
				false 	- file does not exist
			]

	native bool:nfile_Open(path[]);
	@return
		bool[
				true 	- success
				false 	- unable to open
			]
			
	native bool:nfile_Switch(path[]);
	//Closes the aktive connection and nfile_Open(path);
	@return
		bool
			[
				-> nfile_Open(path);
			]
			
	native nfile_Close();
	//Closes the aktive connection. You have to select a new path in each function or use nfile_Open(path[]);
	@return
		0 - no file selected yet
		1 - successfully closed

	native nfile_AddKey(key[],value[]="",path[]="",delim[]=STANDART_DELIM);
	//Adds a key in file "key[]=0\r\n"
	@return
		0  - file does not exist
		2  - key already exists
		1  - success
		-1 - no key
		-2 - no path

	native bool:nfile_ValidKey(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true);
	//Checks if "key[]" is available
	@return
		bool[
			true 	- key[] exists
			false 	- key[] does not exist
			]
	
	native nfile_GetValue(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true,bool:_read_body=true);
	native nfile_GetString(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true,bool:_read_body=true);
	native nfile_GetInt(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true,bool:_read_body=true);
	native nfile_GetBool(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true,bool:_read_body=true);
	native nfile_GetFloat(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true,bool:_read_body=true);
	//Returns the value where "key=key[]"
	@return
		value[string]
			{
				empty (maybe):
					- no path
					- no key
			}

    native nfile_GetArray(key[],insert_array[][],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true,const a_size=sizeof(insert_array),const b_size=sizeof(insert_array[]));
    //Stores the array "ARRAY{a,b,c}" into insert_array[]
	@return
		nothing

	native nfile_SetValue(key[],value[],path[]="",delim[]=STANDART_DELIM);
	native nfile_SetString(key[],value[],path[]="",delim[]=STANDART_DELIM);
	native nfile_SetInt(key[],value,path[]="",delim[]=STANDART_DELIM);
	native nfile_SetBool(key[],bool:value,path[]="",delim[]=STANDART_DELIM);
	native nfile_SetFloat(key[],Float:value,path[]="",delim[]=STANDART_DELIM);
	//Will set the value where key=key[]
	@return
		1  - success
		0  - file does not exist
		-1 - no key
		-2 - no path

	native misc_string_GetKey(input[],delim[]);
	//Splits the key
	@return
		value[string]

	native misc_string_GetValue(input[],delim[]);
	//Splits the value
	@return
		value[string]

	native misc_GetFilenameFromPath(path[]);
	//Gets the filename from a path
	@return
		value[string]

	native debug_Log(insert_log[]);
	//Will log all info and errormessages
	@return
		1 - success
		0 - unknown error occured
	
	native nfile_RemoveKey(key[],path[]="",delim[]=STANDART_DELIM)
	//Removes a key
		-1 - no key
		-2 - no path
		-3 - key does not exist
		 0 - file does not exist
		 1 - success

	native nfile_Append(insert[],path[]="")
	//Writes insert[] in path[]
		-1 - file does not exist
		 0 - unknown
   		 1 - success
*/

//Functions
#define nfile_GetInt(%0)    	strval(nfile_GetValue(%0))
#define nfile_GetFloat(%0)  	floatstr(nfile_GetValue(%0))
#define nfile_GetString(%0) 	nfile_GetValue(%0)
#define nfile_Exists(%0)		(fexist(%0)==1?true:false)
#define nfile_SetString(%0)		nfile_SetValue(%0)	
#define escape_string(%0) while(strfind(%0,"\n") != -1)  %0[strfind(%0,"\n")] = ' ';\
while(strfind(%0,"\r") != -1) %0[strfind(%0,"\r")] = ' ';
	
new nfile_string[150];
enum e_file
{
	__path[MAX_PATH_LEN],
	bool:__opened,
	File:__file,
}
new ___file[e_file];

stock nfile_Init()
{
	nfile_Switch("/nfile/nfile.init");
	print("\n");
	print("------nFile.startup---------");
	printf("Author:     	%s",nfile_GetString("author"));
	printf("Version 	%0.1f",nfile_GetFloat("version"));
	printf("Codename 	%s",nfile_GetString("codename"));

	new a[3][5];
	nfile_GetArray("updated",a);
	new year	= strval(a[0]),
	    month 	= strval(a[1]),
	    day     = strval(a[2]);
	printf("Last update 	%d/%d/%d",day,month,year);
    print("----------------------------");
	print("\n");
	HTTP(nfile_GetInt("update_ts"),HTTP_GET,"release.neophoenix.net/nfile/last_update.txt","","nfile_checkupdate");
	nfile_Close();
	return 1;
}

forward nfile_checkupdate(index, response_code, data[]);
public nfile_checkupdate(index, response_code, data[])
{
	if(response_code == 200)
	{
		if(strval(data) > index)
		{//Update available
			HTTP(0,HTTP_GET,"release.neophoenix.net/nfile/version.txt","","nfile_readupdate");
		}
	}
	else print("nfile_Update.INFO: Could not connect to server");
	return 1;
}
forward nfile_readupdate(index, response_code, data[]);
public nfile_readupdate(index, response_code, data[])
{
	printf("nfile_Update.INFO: NEW VERSION (%s) OF NFILE AVAILABLE AT NEOPHOENIX.NET",data);
	return 1;
}

stock nfile_Delete(path[]="")
{
	new filename[MAX_FILE_NAME_LEN];
	if(strlen(path) == 0) strmid(filename,___file[__path],0,strlen(___file[__path]),255);
 	else strmid(filename,path,0,strlen(path),255);
	if(!path[0]) return -2;
	if(!nfile_Exists(filename))
	{
		#if defined __nfile__debug_error
			format(nfile_string,sizeof(nfile_string),"nfile_Delete.ERROR: File \"%s\" does not exist.",filename);
			debug_Log(nfile_string);
		#endif
		return 0;
	}
	if(!strcmp(filename,___file[__path],true)) nfile_Close();
	fremove(filename);
	if(!nfile_Exists(filename))
	{
		#if defined __nfile__debug_info
			format(nfile_string,sizeof(nfile_string),"nfile_Delete.INFO: File \"%s\" has been removed.",filename);
			debug_Log(nfile_string);
		#endif
		return 1;
	}
	#if defined __nfile__debug_error
		format(nfile_string,sizeof(nfile_string),"nfile_Delete.ERROR: Wasnt able to delete file \"%s\"",filename);
		debug_Log(nfile_string);
	#endif
	return -1;
}

stock nfile_Create(path[],bool:__switch=true)
{
	if(!path[0]) return -2;
    if(nfile_Exists(path))
	{
		#if defined __nfile__debug_error
			format(nfile_string,sizeof(nfile_string),"nfile_Create.ERROR: File \"%s\" already exists",path);
			debug_Log(nfile_string);
		#endif
		return 0;
	}
	___file[__file] = fopen(path,io_write);
	if(___file[__file])
 	{
  		fclose(___file[__file]);
		#if defined __nfile__debug_info
			format(nfile_string,sizeof(nfile_string),"nfile_Create.INFO: File \"%s\" created.",path);
			debug_Log(nfile_string);
		#endif
		if(__switch) nfile_Open(path);
		return 1;
	}
	fclose(___file[__file]);
	#if defined __nfile__debug_error
		format(nfile_string,sizeof(nfile_string),"nfile_Create.ERROR: File \"%s\" could not be created.",path);
		debug_Log(nfile_string);
	#endif
	return -1;
}

forward bool:nfile_Switch(path[]);
stock bool:nfile_Switch(path[])
{
	if(!path[0]) return false;
	if(___file[__opened]) nfile_Close();
	return nfile_Open(path);
}

forward bool:nfile_Open(path[]);
stock bool:nfile_Open(path[])
{
	if(!path[0]) return false;
	if(___file[__opened]) nfile_Close();
    if(!nfile_Exists(path)) nfile_Create(path);

	___file[__file] = fopen(path,io_read);
	if(___file[__file])
	{
	    ___file[__opened] = true;
	    strmid(___file[__path],path,0,strlen(path),255);
	    fclose(___file[__file]);
		#if defined __nfile__debug_info
			format(nfile_string,sizeof(nfile_string),"nfile_Open.INFO: File \"%s\" opened.",___file[__path]);
			debug_Log(nfile_string);
		#endif
		return true;
	}
	fclose(___file[__file]);
	#if defined __nfile__debug_error
		format(nfile_string,sizeof(nfile_string),"nfile_Open.ERROR: Unable to open file \"%s\".",path);
		debug_Log(nfile_string);
	#endif
	return false;
}

stock nfile_Close()
{
    if(!___file[__opened])
	{
		#if defined __nfile__debug_error
			format(nfile_string,sizeof(nfile_string),"nfile_Close.ERROR: File \"%s\" already closed.",___file[__path]);
			debug_Log(nfile_string);
		#endif
		return 0;
	}
	#if defined __nfile__debug_info
		format(nfile_string,sizeof(nfile_string),"nfile_Close.INFO: File \"%s\" closed.",___file[__path]);
		debug_Log(nfile_string);
	#endif
	___file[__opened] 	= false;
	___file[__path][0]	= 0;
	return 1;
}

forward bool:nfile_GetBool(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true);
stock bool:nfile_GetBool(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true)
{
	if(!key[0]) return false;
	new result[10];
	strmid(result,nfile_GetValue(key,path,delim,_use_tplscript),0,5,255);
	if(!result[0]) return false;
	if(strval(result) == 1) return true;
	if(!strcmp(result,"true")) return true;
	return false;
}

stock nfile_GetValue(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true)
{
	new filename[MAX_FILE_NAME_LEN],
		value[MAX_GET];
	if(!key[0]) return value;
	if(strlen(path) == 0) strmid(filename,___file[__path],0,strlen(___file[__path]),255);
	else strmid(filename,path,0,strlen(path),255);
	if(!filename[0]) return value;
	if(!nfile_Exists(filename)) return value;
	___file[__file] = fopen(filename,io_read);
	new line[(2*MAX_GET)+3],
		comment=false;
	escape_string(key)	
 	while(fread(___file[__file],line,sizeof(line)))
	{
		if(_use_tplscript)
		{
		    if(line[0] == '/')
		    {
		        if(line[1] == '*') comment = true;
		        continue;
		    }
		    if(comment)
		    {
		        if(line[0] == '*' && line[1] == '/') comment = false;
		        continue;
		    }
		}
		
		if(line[strlen(line)-2] == '\r') line[strlen(line)-2] = 0;
		if(line[strlen(line)-1] == '\n') line[strlen(line)-1] = 0;

    	if(misc_nfile_CheckKey(line,key,delim))
		{
		    format(value,MAX_GET,"%s",misc_nfile_string_GetValue(line,strlen(key)+strlen(delim)));
		    fclose(___file[__file]);
		    return value;
		}
	}
	fclose(___file[__file]);
	value[0] = 0;
	return value;
}

stock nfile_SetArray(key[],insert_array[][],path[]="",delim[]=STANDART_DELIM,const a_size=sizeof(insert_array),const b_size=sizeof(insert_array[]))
{
	if(!key[0]) return ;
	new filename[MAX_FILE_NAME_LEN];
	if(strlen(path) == 0) strmid(filename,___file[__path],0,strlen(___file[__path]),255);
	else strmid(filename,path,0,strlen(path),255);
	if(!filename[0]) return ;
	if(!nfile_Exists(filename)) return ;

	new inserted = 0;
	format(nfile_string,sizeof(nfile_string),"ARRAY{");
	for(new al; al<a_size; al++)
	{
		if(!insert_array[al][0]) continue;
		escape_string(insert_array[al])
		format(nfile_string,sizeof(nfile_string),"%s%s,",nfile_string,insert_array[al]);
		inserted++;
	}
	if(inserted >= 1) nfile_string[strlen(nfile_string)-1] = '}';
	else format(nfile_string,sizeof(nfile_string),"ARRAY{}");
	nfile_SetValue(key,nfile_string,filename,delim);
	#pragma unused b_size
	return ;
}

stock nfile_GetArray(key[],insert_array[][],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true,const a_size=sizeof(insert_array),const b_size=sizeof(insert_array[]))
{
	if(!key[0]) return ;
	new result[MAX_GET],tmp_result[MAX_GET];
	escape_string(key)
    strmid(result,nfile_GetValue(key,path,delim,_use_tplscript),0,sizeof(result),255);
	if(!result[0]) return ;
    strmid(tmp_result,result,0,5,255);	
    
    new a_delimiter[2] = {0,...};
    for(new c=strlen(result); c>=0; c--)
    {
        if(result[c] == '{' && !a_delimiter[0]) a_delimiter[0] = c;
        if(result[c] == '}' && !a_delimiter[1]) a_delimiter[1] = c;
    }
    if(a_delimiter[0] >= a_delimiter[1])
	{
		#if defined __nfile__debug_error
			debug_Log("nfile_GetArray.ERROR: Parsing error type 1");
		#endif
		return ;
	}
	if((strcmp(tmp_result,"ARRAY") && strcmp(tmp_result,"array")) || !a_delimiter[0] || !a_delimiter[1])
    {
		#if defined __nfile__debug_error
			debug_Log("nfile_GetArray.ERROR: Parsing error type 2");
		#endif
        return ;
    }
    for(new i1; i1<a_size; i1++) for(new i2; i2<b_size; i2++) insert_array[i1][i2] = 0;//Reset array
    new index[2] = {0,-1};
    for(new c=(a_delimiter[0]+1); c<a_delimiter[1]; c++)
    {
		if(result[c] == ',')
		{
		    if(++index[0] >= a_size) break;
		    index[1] = -1;
		    continue;
		}
		if(++index[1] >= b_size) continue;
		insert_array[/**/index[0]/**/][/**/index[1]/**/] = result[c];
    }
	#if defined __nfile__debug_info
	    format(nfile_string,sizeof(nfile_string),"nfile_GetArray.INFO: Got array from \"\%s\"",result);
		debug_Log(nfile_string);
	#endif
	return ;
}

forward bool:misc_nfile_CheckKey(line[],key[],delim[]=STANDART_DELIM);
stock bool:misc_nfile_CheckKey(line[],key[],delim[]=STANDART_DELIM)
{
	format(nfile_string,sizeof(nfile_string),"%s%s",key,delim);
	return strfind(line,nfile_string,true)==0?true:false;
}

stock misc_nfile_string_GetValue(input[],start)
{
	new value[MAX_GET];
	if(!input[0]) return value;
	strmid(value,input,start,strlen(input),MAX_GET);
	return value;
}

stock misc_GetFilenameFromPath(path[])
{
	new filename[MAX_FILE_NAME_LEN],
		splitd =-1;
	if(!path[0]) return filename;	
	format(filename,sizeof(filename),"%s",path);
	for(new c=strlen(path); c>=0; c--)
	{
	    if(path[c] == '/' && splitd == -1)
	    {
	        splitd = c;
	        break;
	    }
	}
	if(splitd != -1) strmid(filename,filename,splitd+1,strlen(filename),255);
	return filename;
}

forward bool:nfile_ValidKey(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true);
stock bool:nfile_ValidKey(key[],path[]="",delim[]=STANDART_DELIM,bool:_use_tplscript=true)
{
	if(!key[0]) return false;
	new filename[MAX_FILE_NAME_LEN];
	if(strlen(path) == 0) strmid(filename,___file[__path],0,strlen(___file[__path]),255);
	else strmid(filename,path,0,strlen(path),255);
	if(!filename[0]) return false;
	if(!nfile_Exists(filename)) return false;
	___file[__file] = fopen(filename,io_read);
	new line[(2*MAX_GET)+3],
		comment=false;
	escape_string(key)

 	while(fread(___file[__file],line,sizeof(line)))
	{
		if(!line[0]) continue;
		if(_use_tplscript)
		{
		    if(line[0] == '/')
		    {
		        if(line[1] == '*') comment = true;
		        continue;
		    }
		    if(comment)
		    {
		        if(line[0] == '*' && line[1] == '/') comment = false;
		        continue;
		    }
		}
		
		if(line[strlen(line)-2] == '\r') line[strlen(line)-2] = 0;
		if(line[strlen(line)-1] == '\n') line[strlen(line)-1] = 0;
		
    	if(misc_nfile_CheckKey(line,key,delim) == true)
		{
			fclose(___file[__file]);
			return true;		    
		}
	}
	fclose(___file[__file]);
	return false;
}

stock nfile_Copy(newpath[],oldpath[]="",bool:_rewrite=false)
{
	if(!newpath[0]) return -1;
	new oldfilename[MAX_FILE_NAME_LEN];
	if(strlen(oldpath) == 0) strmid(oldfilename,___file[__path],0,strlen(___file[__path]),255);
	else strmid(oldfilename,oldpath,0,strlen(oldpath),255);
	if(!oldpath[0]) return -4;
	if(!nfile_Exists(oldfilename))
	{
	    #if defined __nfile__debug_error
	        format(nfile_string,sizeof(nfile_string),"nfile_Copy.ERROR: File \"%s\" does not exist.",oldpath);
	        debug_Log(nfile_string);
	    #endif
		return -2;
	}
	if(nfile_Exists(newpath))
	{
	    if(!_rewrite)
	    {
		    #if defined __nfile__debug_error
		        format(nfile_string,sizeof(nfile_string),"nfile_Copy.ERROR: File \"%s\" does already exist.",newpath);
		        debug_Log(nfile_string);
		    #endif
			return -3;
		}
		nfile_Delete(newpath);
	}
	nfile_Create(newpath,false);
	___file[__file] = fopen(oldfilename,io_read);
	new line[(2*MAX_GET)+3],
		File:newfile = fopen(newpath,io_write);
 	while(fread(___file[__file],line,sizeof(line))) fwrite(newfile,line);
	fclose(___file[__file]);
 	fclose(newfile);
    #if defined __nfile__debug_info
        format(nfile_string,sizeof(nfile_string),"nfile_Copy.INFO: File \"%s\" has been copied to \"%s\".",oldfilename,newpath);
        debug_Log(nfile_string);
    #endif
	return 1;
}

stock nfile_SetFloat(key[],Float:value,path[]="",delim[]=STANDART_DELIM)
{
	if(!key[0]) return 0;
	new floatvalue[MAX_GET];
	format(floatvalue,sizeof(floatvalue),"%f",value);
	return nfile_SetValue(key,floatvalue,path,delim);
}

stock nfile_SetInt(key[],value,path[]="",delim[]=STANDART_DELIM)
{
	if(!key[0]) return 0;
	new intvalue[MAX_GET];
	format(intvalue,sizeof(intvalue),"%d",value);
	return nfile_SetValue(key,intvalue,path,delim);
}

stock nfile_SetBool(key[],bool:value,path[]="",delim[]=STANDART_DELIM)
{
	if(!key[0]) return 0;
	return nfile_SetValue(key,value?("true"):("false"),path,delim);
}

stock nfile_SetValue(key[],value[],path[]="",delim[]=STANDART_DELIM,bool:_addkey=true)
{
	if(!key[0]) return -1;
	new tmpfilename[MAX_FILE_NAME_LEN],
		filename[MAX_FILE_NAME_LEN];
	if(strlen(path) == 0) strmid(filename,___file[__path],0,strlen(___file[__path]),255);
	else strmid(filename,path,0,strlen(path),255);
	if(!filename[0]) return -2;
	format(tmpfilename,sizeof(tmpfilename),"%s/%s",__tmp_nfile_cache,misc_GetFilenameFromPath(filename));

	if(!nfile_Exists(filename))
	{
	    #if defined __nfile__debug_info
	        format(nfile_string,sizeof(nfile_string),"nfile_SetValue.ERROR: File \"%s\" does not exist.",filename);
	        debug_Log(nfile_string);
	    #endif
	    return 0;
	}

	escape_string(key)
	escape_string(value)
	
	nfile_Copy(tmpfilename,filename,true);
	nfile_Delete(filename);
	nfile_Create(filename,false);

	___file[__file] = fopen(tmpfilename,io_read);
	new line[(2*MAX_GET)+3],
		File:newfile = fopen(filename,io_write),
		match_found = false;

	while(fread(___file[__file],line,sizeof(line)))
	{
	    if(!match_found && misc_nfile_CheckKey(line,key,delim) == true)
	    {
	        match_found = true;
			format(nfile_string,sizeof(nfile_string),"%s%s%s\r\n",key,delim,value);
			fwrite(newfile,nfile_string);
			#if defined __nfile__debug_info
				format(nfile_string,sizeof(nfile_string),"nfile_SetValue.INFO: Value (file:\"%s\") set.",filename);
				debug_Log(nfile_string);
			#endif
	        continue;
	    }
		fwrite(newfile,line);
	}
	fclose(___file[__file]);
 	fclose(newfile);

	nfile_Delete(tmpfilename);
	nfile_Switch(filename);
	
	if(!match_found)
	{
		if(_addkey && nfile_AddKey(key,value) == 1)
		{
			#if defined __nfile__debug_info
				format(nfile_string,sizeof(nfile_string),"nfile_SetValue.INFO: Value (file:\"%s\") added.",filename);
				debug_Log(nfile_string);
			#endif
		}
		else
		{
			#if defined __nfile__debug_error
				format(nfile_string,sizeof(nfile_string),"nfile_SetValue.ERROR: Value (file:\"%s\") could not be added/set.",filename);
				debug_Log(nfile_string);
			#endif
		}	
	}
	return 1;
}

stock nfile_RemoveKey(key[],path[]="",delim[]=STANDART_DELIM)
{
	if(!key[0]) return -1;
	new tmpfilename[MAX_FILE_NAME_LEN],
		filename[MAX_FILE_NAME_LEN];
	if(strlen(path) == 0) strmid(filename,___file[__path],0,strlen(___file[__path]),255);
	else strmid(filename,path,0,strlen(path),255);
	if(!filename[0]) return -2;
	format(tmpfilename,sizeof(tmpfilename),"%s/%s",__tmp_nfile_cache,misc_GetFilenameFromPath(filename));

	if(!nfile_Exists(filename))
	{
	    #if defined __nfile__debug_info
	        format(nfile_string,sizeof(nfile_string),"nfile_RemoveKey.ERROR: File \"%s\" does not exist.",filename);
	        debug_Log(nfile_string);
	    #endif
	    return 0;
	}
	
	escape_string(key)
	
	nfile_Copy(tmpfilename,filename,true);
	nfile_Delete(filename);
	nfile_Create(filename,false);

	___file[__file] = fopen(tmpfilename,io_read);
	new line[(2*MAX_GET)+3)],
		File:newfile = fopen(filename,io_write),
		match_found = false;

	while(fread(___file[__file],line,sizeof(line)))
	{
	    if(!match_found && misc_nfile_CheckKey(line,key,delim) == true)
	    {
	        match_found = true;
	        continue;
	    }
		fwrite(newfile,line);
	}
	fclose(___file[__file]);
 	fclose(newfile);
	if(!match_found)
	{
	    #if defined __nfile__debug_info
	        format(nfile_string,sizeof(nfile_string),"nfile_RemoveKey.ERROR: Key \"%s\" does not exist.",key);
	        debug_Log(nfile_string);
	    #endif	
		return -3;
	}

	nfile_Delete(tmpfilename);
 	nfile_Switch(filename);
    #if defined __nfile__debug_info
        format(nfile_string,sizeof(nfile_string),"nfile_RemoveKey.INFO: Key \"%s\" (file:\"%s\") removed.",key,filename);
        debug_Log(nfile_string);
    #endif
	return 1;
}

stock nfile_Reset(path[]="")
{
	new filename[MAX_FILE_NAME_LEN];
	if(strlen(path) == 0) strmid(filename,___file[__path],0,strlen(___file[__path]),255);
	else strmid(filename,path,0,strlen(path),255);
	if(!filename[0]) return -1;
	if(!nfile_Exists(filename))
	{
	    #if defined __nfile__debug_info
	        format(nfile_string,sizeof(nfile_string),"nfile_Reset.Error: File \"%s\" does not exist.",filename);
	        debug_Log(nfile_string);
	    #endif
	    return 0;
	}
	nfile_Delete(filename);
	nfile_Create(filename);
    #if defined __nfile__debug_info
        format(nfile_string,sizeof(nfile_string),"nfile_Reset.INFO: File \"%s\" reset.",filename);
        debug_Log(nfile_string);
    #endif
	return 1;
}

stock nfile_Append(insert[],path[]="",bool:_create=true)
{
	new filename[MAX_FILE_NAME_LEN];
	if(strlen(path) == 0) strmid(filename,___file[__path],0,strlen(___file[__path]),255);
	else strmid(filename,path,0,strlen(path),255);
	if(!filename[0]) return -1;
	if(!nfile_Exists(filename))
	{
		if(!_create)
		{
			#if defined __nfile__debug_info
				format(nfile_string,sizeof(nfile_string),"nfile_Append.Error: File \"%s\" does not exist.",filename);
				debug_Log(nfile_string);
			#endif
			return 0;
		}
		nfile_Create(filename);
	}
	___file[__file] = fopen(filename,io_append);
	fwrite(___file[__file],insert);
	fclose(___file[__file]);
    #if defined __nfile__debug_info
        format(nfile_string,sizeof(nfile_string),"nfile_Append.INFO: Appended \"%s\" on file \"%s\".",insert,filename);
        debug_Log(nfile_string);
    #endif
	return 1;
}

stock nfile_AddKey(key[],value[]="",path[]="",delim[]=STANDART_DELIM)
{
	if(!key[0]) return -1;
	new filename[MAX_FILE_NAME_LEN];
	if(strlen(path) == 0) strmid(filename,___file[__path],0,strlen(___file[__path]),255);
	else strmid(filename,path,0,strlen(path),255);
	if(!filename[0]) return -2;

	if(!nfile_Exists(filename))
	{
	    #if defined __nfile__debug_info
	        format(nfile_string,sizeof(nfile_string),"nfile_AddKey.ERROR: File \"%s\" does not exist.",filename);
	        debug_Log(nfile_string);
	    #endif
	    return 0;
	}
	
	escape_string(key)
	escape_string(value)
	
	new line[(2*MAX_GET)+3],
		match_found = false;

    ___file[__file] = fopen(filename,io_read);
	while(fread(___file[__file],line,sizeof(line)))
	{
	    if(!match_found && misc_nfile_CheckKey(line,key,delim) == true)
	    {
	        match_found = true;
	        continue;
	    }
	}
    fclose(___file[__file]);
    
	if(match_found)
	{
	    #if defined __nfile__debug_error
	        format(nfile_string,sizeof(nfile_string),"nfile_AddKey.ERROR: Key \"%s\" (file:\"%s\") already exists.",key,filename);
	        debug_Log(nfile_string);
	    #endif
	    return 2;
	}

	___file[__file] = fopen(filename,io_append);
	format(nfile_string,sizeof(nfile_string),"%s%s%s\r\n",key,delim,value);
	fwrite(___file[__file],nfile_string);
	fclose(___file[__file]);
	
	#if defined __nfile__debug_info
	    format(nfile_string,sizeof(nfile_string),"nfile_AddKey.INFO: Key \"%s\" (file:\"%s\") added.",key,filename);
	    debug_Log(nfile_string);
	#endif
	return 1;
}

#if defined __nfile__debug_info || defined __nfile__debug_error
stock debug_Log(insert_log[])
{
    new year,
		month,
		day,
		hour,
		minute,
		second,
		log_path[MAX_PATH_LEN+1+4+1+2+1+2+1+3+1];//"PATH / yyyy - mm - dd . txt" +1
    getdate(year,month,day);
	format(log_path,sizeof(log_path),"%s/%d-%d-%d.txt",__debug__logfile,year,month,day);
	new File:log_file = fopen(log_path,io_append);
	if(log_file)
	{
	    gettime(hour,minute,second);
		#if defined __nfile__debug_console
            printf("[%02d:%02d-%02d] (%s)",hour,minute,second,insert_log);
		#endif
	    format(nfile_string,sizeof(nfile_string),"[%02d:%02d-%02d] (%s)\r\n",hour,minute,second,insert_log);
	    fwrite(log_file,nfile_string);
	    fclose(log_file);
	    return 1;
	}
	return 0;
}
#endif