/*
 * Brutus implementation file for an ORB initiation helper class.
 * Copyright (C) 2004-2007 OMC Denmark ApS.
 * 
 * This program is free software: 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 program 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/>.
 */


#include "init_orb.h"
#include <string.h>
#include <stdlib.h>


/*
 * Will realloc and strcat src to *dest, freeing *dest if 
 * not successfull. Returns a pointer to the longer string.
 */
char *append_string(char **dest, const char *src)
{
	char *retv;
	size_t size;


	if (!*dest) {
		size = sizeof(char) * (strlen(src) + 1);
		retv = (char*)calloc(size, sizeof(char));
	} else {
		size = sizeof(char) * (strlen(*dest) + strlen(src) + 1);
		retv = (char*)realloc((void*)*dest, size);
	}
	if (!retv) {
		free(*dest);
		return NULL;
	}

	strcat(retv, src);
	*dest = retv;

	return *dest;
}

char *build_init_ref_arg(const bool use_ssl,
			 const char *init_ref,
			 const char *obj_key,
			 const char *server_host,
			 const uint16_t server_port)
{
	char *init_ref_arg = NULL;
	char server_port_str[6] = { '\0' };
	
	init_ref_arg = append_string(&init_ref_arg, init_ref);
	if (!init_ref_arg) 
		goto out;

	init_ref_arg = append_string(&init_ref_arg, use_ssl ? "=corbaloc:ssliop:" : "=corbaloc:iiop:");
	if (!init_ref_arg) 
		goto out;

	init_ref_arg = append_string(&init_ref_arg, server_host);
	if (!init_ref_arg) 
		goto out;

	init_ref_arg = append_string(&init_ref_arg, ":");
	if (!init_ref_arg) 
		goto out;

	snprintf(server_port_str, 6, "%hu", server_port);
	init_ref_arg = append_string(&init_ref_arg, server_port_str);
	if (!init_ref_arg) 
		goto out;

	init_ref_arg = append_string(&init_ref_arg, "/");
	if (!init_ref_arg) 
		goto out;
	
	init_ref_arg = append_string(&init_ref_arg, obj_key);
	if (!init_ref_arg) 
		goto out;

out:
	return init_ref_arg;
}


/*
 * This method will return an ORB which is so initialized 
 * that the remote Brutus Logon object can be resolved 
 * with resolve_initial_references().
 *
 * argc and argv are command line arguments with other
 * options that must be given to the ORB in ORB_init().
 *
 * argc                  : ORB command line argument count
 *
 * argv                  : ORB command line arguments
 *
 * logon_init_ref        : String to pass to resolve_initial_references() for BrutusLogOn::
 *
 * logon_obj_server_key  : Object key given to BrutusLogOn:: object at the server
 *
 * server_host_name      : Hostname or IP address of remote Brutus server
 *
 * server_port           : Port number where the remote Brutus Logon object is exposed
 *
 * orb_name              : Name of return ORB or empty string
 *
 * Return value          : Initialized ORB or CORBA::ORB::_nil()
 *
 */
CORBA::ORB_ptr Init_ORB::create(int argc,
				char **argv,
				const bool use_ssl,
				const char *logon_init_ref, 
				const char *logon_obj_server_key, 
				const char *server_host_name, 
				const uint16_t server_port,
				const char *orb_name)
{
	// sanity checks
	if (!argc)
		return CORBA::ORB::_nil();
	if (!*argv)
		return CORBA::ORB::_nil();
	if (!logon_init_ref)
		return CORBA::ORB::_nil();
	if (!logon_obj_server_key)
		return CORBA::ORB::_nil();
	if (!server_host_name)
		return CORBA::ORB::_nil();
	if (!server_port)
		return CORBA::ORB::_nil();
	if (!orb_name)
		return CORBA::ORB::_nil();
	
	CORBA::ORB_var orb = CORBA::ORB::_nil();
	int init_argc = argc + 4;
	char **init_argv = (char**)malloc(sizeof(char*) * (init_argc));
	if (!init_argv)
		return CORBA::ORB::_nil();
	memset((void*)init_argv, 0, init_argc);


	// copy the original arguments
	memcpy((void*)init_argv, (void*)argv, sizeof(char*) * (argc));

	// init refs
	char *init_ref_logon_arg = NULL;

	// BrutusLogOn
	init_argv[argc] = "-ORBInitRef";
	init_ref_logon_arg = build_init_ref_arg(use_ssl,
						logon_init_ref,
						logon_obj_server_key,
						server_host_name,
						server_port);
	if (!init_ref_logon_arg) 
		goto out;
	init_argv[argc+1] = init_ref_logon_arg;

	init_argv[argc+2] = "-ORBDottedDecimalAddresses";
	init_argv[argc+3] = "1";

	// initialize the ORB
        orb = CORBA::ORB_init(init_argc, init_argv, orb_name);

out:
	free(init_ref_logon_arg);
	free(init_argv);

	return orb._retn();
}
