/* -*- mode: c++; c-basic-offset: 4; -*-
 *
 * MICO --- a CORBA implementation
 * Copyright (C) 1997-98 Kay Roemer & Arno Puder
 * 
 * thread management
 * 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
 * 
 */


#ifndef __mico_mt_manager_h__
#define __mico_mt_manager_h__

struct tm_init_t {
    MICO::Operation::OP_id_type_decl  OP_type;
    unsigned int max;
    unsigned int max_idle;
    unsigned int min_idle;
    MICO::MsgChannel::Types mct;
    unsigned int mc_size;
    MICO::Operation *op;
    CORBA::Boolean start;
};

void thread_setup(unsigned int conn_limit, unsigned int req_limit);

class ThreadPoolManager;
class ThreadPool;

class WorkerThread: public MICOMT::Thread {
public:
    enum State { Transition, Idle, Busy, Stop };
protected:
    ThreadPool *tp;
    Operation* op;
    MICOMT::Mutex      op_critical;
    State      _state;
    MICOMT::Semaphore  _state_sem;
    msg_type   *_msg;
public:
    WorkerThread();
    WorkerThread( ThreadPool * );
    virtual ~WorkerThread();

    void setThreadPool( ThreadPool * );
    ThreadPool *getThreadPool();
    void registerOperation( Operation * );
    void deregisterOperation( Operation * );

    void put_msg(msg_type *);
    void mark_idle();
    void mark_busy();

    Operation *getOperation() const;
    virtual void _run (void *);

    void state (State s) {
	_state = s;
    };
    void post_state_change() {
	_state_sem.post();
    };
    State state() {
	return _state;
    };
private:
    void _run_single_queue_input();
    void _run_multi_queue_input();
    void _run_process();

    void wait_for_state_change() {
	_state_sem.wait();
    };
};

typedef FastArray<class WorkerThread> thread_map;
//typedef class WorkerThread WorkerThread;

class ThreadPool: public MsgChannel {
protected:
    MICOMT::Mutex tp_lock;

    ThreadPoolManager *tpm;

    //FIXME: those three array can be merged into one
    FastArray<WorkerThread> idle_threads;

    Operation* op;
    MsgChannel *input_mc;

    unsigned int max;
    unsigned int max_idle;
    unsigned int min_idle;

    unsigned int cnt_all;

public:
    ThreadPool( unsigned int _max,
		unsigned int _max_idle,
		unsigned int _min_idle);
    virtual ~ThreadPool();
    
    WorkerThread *get_idle_thread();
    WorkerThread *new_idle_thread();
    void mark_idle( WorkerThread * );
    void mark_busy( WorkerThread * );

    void remove_thread( WorkerThread *kt );

    // fire up all threads
    virtual void start_threads (void *arg = NULL);

    ThreadPoolManager& getThreadPoolManager() const {
	return *tpm;
    };
    void setThreadPoolManager(ThreadPoolManager& _tpm) {
	tpm = &_tpm;
    };

    void setOperation(Operation *_op) {
	op = _op;
    };
    Operation *getOperation() const {
	return op;
    };

    void registerInputMC(MsgChannel& _mc) {
	input_mc = &_mc;
	input_mc->setThreadPool( this );
    };
    MsgChannel& getInputMC() const {
	return *input_mc;
    };

    // methods from MsgChannel
    //    virtual msg_type * get_msg( OP_id_type nextOP_id);
    virtual void put_msg( OP_id_type nextOP_id, msg_type * msg);
};

inline void WorkerThread::mark_idle()
{
    if (getThreadPool())
	getThreadPool()->mark_idle( this );
};

inline void WorkerThread::mark_busy()
{
    if (getThreadPool())
	getThreadPool()->mark_busy( this );
};

inline void WorkerThread::setThreadPool( ThreadPool *_tp )
{
    tp = _tp;
};

inline ThreadPool *WorkerThread::getThreadPool()
{
    return tp;
};

inline void WorkerThread::put_msg( msg_type *m )
{
    op->put_msg( op->Info().get_OP_id(), m );
};

inline Operation *WorkerThread::getOperation() const {
    return op;
};

class ThreadPoolManager: public MsgChannel {
private:
    map<const OP_id_type, ThreadPool*> tp;
    MICO_ULong usercnt;
public:

    ThreadPoolManager() { usercnt = 64; };
    virtual ~ThreadPoolManager() {};

    MICO_ULong register_new_tp( ThreadPool& _tp) {
	tp[usercnt] = &_tp;
	_tp.setThreadPoolManager( *this );
        return ++usercnt;
    };
    void register_tp( const OP_id_type OP_id, ThreadPool& _tp) {
	tp[OP_id] = &_tp;
	_tp.setThreadPoolManager( *this );
    };

    ThreadPool& getThreadPool( const OP_id_type OP_id ) {
	return *tp[OP_id];
    };

    WorkerThread *get_idle_thread( const OP_id_type OP_id ) {

	return getThreadPool( OP_id ).get_idle_thread();
    }

    Operation *getOperation( OP_id_type OP_id ) {
	return getThreadPool( OP_id ).getOperation();
    }
    virtual void put_msg( OP_id_type nextOP_id, msg_type * msg) {
	getThreadPool(nextOP_id).put_msg( nextOP_id, msg );
    };
};

extern ThreadPoolManager     *_tpm;

#endif // __mico_mt_manager_h__
