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

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

#include <Test1.h>
#include <Test2.h>
#include <TestMacro.h>

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

#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif

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

void
TestMacro(const char* ex, const char* file, unsigned int line)
{
    cout << "Failed!" << endl;
    cout << "Reason: ( " << ex << " ) == false" << endl;
    cout << "File: " << file << endl;
    cout << "Line: " << line << endl;
    abort();
}

int
ClientRun(CORBA_ORB_ptr orb, int argc, char* argv[])
{
    //
    // Get TestInterface
    //
    const char* refFile = "TestInterface.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 impl[1000];
    in >> impl;
    char implDSI[1000];
    in >> implDSI;
    char implTie[1000];
    in >> implTie;

    in.close(); // The explicit close is necessary to satisfy the Windows NT
                // file locking

    //
    // Run tests
    //
    cout << "Testing constants... " << flush;
    extern void TestConst();
    TestConst();
    cout << "OK!" << endl;

    cout << "Testing TypeCode type... " << flush;
    extern void TestTypeCode();
    TestTypeCode();
    cout << "OK!" << endl;
    
    cout << "Testing any type... " << flush;
    extern void TestAny();
    TestAny();
    cout << "OK!" << endl;

    cout << "Testing some union types... " << flush;
    extern void TestUnion();
    TestUnion();
    cout << "OK!" << endl;

    cout << "Testing string_to_object()... " << flush;
    CORBA_Object_var obj = orb -> string_to_object(impl);
    TEST(!CORBA_is_nil(obj));
    CORBA_Object_var objDSI = orb -> string_to_object(implDSI);
    TEST(!CORBA_is_nil(objDSI));
    bool tie = true;
    CORBA_Object_var objTie;
    try
    {      
	objTie = orb -> string_to_object(implTie);
	TEST(!CORBA_is_nil(objTie));
    }
    catch(const CORBA_BAD_PARAM&)
    {
	tie = false;
    }
    cout << "OK!" << endl;

    cout << "Testing _narrow()... " << flush;
    TestInterface_var ti = TestInterface::_narrow(obj);
    TEST(!CORBA_is_nil(ti));
    TestInterface_var tiDSI = TestInterface::_narrow(objDSI);
    TEST(!CORBA_is_nil(tiDSI));
    TestInterface_var tiTie;
    if(tie)
    {
	tiTie = TestInterface::_narrow(objTie);
	TEST(!CORBA_is_nil(tiTie));
    }

    TestInterfaceEx_var tiex = TestInterfaceEx::_narrow(ti);
    TEST(!CORBA_is_nil(tiex));
    TestInterfaceEx_var tiexDSI = TestInterfaceEx::_narrow(tiDSI);
    TEST(!CORBA_is_nil(tiexDSI));
    TestInterfaceEx_var tiexTie;
    if(tie)
    {
	tiexTie = TestInterfaceEx::_narrow(tiTie);
	TEST(!CORBA_is_nil(tiexTie));
    }

    TestInterfaceTimeout_var titimeout =
	TestInterfaceTimeout::_narrow(ti);
    TEST(!CORBA_is_nil(titimeout));
    cout << "OK!" << endl;

    cout << "Testing interface stub... " << flush;
    extern void TestStub(TestInterface_ptr);
    TestStub(ti);
    cout << "OK!" << endl;

    cout << "Ditto, but with the DSI implementation... " << flush;
    TestStub(tiDSI);
    cout << "OK!" << endl;

    if(tie)
    {
	cout << "Ditto, but with the tie implementation... " << flush;
	TestStub(tiTie);
	cout << "OK!" << endl;
    }

    cout << "Testing interface stub with contexts... " << flush;
    extern void TestStubContext(TestInterface_ptr, CORBA_ORB_ptr);
    TestStubContext(ti, orb);
    cout << "OK!" << endl;

    cout << "Ditto, but with the DSI implementation... " << flush;
    TestStubContext(tiDSI, orb);
    cout << "OK!" << endl;

    if(tie)
    {
	cout << "Ditto, but with the tie implementation... " << flush;
	TestStubContext(tiTie, orb);
	cout << "OK!" << endl;
    }

    cout << "Testing interface stub with exceptions... " << flush;
    extern void TestStubException(TestInterfaceEx_ptr, bool);
    TestStubException(tiex, false);
    cout << "OK!" << endl;
    
    cout << "Ditto, but with the DSI implementation... " << flush;
    TestStubException(tiexDSI, true);
    cout << "OK!" << endl;

    if(tie)
    {
	cout << "Ditto, but with the tie implementation... " << flush;
	TestStubException(tiexTie, true);
	cout << "OK!" << endl;
    }

    cout << "Testing interface stub with timeouts... " << flush;
    extern void TestStubTimeout(CORBA_ORB_ptr,TestInterfaceTimeout_ptr);
    TestStubTimeout(orb, titimeout);
    cout << "OK!" << endl;

    cout << "Testing DII... " << flush;
    extern void TestDII(CORBA_Object_ptr, CORBA_ORB_ptr);
    TestDII(obj, orb);
    cout << "OK!" << endl;
    
    cout << "Ditto, but with the DSI implementation... " << flush;
    TestDII(objDSI, orb);
    cout << "OK!" << endl;

    if(tie)
    {
	cout << "Ditto, but with the tie implementation... " << flush;
	TestDII(objTie, orb);
	cout << "OK!" << endl;
    }

    cout << "Testing DII with contexts... " << flush;
    extern void TestDIIContext(CORBA_Object_ptr, CORBA_ORB_ptr);
    TestDIIContext(obj, orb);
    cout << "OK!" << endl;
    
    cout << "Ditto, but with the DSI implementation... " << flush;
    TestDIIContext(objDSI, orb);
    cout << "OK!" << endl;

    if(tie)
    {
	cout << "Ditto, but with the tie implementation... " << flush;
	TestDIIContext(objTie, orb);
	cout << "OK!" << endl;
    }

    cout << "Testing DII with exceptions... " << flush;
    extern void TestDIIException(CORBA_Object_ptr);
    TestDIIException(obj);
    cout << "OK!" << endl;
    
    cout << "Ditto, but with the DSI implementation... " << flush;
    TestDIIException(objDSI);
    cout << "OK!" << endl;

    if(tie)
    {
	cout << "Ditto, but with the tie implementation... " << flush;
	TestDIIException(objTie);
	cout << "OK!" << endl;
    }

    try
    {
	ti -> deactivate();
    }
    catch(const CORBA_TRANSIENT&)
    {
	// This call will deactivate the server and thus throw an
	// exception
    }

    return(0);
}
