// **********************************************************************
//
// Copyright (c) 1999
// Object Oriented Concepts, Inc.
// Billerica, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#include <OB/CORBA.h>
#include <OB/Properties.h>

//
// Create a registry key, and all subkeys leading to this key.
//
HKEY
createKey(HKEY base, const char* key)
{
    char path[MAX_PATH];
    strcpy(path, key);
    char* p = path;
    const char* end = p + strlen(path);
    for(;;)
    {
	while(*p && *p != '\\')
	    ++p;

	//
	// Failure - badly formatted key.
	//
	if(*p == '\0')
	{
	    cerr << "createKey: expected \\ \"" << key << "\"" << endl;
	    return 0;
	}

	*p = '\0';

	//
	// Try to open this key.
	//
	HKEY key;
	DWORD rc = RegOpenKeyEx(base, path, 0, KEY_WRITE|KEY_EXECUTE, &key);
	if(rc != ERROR_SUCCESS)
	{
	    rc = RegCreateKey(base, path, &key);
	    if(rc != ERROR_SUCCESS)
	    {
		cerr << "RegCreateKey \"" << path << "\" failed: "
		     << rc << endl;
		return 0;
	    }
	}
	*p = '\\';
	++p;
	//
	// Have we opened the full key?
        //
	if(p == end)
	    return key;
	RegCloseKey(key);
    }
}

//
// Add the key and value to the registry.
//
bool
addRegistryKey(HKEY base, const char* basePath, const char* k, const char* v)
{
    char path[MAX_PATH];
    char valueName[MAX_PATH];

    valueName[0] = '\0';
    strcpy(path, basePath);

    //
    // Ensure that the path ends with '\'
    //
    if(path[strlen(path)-1] != '\\')
	strcat(path, "\\");

    char keyname[MAX_PATH];
    strcpy(keyname, k);

    char* start = keyname;
    char* p = start;

    //
    // Take each dotted section of the name. The last dotted section
    // is the value name, and the other section names are the keys,
    // and sub-keys.
    //
    while(p != 0)
    {
	p = strchr(start, '.');
	if(p != 0)
	{
	    *p = '\0';
	}
	if(*valueName != '\0')
	{
	    strcat(path, valueName);
	    strcat(path, "\\");
	}
	strcpy(valueName, start);
	if(p != 0)
	{
	    start = p + 1;
	    p = start;
	}
    }
    
    //
    // Try to open the key.
    //
    HKEY key;
    DWORD rc = RegOpenKeyEx(base, path, 0, KEY_WRITE|KEY_EXECUTE, &key);
    if(rc != ERROR_SUCCESS)
    {
	//
	// If open fails, then create the key.
	//
	key = createKey(base, path);

	//
	// If that fails then we can't add the value.
	//
	if(key == 0)
	    return false;
    }

    rc = RegSetValueEx(key, valueName, 0, REG_SZ, (BYTE*)v, strlen(v));
    if(rc != ERROR_SUCCESS)
    {
	cerr << "RegSetValueEx failed: " << rc << endl;
    }
    RegCloseKey(key);

    return true;
}

//
// Clean each of the values from the registry under the OOC\\Properties
// tree.
//
void
cleanRegistry(HKEY base, const char* path, bool deleteThis)
{
    HKEY key;
    DWORD rc = RegOpenKeyEx(base, path, 0,
			 KEY_ENUMERATE_SUB_KEYS|KEY_EXECUTE|KEY_QUERY_VALUE,
			 &key);
    if(rc != ERROR_SUCCESS)
	return;

    //
    // Get all sub-keys, and add to a string list. Next run through
    // each sub-key, and clean all the contained entries.
    //
    char name[MAX_PATH];
    OBStrSeq trash;
    int i;
    for(i = 0, rc = ERROR_SUCCESS; rc == ERROR_SUCCESS; i++)
    {
	rc = RegEnumKey(key, i, name, MAX_PATH);
	if(rc == ERROR_SUCCESS)
	{
	    char buf[MAX_PATH];
	    strcpy(buf, path);
	    strcat(buf, "\\");
	    strcat(buf, name);
	    trash.append(CORBA_string_dup(buf));
	}
    }
    for(CORBA_ULong j = 0; j < trash.length(); ++j)
	cleanRegistry(base, trash[j], true);

    RegCloseKey(key);

    //
    // Delete all values in this key.
    //
    if(deleteThis)
    {
	rc = RegDeleteKey(base, path);
	if(rc != ERROR_SUCCESS)
	    cerr << "RegDeleteKey failed: " << rc << endl;
    }
}

void
usage(const char* progName)
{
    cerr << "Usage: " << progName
	 << " [-ORBconfig file] HKEY_CURRENT_USER|KEY_LOCAL_MACHINE"
	 << endl;
}
int
main(int argc, char** argv)
{
    int status = 0;
    try
    {
	OBProperties* properties = OBProperties::init(argc, argv, false);

	if(argc != 2)
	{
	    usage(argv[0]);
	    return 1;
	}
	HKEY base;
	if(strcmp(argv[1], "HKEY_CURRENT_USER") == 0)
	    base = HKEY_CURRENT_USER;
	else if(strcmp(argv[1], "HKEY_LOCAL_MACHINE") == 0)
	    base = HKEY_LOCAL_MACHINE;
	else
	{
	    usage(argv[0]);
	    return 1;
	}

	const char* basePath = "Software\\OOC\\Properties";

	//
	// Clean all registry keys under
	//
	cleanRegistry(base, basePath, false);

	//
	// Get all registry keys.
	//
	OBProperties::KeySeq keys = properties -> getKeys("");
	for(CORBA_ULong i = 0; i < keys.length(); ++i)
	    if(!addRegistryKey(base, basePath, keys[i],
			       properties -> getProperty(keys[i])))
	    {
		cerr << "Add of " << keys[i] << " failed. Bailing." << endl;
		status = 1;
		break;
	    }
    }
    catch(const CORBA_INITIALIZE&)
    {
	status = 1;
    }
    return status;
}
