/*

CLASS {NATIVE_Configuration|_CSharp}, NATIVE:

*/
#ifdef SEPARATE_UNITS
    #include "NATIVE_Configuration.h"
#endif

std::vector<AL4_configuration*> AL4_configuration::All_configs;

int AL4_configuration::Create_new_configure(int Area, std::string Path,
    std::string Name, bool Write, bool Create)
{
    int i = -1;
    int siz = (int)AL4_configuration::All_configs.size();
    for (int j = 0; j < siz; j++)
        if (AL4_configuration::All_configs[j] == nullptr)
        {
            i = j;
            break;
        }
    if (i < 0)
    {
        i = AL4_configuration::All_configs.size();
        AL4_configuration::All_configs.push_back(nullptr);
    }
    AL4_configuration::All_configs[i] = 
        new AL4_configuration(Area, Path, Name, Write, Create);
    return i;
}

void AL4_configuration::Release_configure(int Handle)
{
    if ((int)AL4_configuration::All_configs.size() > Handle && Handle >= 0)
    {
        AL4_configuration* to_release = All_configs[(unsigned int)Handle];
        AL4_configuration::All_configs[(unsigned int)Handle] = nullptr;
        delete to_release;
    }
    for (int i = (int)AL4_configuration::All_configs.size()-1; i >= 0; i--)
        if (AL4_configuration::All_configs[(unsigned int)i] == nullptr)
            AL4_configuration::All_configs.erase(
                AL4_configuration::All_configs.begin()+i);
        else break;
}

AL4_configuration::AL4_configuration(int Area, std::string Path,
    std::string Name, bool Write, bool Create)
{
    AppName = Name;
    KeyName = Path;
    Read_only = !Write;
    Can_create = Create;
    Area_config = Area;
}

#ifdef MSWINDOWS
HKEY AL4_configuration::create_key()
#else
int AL4_configuration::create_key()
#endif
{
	if (AppName == "") return 0;
    try
    {
        #ifdef MSWINDOWS
    		HKEY RESULT = 0;
        	HKEY k = HKEY_CURRENT_USER;
        	if (Area_config == 1) k = HKEY_LOCAL_MACHINE;
        	std::string sub_key = "Software\\" + AppName;
        	if (KeyName != "")
        	{
        		if (sub_key != "" && sub_key[sub_key.length()-1] != '\\')
        			sub_key = sub_key + "\\";
        		sub_key = sub_key + KeyName;
        	}
        	
        	int ok = 0;
        	if (Read_only || !Can_create)
        	{
        		ok = RegOpenKeyExA(k, &sub_key[0], 0, KEY_QUERY_VALUE | KEY_READ,
        			&RESULT);
        	}
        	else
        	{
        		DWORD disp;
        		ok = RegCreateKeyExA(k, &sub_key[0], 0, 
        			NULL, REG_OPTION_NON_VOLATILE,
        			  KEY_CREATE_SUB_KEY
        			| KEY_ENUMERATE_SUB_KEYS
        			| KEY_EXECUTE
        			| KEY_QUERY_VALUE
        			| KEY_SET_VALUE, NULL, &RESULT, &disp); 
        	}
        	if (ok != ERROR_SUCCESS) return 0;
    		return RESULT;
        #else
        	//not implemented for linux
        #endif
    }
    catch (std::exception& E)
    {
        
    }
    return 0;
}

#ifdef MSWINDOWS
void AL4_configuration::close_key(HKEY k)
{
	RegCloseKey(k);	
}
#else
void AL4_configuration::close_key(int k)
{
	//not implemented for Linux	
}
#endif

std::string AL4_configuration::Value_string(int Handle, 
    std::string Name_value, std::string New_value, bool Set_new)
{
	if (Name_value == "") return "";
    AL4_configuration* config = All_configs[Handle];
    std::string RESULT = "";
    #ifdef MSWINDOWS
    	HKEY k = config->create_key();
    	DWORD size;
    	DWORD type;
    	bool ok = ERROR_SUCCESS == RegQueryValueExA(
    		k, &Name_value[0], NULL, &type, NULL, &size);
    	if (ok && type == REG_SZ)
    	{
	    	char *buffer = (char*)malloc(size+1);
	    	ok = ERROR_SUCCESS == RegQueryValueExA(
	    		k, &Name_value[0], NULL, &type, (LPBYTE)buffer, &size);
	    	RESULT = buffer;
	    	free(buffer);
    	}
	    if (Set_new && !config->Read_only)
	    {
	    	RegSetValueExA(k, &Name_value[0], 0, REG_SZ, (byte *)&New_value[0],
	    		New_value.length());
	    }
    	close_key(k);
    #else
    	//not implemented for linux
    #endif

    return RESULT;
}

int AL4_configuration::Value_integer(int Handle, 
    std::string Name_value, int New_value, bool Set_new)
{
	if (Name_value == "") return 0;
    AL4_configuration* config = All_configs[Handle];
    int RESULT = 0;
    #ifdef MSWINDOWS
    	HKEY k = config->create_key();
    	DWORD size;
    	DWORD type;
    	bool ok = ERROR_SUCCESS == RegQueryValueExA(
    		k, &Name_value[0], NULL, &type, NULL, &size);
    	if (ok && type == REG_DWORD)
    	{
	    	ok = ERROR_SUCCESS == RegQueryValueExA(
	    		k, &Name_value[0], NULL, &type, (LPBYTE)&RESULT, &size);
    	}
	    if (Set_new && !config->Read_only)
	    {
	    	RegSetValueExA(k, &Name_value[0], 0, REG_DWORD, (LPBYTE)&New_value,
	    		sizeof(DWORD));
	    }
    	close_key(k);
    #else
    	//not implemented for linux
    #endif
    return RESULT;
}

