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

#include <OB/CORBA.h>

#include <Chain_impl.h>

#ifndef WIN32
#include <unistd.h>
#endif

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

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

// ----------------------------------------------------------------------
// Link_impl constructor and desctructor
// ----------------------------------------------------------------------

Link_impl::Link_impl(CORBA_ORB_ptr orb, const char* file)
    : orb_(CORBA_ORB::_duplicate(orb)), file_(file), master_(false),
      nextId_(0)
{
}

// ----------------------------------------------------------------------
// Link_impl public members
// ----------------------------------------------------------------------
void
Link_impl::forward(const Message& msg)
{
    cout << "Received message " << msg.id << "\n";
    //
    // If this isn't the master, then forward the message.
    //
    if(!master_)
    {
	try
	{
	    cout << "Forwarding to next link." << endl;
	    next_ -> forward(msg);
	}
	catch(const CORBA_COMM_FAILURE&)
	{
	    cout << "COMM_FAILURE" << endl;
	}
    }
    else
    {
#if defined(WIN32)
	clock_t endTime = clock();
	cout << ((float)(endTime - startTime_))/CLOCKS_PER_SEC
	     << " sec." << endl;
#else
	struct timeval tp;
	gettimeofday(&tp, 0);
	double endTime = double(tp.tv_usec)+ double(tp.tv_sec)*double(1000000);
	long seconds = (long)(endTime-startTime_);
	cout << ((float)seconds)/ 1000000.0 << " sec roundtrip.\n";
#endif
    }
}

void
Link_impl::send(CORBA_Long nPings, CORBA_Long msgSize)
{
    cout << "start: initializing message." << endl;
    Message msg;
    msg.data.length(msgSize);
    int i;
    for(i = 0; i < msgSize; ++i)
    {
	msg.data[i] = 0;
    }
    cout << "start: done initialization." << endl;

    master_ = true;
    try
    {
	for(i = 0; i < nPings; ++i)
	{
	    //
	    // Set the message ID.
	    //
	    msg.id = nextId_++;

	    //
	    // Calculate the start time.
	    //
#if defined(WIN32)
	    startTime_ = clock();
#else
	    struct timeval tp;
	    gettimeofday(&tp, 0);
	    startTime_ = double(tp.tv_usec)+ double(tp.tv_sec)*double(1000000);
#endif
	    //
	    // Forward to the next link in the chain.
	    //
	    next_ -> forward(msg);
	}
    }
    catch(const CORBA_COMM_FAILURE&)
    {
	cout << "COMM_FAILURE::start on forward " << i << endl;
    }
    master_ = false;
}

void
Link_impl::close_loop()
{
    //
    // we're done if we already have the next element in the chain.
    //
    if(!CORBA_is_nil(next_))
    {
	return;
    }
    ifstream in; // Must use open(name), not ifstream in(name) (VC++ bug)
    in.open(file_);
    if(in.fail())
    {
	cerr << "can't open `" << file_ << "': "
	     << strerror(errno) << endl;
	exit(EXIT_FAILURE);
    }
    
    char s[1000];
    in >> s;
    
    CORBA_Object_var obj = orb_ -> string_to_object(s);
    assert(!CORBA_is_nil(obj));
    
    next_ = Link::_narrow(obj);
    assert(!CORBA_is_nil(next_));

    next_ -> close_loop();
}
