/*
 * Brutus implementation file for an ORB initiation helper function.
 * 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 <brutus_utils/brutus_macros.h>
#include <stdio.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.
 */
static 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;
}


static char *build_init_ref_opt(const unsigned char ssl,
				const char *init_ref,
				const char *obj_key,
				const char *server_host,
				const uint16_t server_port)
{
	char *init_ref_opt = strdup("--ORBInitRef=");
	char server_port_str[6] = { '\0' };
	
	init_ref_opt = append_string(&init_ref_opt, init_ref);
	if (!init_ref_opt) 
		goto out;

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

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

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

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

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

out:
	return init_ref_opt;
}

/*
 * 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 create_orbit_orb(int argc,
			   char **argv,
			   const unsigned char 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,
			   CORBA_Environment *ev)
{
	// sanity checks
	if (!argc)
		return CORBA_OBJECT_NIL;
	if (!*argv)
		return CORBA_OBJECT_NIL;
	if (!logon_init_ref)
		return CORBA_OBJECT_NIL;
	if (!logon_obj_server_key)
		return CORBA_OBJECT_NIL;
	if (!server_host_name)
		return CORBA_OBJECT_NIL;
	if (!server_port)
		return CORBA_OBJECT_NIL;
	if (!orb_name)
		return CORBA_OBJECT_NIL;
	
	CORBA_ORB orb = CORBA_OBJECT_NIL;
	int init_argc = argc + 6;
	char **init_argv = (char**)malloc(sizeof(char*) * (init_argc));
	if (!init_argv)
		return CORBA_OBJECT_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_ref_logon_arg = build_init_ref_opt(ssl,
						logon_init_ref,
						logon_obj_server_key,
						server_host_name,
						server_port);
	if (!init_ref_logon_arg) 
		goto out;
	init_argv[argc] = init_ref_logon_arg;

	// IPv4 - needed to interoperate with TAO
	init_argv[argc+1] = "--ORBIIOPIPv4=1";

	// IPv6 - could be needed to interoperate with TAO
	init_argv[argc+2] = "--ORBIIOPIPv6=0";

	// Explicitly force ORBit2 to be non-local
	init_argv[argc+3] = "--ORBLocalOnly=0";

	// Force ORBit2 to use the IP address in the all generated IORs
//	init_argv[argc+4] = "--ORBNetID=ipaddr";
	init_argv[argc+4] = "--ORBNetID=localhost";

	// Set a 30 second timeout limit for GIOP operations
	init_argv[argc+5] = "--GIOPTimeoutMSEC=30000"; /* 30 seconds */

//	init_argv[argc+6] = "--ORBIIOPIPName=192.168.0.133";

	// initialize the ORB
        orb = CORBA_ORB_init(&init_argc, init_argv, (char*)orb_name, ev);
	if (ORBIT2_EX(ev)) {
		ORBIT2_PRINT_EX("CORBA_ORB_init() : ", ev);
		orb = CORBA_OBJECT_NIL;
	}

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

	return orb;
}
