/* -*- mode: c++; c-basic-offset: 4; -*-
 *
 * MICO --- a CORBA implementation
 * Copyright (C) 1997-98 Kay Roemer & Arno Puder
 * 
 * Operation provider
 * Copyright (C) 1999 Andreas Schultz                                 
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Send comments and/or bug reports to:
 *                mico@informatik.uni-frankfurt.de
 * 
 * $Id: Operation.cc,v 1.18 2000/01/21 18:40:22 aschultz Exp $
 *
 */

#define MICO_DEBUG_MODULE MICODebug::Thread

#define MICO_CONF_IMR

#include <CORBA-SMALL.h>
#include <mico/impl.h>

MICO::OperationInfoNode::OperationInfoNode() {

    nextOP = 0;
    tp = 0;
};

MICO::OperationInfoNode::~OperationInfoNode() {};

MICO::Operation::Operation() {

    thr = 0;
    info = new OperationInfoNode;
};

MICO::Operation::Operation( const Operation &op ) {

    thr = 0;
    info = &op.Info();
};

MICO::Operation::Operation( MICO::ThreadPool& _tp ) {

    thr = 0;
    info = new OperationInfoNode;
    Info().setThreadPool( &_tp );
};

MICO::Operation::~Operation() {

    assert( !thr );

    CORBA::release (info);
}

void
MICO::Operation::send_msg( MICO::OP_id_type nextOP_id, MICO::msg_type *msg)
{
    Info().get_nextOP().put_msg( nextOP_id, msg );
}

void
MICO::Operation::initShutdown() {}

void
MICO::Operation::finalizeShutdown()
{
    // make sure the thread has left the context of
    //   this OP, deregisterOP will take care of that !

    if (thr)
	thr->deregisterOperation( this );
}

/*
 *  the assert's below mark methods that have to be overloaded
 *  in derived classes
 *
 *  the derived classes have to overload only one of those !!!
 *
 */
void
MICO::Operation::process( MICO::msg_type * msg ) {

    __MTOUT( MT_TRACE ( MICODebug::instance()->printer() 
	      << "implementation error - this should never happen" << endl ));
	
    assert( 0 );
};

void
MICO::Operation::put_msg( MICO::OP_id_type nextOP_id, MICO::msg_type *msg)
{
    __MTOUT( MT_TRACE ( MICODebug::instance()->printer() 
	      << "implementation error - Operation::put_msg - this should never happen" << endl ));
    assert( 0 );
};

void
MICO::passiveOperation::put_msg( MICO::OP_id_type nextOP_id, MICO::msg_type *msg)
{
    assert( Info().get_OP_id() == nextOP_id );
    __MTOUT( MT_TRACE ( MICODebug::instance()->printer() 
	      << "passiveOperation::put_msg():" << msg << endl ));
    _msg = msg;
};

void
MICO::passiveOperation::_run() {

    __MTOUT( MT_TRACE ( MICODebug::instance()->printer() 
	      << "passiveOperation::_run():" << _msg << endl ));
	
    if ( !_msg || _msg->get_type() == msg_type::Terminate ) {
	delete _msg;
	_msg = 0;
	return;
    }
    process( _msg );
    _msg = 0;
}

MICO::activeOperation::activeOperation(): Operation()
{
    registerInputMC( 0 );
};

MICO::activeOperation::activeOperation( const activeOperation &op ): Operation( op )
{
    registerInputMC( op.getInputMC() );
};

MICO::activeOperation::activeOperation( MICO::ThreadPool& _tp ): Operation( _tp )
{
    registerInputMC( 0 );
};

void
MICO::activeOperation::initShutdown() {

    if ( getInputMC() ) {
	MICO::msg_type *msg = new msg_type( 0, MICO::msg_type::Terminate );
	
	__MTOUT( MT_TRACE ( MICODebug::instance()->printer()
			    << "MICO::activeOperation::terminate" << endl ));
	getInputMC()->put_msg( Info().get_OP_id(), msg );
	__MTOUT( MT_TRACE ( MICODebug::instance()->printer()
			    << "  exiting thread: " << Thread() << endl ));

    }
}

void
MICO::activeOperation::_run() {

    while (42) {

        __MTOUT( MT_TRACE ( MICODebug::instance()->printer() 
            << __NAME (name () <<) "activeOperation::_run(): waiting for a msg"
                    << endl ));

        msg_type *msg = getInputMC()->get_msg( Info().get_OP_id() );
        //
        // We are guaranteed that msg is not NULL because get_msg() asserts
        // this, so don't bother checking it again after the call to get_msg()
        // above!!!
        //

        __MTOUT( MT_TRACE ( MICODebug::instance()->printer() 
            << __NAME (name () <<) "activeOperation::_run(): recv'd msg"
                    << endl ));

        if (msg->get_type() == msg_type::Terminate) {
            delete msg;
            return;
        }

        process( msg );
    }
}

