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

#include <OB/CORBA.h>
#include <OB/OCI_IIOP.h>
#include <OB/Util.h>

#include <Hello.h>

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#ifdef HAVE_FSTREAM
#   include <fstream>
#else
#   include <fstream.h>
#endif

class CloseCB_impl : public OCI_CloseCB
{
public:

    virtual void close_cb(OCI_TransportInfo_ptr transport_info)
    {
        OCI_IIOP_TransportInfo_var iiopInfo =
	    OCI_IIOP_TransportInfo::_narrow(transport_info);

	if(!CORBA_is_nil(iiopInfo))
	{
	    OCI_IIOP_InetAddr_var remoteAddr = iiopInfo -> remote_addr();
	    CORBA_UShort remotePort = iiopInfo -> remote_port();
	    
	    cout << "Closing connection to: "
		 << (int)remoteAddr[0] << '.' << (int)remoteAddr[1] << '.'
		 << (int)remoteAddr[2] << '.' << (int)remoteAddr[3]
		 << ":" << remotePort << endl;
	}
    }
};

class ConnectCB_impl : public OCI_ConnectCB
{
public:

    virtual void connect_cb(OCI_TransportInfo_ptr transport_info)
    {
        OCI_IIOP_TransportInfo_var iiopInfo =
	    OCI_IIOP_TransportInfo::_narrow(transport_info);

	if(!CORBA_is_nil(iiopInfo))
	{
	    OCI_IIOP_InetAddr_var remoteAddr = iiopInfo -> remote_addr();
	    CORBA_UShort remotePort = iiopInfo -> remote_port();
        
	    cout << "Connection to: "
		 << (int)remoteAddr[0] << '.' << (int)remoteAddr[1] << '.'
		 << (int)remoteAddr[2] << '.' << (int)remoteAddr[3]
		 << ":" << remotePort << endl;

	    char c;
	    do
	    {
		cout << "Refuse connection (y/n)? ";
		cin >> c;
	    }
	    while(c != 'y' && c != 'n');

	    if(c == 'y')
		throw CORBA_NO_PERMISSION();

	    //
	    // Add the close callback object
	    //
	    OCI_CloseCB_var closeCB = new CloseCB_impl;
	    iiopInfo -> add_close_cb(closeCB);
	}
    }
};

int
main(int argc, char* argv[], char*[])
{
    try
    {
	//
	// Create ORB
	//
	CORBA_ORB_var orb = CORBA_ORB_init(argc, argv);

        //
        // Add the connect callback object to the ConFactory for the
        // IIOP OCI Plug-In.
        //
	OCI_ConFactoryRegistry_var registry =
	    orb -> get_con_factory_registry();
        OCI_ConFactorySeq_var factories = registry -> get_factories();

        for(CORBA_ULong i = 0; i < factories -> length(); ++i)
        {
	    OCI_ConFactoryInfo_var info = factories[i] -> get_info();
            OCI_IIOP_ConFactoryInfo_var iiopInfo =
		OCI_IIOP_ConFactoryInfo::_narrow(info);

            if(!CORBA_is_nil(iiopInfo))
            {
                //
                // Add the connect callback object
                //
                OCI_ConnectCB_var connectorCB = new ConnectCB_impl;
                info -> add_connect_cb(connectorCB);
            }
        }

	//
	// Get "hello" object
	//
	const char* refFile = "Hello.ref";
	ifstream in; // Must use open(name), not ifstream in(name) (VC++ bug)
	in.open(refFile);
	if(in.fail())
	{
	    cerr << argv[0] << ": can't open `" << refFile << "': "
		 << strerror(errno) << endl;
	    return 1;
	}
	
	char s[1000];
	in >> s;
	
	CORBA_Object_var obj = orb -> string_to_object(s);
	assert(!CORBA_is_nil(obj));
	
        //
        // Display information on the host and port number to which
        // we'll attempt to connect.
        //
        OCI_ConnectorInfo_var info = obj -> _get_oci_connector_info();
	OCI_IIOP_ConnectorInfo_var iiopInfo =
	    OCI_IIOP_ConnectorInfo::_narrow(info);

        if(!CORBA_is_nil(iiopInfo))
        {
            OCI_IIOP_InetAddr_var remoteAddr = iiopInfo -> remote_addr();
            CORBA_UShort remotePort = iiopInfo -> remote_port();

            cout << "Will connect to: "
		 << (int)remoteAddr[0] << '.' << (int)remoteAddr[2] << '.'
		 << (int)remoteAddr[2] << '.' << (int)remoteAddr[3]
		 << ":" << remotePort << endl;

        }

        //
	// Narrow to hello
	//
	Hello_var hello = Hello::_narrow(obj);
	assert(!CORBA_is_nil(hello));

	//
	// Main loop
	//
	cout << "Enter 'h' for hello or 'x' for exit:\n";
	char c;
	do
	{
	    cout << "> ";
	    cin >> c;
	    if(c == 'h')
	    {
		try
		{
		    hello -> hello();
		}
		catch(const CORBA_NO_PERMISSION&)
		{
		    cout << "Connection was refused" << endl;
		}
	    }
	}
	while(c != 'x');
    }
    catch(CORBA_SystemException& ex)
    {
	OBPrintException(ex);
	return 1;
    }
    
    return 0;
}

