//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / OVOPS++
//
//File: system.cpp
//
//Version: $Revision: 1.21 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/11/19 10:13:01 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
// 
//Authors:
//	Timo Kokkonen
//      Juhana Räsänen
//      Pasi Nummisalo
//
//Description:
//      A System class encapsulates SF mechanics.
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//     
//      
//Licence:
//     
//
//History:
//
//
 
#include "system.h"
#include <OB/Util.h>
#include <unistd.h>
#include "timer.h"
#include "protocol.h"
#include "device.h"
#include "memory.h"
#include "debug.h"
#include "sf/fifoscheduler.h"
#include "sf/schedulerhandle.h"

pfSystem *pfSystem :: _only = 0;

void pfSystem :: init(int argc, char *argv[])
{
    if (_only == 0)
    {
        try
        {
            _only = new pfSystem(argc, argv);
	}
	catch(...)
	{
	    debugUser("pfSyste::system initialization failed");
	    exit(-1);
	}
    }
    else
    {
        debugUser("pfSyste::system re-initialization not implemented");
    }
    return;
}

pfSystem *pfSystem :: instance(void)
{
    if(_only == 0)
    {
        _only = new pfSystem();
    }
    return _only;
}

pfSystem :: pfSystem(void)
    : _scheduler(0)
{
    _scheduler = sfFIFOScheduler::instance();
    pfMemory::reset();
    return;
}   

pfSystem :: pfSystem(int argc, char *argv[])
    : _scheduler(0)
{
    // The sfORBScheduler *must* be instantiated before calling
    // CORBA_ORB_init, otherwise the ORB will use default OmniBroker
    // SelectReactor as its reactor, not the SF version.
    _scheduler = sfFIFOScheduler::instance();
    sfFIFOScheduler::initORB(argc, argv);
    pfMemory::reset();
    return;
}   

pfSystem :: ~pfSystem(void)
{
    _only = 0;
    pfMemory::report();
    return;
}

//
//Function: run
//
//Description:
//    Runs the SF scheduler
//

void pfSystem :: run(void)
{
    try
    {
        _scheduler->run();
    }

    // If an sfSchedulerEmptyException is catched, just print info and
    // let this metohd return to the caller. It may be, that we are
    // driven by a program that has inserted something into this system,
    // waits for it to be handled and wants to continue after that.
    catch (sfException &exception_)
    {
        exception_.printInfo();

#ifdef __GNUC__

        // This is due to a bug in g++ exception handling code: exception
        // instances are not automatically freed outside catch block
        delete (sfException *) &exception_;

#endif // __GNUC__

    }

    // Any other exception from Scheduler Framework is printed and the
    // program is terminated.
    catch (sfException &exception_)
    {
        exception_.printInfo();

#ifdef __GNUC__

        // This is due to a bug in g++ exception handling code: exception
        // instances are not automatically freed outside catch block
        delete (sfException *) &exception_;

#endif // __GNUC__

        exit(0);
    }
    return;
}

//
//Function: next
//
//Description:
//    Runs only one step of SF scheduler 
//

void pfSystem :: next(void)
{
    try
    {
        _scheduler->step();
    }

    // If an sfSchedulerEmptyException is catched, just print info and
    // let this metohd return to the caller. It may be, that we are
    // driven by a program that has inserted something into this system,
    // waits for it to be handled and wants to continue after that.
    catch (sfException &exception_)
    {
        exception_.printInfo();

#ifdef __GNUC__

        // This is due to a bug in g++ exception handling code: exception
        // instances are not automatically freed outside catch block
        delete (sfException *) &exception_;

#endif // __GNUC__

    }

    // Any other exception from Scheduler Framework is printed and the
    // program is terminated.
    catch (sfException &exception_)
    {
        exception_.printInfo();

#ifdef __GNUC__

        // This is due to a bug in g++ exception handling code: exception
        // instances are not automatically freed outside catch block
        delete (sfException *) &exception_;

#endif // __GNUC__

        exit(0);
    }
    return;
}

CORBA_ORB_ptr pfSystem :: getORB(void)
{
    return sfFIFOScheduler::getORB();
}

void pfSystem::startProgram(const string &programName_,
                            const vector<string> &arguments_)
{
    int length = arguments_.size();
    char *arguments[length + 1];
    for (int i = 0; i < length; ++i)
    {
        arguments[i] = arguments_[i].c_str();
    }
    arguments[length] = 0;
    execv(programName_.c_str(), arguments);
    return;
}

//
//Function: registerTimer
//
//Description:
//    Registers a new timer to the system
//

void pfSystem :: registerTimer(pfTimer *timer_)
{
    if (timer_->getHandle() == 0)
    {
        sfSchedulerHandle *handle = _scheduler->makeHandle(timer_);
        timer_->setHandle(handle);
    }
    return;
}

//
//Function: registerConduit
//
//Description:
//    Registers a new conduit to the system
//

void pfSystem :: registerConduit(pfProtocol *conduit_)
{
    if (conduit_->getHandle() == 0)
    {
        sfSchedulerHandle *handle = _scheduler->makeHandle(conduit_);
        conduit_->setHandle(handle);
    }
    return;
}

//
//Function: registerDevice
//
//Description:
//    Registers a new device to the system
//

void pfSystem :: registerDevice(pfDevice *device_)
{
    if (device_->getHandle() == 0)
    {
        sfSchedulerHandle *handle = _scheduler->makeHandle(device_);
        device_->setHandle(handle);
    }
    return;
}