bool AL4_configuration::Value_boolean(int Handle, 
    std::string Name_value, bool New_value, bool Set_new)
{
	if (Name_value == "") return false;
    AL4_configuration* config = All_configs[Handle];
    int value = 0;
    bool RESULT = false;
    #ifdef MSWINDOWS
    	HKEY k = config->create_key();
    	DWORD size;
    	DWORD type;
    	bool ok = ERROR_SUCCESS == RegQueryValueExA(
    		k, &Name_value[0], NULL, &type, NULL, &size);
    	if (ok && type == REG_DWORD)
    	{
	    	ok = ERROR_SUCCESS == RegQueryValueExA(
	    		k, &Name_value[0], NULL, &type, (LPBYTE)&value, &size);
	    	RESULT = value != 0;
    	}
	    if (Set_new && !config->Read_only)
	    {
	    	value = New_value ? 1 : 0;
	    	RegSetValueExA(k, &Name_value[0], 0, REG_DWORD, (LPBYTE)&value,
	    		sizeof(DWORD));
	    }
    	close_key(k);
    #else
    	//not implemented for linux
    #endif
    return RESULT;
}

std::string AL4_configuration::Binary_get(int Handle, std::string Name_value)
{
	if (Name_value == "") return "";
    AL4_configuration* config = All_configs[Handle];
    std::string Result = "\0(not implemented)";
    #ifdef MSWINDOWS
    	HKEY k = config->create_key();
    	
    	close_key(k);
    #else
    	//not implemented for linux
    #endif
    return Result;
}

bool AL4_configuration::Value_present(int Handle, 
    std::string Name_value)
{
	if (Name_value == "") return false;
    AL4_configuration* config = All_configs[Handle];
    bool ok = false;
    #ifdef MSWINDOWS
    	HKEY k = config->create_key();
    	DWORD size;
    	DWORD type;
    	ok = ERROR_SUCCESS == RegQueryValueExA(
    		k, &Name_value[0], NULL, &type, NULL, &size);
    	close_key(k);
    #else
    	//not implemented for linux
    #endif
    return ok;
}

void AL4_configuration::Value_delete(int Handle, 
    std::string Name_value)
{
    AL4_configuration* config = All_configs[Handle];
    #ifdef MSWINDOWS
    	HKEY k = config->create_key();
    	RegDeleteValueA(k, &Name_value[0]);
    	close_key(k);
    #else
    	//not implemented for linux
    #endif
}

void AL4_configuration::Subkey_delete(int Handle, 
    std::string Name_subkey)
{
    AL4_configuration* config = All_configs[Handle];
    #ifdef MSWINDOWS
    	HKEY k = config->create_key();
    	RegDeleteKeyA(k, &Name_subkey[0]);
    	close_key(k);
    #else
    	//not implemented for linux
    #endif
}

void AL4_configuration::Values_list(int Handle, ArrayStr* List)
{
    List->Clear();
    AL4_configuration* config = All_configs[Handle];
    #ifdef MSWINDOWS
    	HKEY k = config->create_key();
    	DWORD size;
    	char buffer[256];
    	for (int i = 0; ; i++)
    	{
    		DWORD type;
    		DWORD data_size;
    		size = 255;
    		bool ok = ERROR_SUCCESS == RegEnumValueA(k, i, buffer, &size, NULL,
    			&type, NULL, &data_size);
    		if (ok)
    			List->Add(buffer);
    		else break;
    	}
    	close_key(k);
    #else
    	//not implemented for linux
    #endif
}

void AL4_configuration::Subkeys_list(int Handle, ArrayStr* List)
{
    List->Clear();
    AL4_configuration* config = All_configs[Handle];
    #ifdef MSWINDOWS
    	HKEY k = config->create_key();
    	char buffer[256];
    	for (int i = 0; ; i++)
    	{
    		DWORD type;
    		DWORD data_size;
    		DWORD size = 255;
    		bool ok = ERROR_SUCCESS == RegEnumKeyExA(k, i, buffer, &size, NULL,
    			NULL, NULL, NULL);
    		if (ok)
    			List->Add(buffer);
    		else break;
    	}
    	close_key(k);
    #else
    	//not implemented for linux
    #endif
}

/*
    
CONST STR:
    NATIVE_configure_import = ""

    NATIVE_new_configure_object = @
    "   RESULT = AL4_configuration::Create_new_configure("
    "       X_Area, X_Path, X_Name, !X_Read, X_Can_create);"
    
    NATIVE_release_configure_object = @
    "   AL4_configuration::Release_configure(X_Handle);"
    
    NATIVE_value_string = @
    "   RESULT = AL4_configuration::Value_string("
    "       X_Handle, X_Name, X_New, X_Set);"
    
    NATIVE_value_integer = @
    "   RESULT = AL4_configuration::Value_integer("
    "       X_Handle, X_Name, X_New, X_Set);"
    
    NATIVE_value_boolean = @
    "   RESULT = AL4_configuration::Value_boolean("
    "       X_Handle, X_Name, X_New, X_Set);"
    
    NATIVE_binary_get = @
    "   RESULT = AL4_configuration::Binary_get(X_Handle, X_Name);"
    
    NATIVE_present_value = @
    "   RESULT = AL4_configuration::Value_present("
    "       X_Handle, X_Name);"
    
    NATIVE_list_values = @
    "   AL4_configuration::Values_list(X_Handle, X_List);"
    
    NATIVE_list_subkeys = @
    "   AL4_configuration::Subkeys_list(X_Handle, X_List);"
    
    NATIVE_delete_value = @
    "   AL4_configuration::Value_delete(X_Handle, X_Name);"
    
    NATIVE_delete_subkey = @
    "   AL4_configuration::Subkey_delete(X_Handle, X_Name);"

    .
        

END
*/

