// **********************************************************************
//
// 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_impl.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 from: "
		 << (int)remoteAddr[0] << '.' << (int)remoteAddr[1] << '.'
		 << (int)remoteAddr[2] << '.' << (int)remoteAddr[3]
		 << ":" << remotePort << endl;
	}
    }
};

class AcceptCB_impl : public OCI_AcceptCB
{
public:

    virtual void accept_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 from: "
		 << (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 and BOA
	//
	CORBA_ORB_var orb = CORBA_ORB_init(argc, argv);
	CORBA_BOA_var boa = orb -> BOA_init(argc, argv);

        //
        // Get the OCI Current object
        //
	CORBA_Object_var ociCurrentObj =
        orb -> resolve_initial_references("OCICurrent");
	OCI_Current_var ociCurrent = OCI_Current::_narrow(ociCurrentObj);

	//
	// Create implementation object
	//
	Hello_var p = new Hello_impl(ociCurrent);

	//
	// Save reference
	//
	CORBA_String_var s = orb -> object_to_string(p);
	
	const char* refFile = "Hello.ref";
	ofstream out(refFile);
	if(out.fail())
	{
	    cerr << argv[0] << ": can't open `" << refFile << "': "
		 << strerror(errno) << endl;
	    return 1;
	}
	
	out << s << endl;
	out.close();

        //
        // Display the host and port
        //
        OCI_AccRegistry_var registry = boa -> get_acc_registry();
        OCI_AcceptorSeq_var acceptors = registry -> get_acceptors();

        for(CORBA_ULong i = 0 ; i < acceptors -> length() ; i++)
        {
            OCI_AcceptorInfo_var info = acceptors[i] -> get_info();
	    OCI_IIOP_AcceptorInfo_var iiopInfo =
		OCI_IIOP_AcceptorInfo::_narrow(info);
	    
	    if(!CORBA_is_nil(iiopInfo))
	    {
                CORBA_String_var host = iiopInfo -> host();
                CORBA_UShort port = iiopInfo -> port();

                cout << "*** Running on host `" << host
                     << "', port number " << port << endl;

                //
                // Add the accept callback object
                //
                OCI_AcceptCB_var acceptorCB = new AcceptCB_impl;
                iiopInfo -> add_accept_cb(acceptorCB);
            }
        }

	//
	// Run implementation
	//
	boa -> impl_is_ready(CORBA_ImplementationDef::_nil());
    }
    catch(CORBA_SystemException& ex)
    {
	OBPrintException(ex);
	return 1;
    }

    return 0;
}

