/*
 * Jakelib2 - General purpose C++ library
 * Copyright (C) 2001 Florian Wolff  (florian@donuz.de)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * $Id: Thread.h,v 1.43 2003/08/26 19:50:16 florian Exp $
 */

#ifndef INCLUDE_JAKELIB2_LANG_THREAD_H
# define INCLUDE_JAKELIB2_LANG_THREAD_H

#define THREAD_STATE_INIT 0
#define THREAD_STATE_RUNNING 1
#define THREAD_STATE_PAUSED 2
#define THREAD_STATE_STOPPED 3

#ifdef HAVE_PTHREAD_H
# include <pthread.h>
#endif
#if defined(JAKELIB_WIN32API)
# include <windows.h>
#endif
#include "Runnable.h"


namespace jakelib {
  namespace util {
    class ArrayList;
  }

  namespace lang {
    class Mutex;
    class StackTrace;
    class TmpStackTraceElement;

    /**
     * @brief Thread represents a single thread of execution.
     *
     * Threads have names to identify them. These names are not necessarily
     * unique. Every \c Thread has a priority, as well.
     * New threads inherit the priority
     * and daemon status of the parent thread, by default (not yet!).
     *
     * There are two methods of creating a Thread: you may subclass \c Thread and
     * implement the \c run() method, at which point you may start the
     * Thread by calling its \c start() method, or you may implement
     * \c Runnable in the class you want to use and then call
     * <code>new Thread(your_obj).start()</code>.
     *
     * It is unclear at what point a Thread should be added to a ThreadGroup,
     * and at what point it should be removed. Should it be inserted when it
     * starts, or when it is created?  Should it be removed when it is suspended
     * or interrupted?  The only thing that is clear is that the Thread should be
     * removed when it is stopped.
     *
     * <tt><pre>
     * class A : public Thread {
     *   void run() {
     *     while(true) {
     *       sleep(500);
     *       System::out->print("(A)");
     *       new String("Hello, my name is A!");
     *     }
     *   }
     * };
     *
     * ...
     *
     * A* a = new A();
     * a->start();
     * Thread::sleep(10000);
     * a->stop();
     *
     * </pre></tt>
     *
     * @class Thread
     * @version $Id: Thread.h,v 1.43 2003/08/26 19:50:16 florian Exp $
     * @author Florian 'Overflo' Wolff (florian@donuz.de)
     */
    class Thread : public Object, Runnable
      {
        friend class jakelib::lang::TmpStackTraceElement;
        friend class jakelib::lang::Throwable;

      public:

#ifdef JAKELIB_THREADS
	/**
	 * @brief Creates a new \c Thread object. To start the thread call \c start.
         *
         * @param name An optional name for the new Thread.
	 */
        Thread(jakelib::lang::String* name = null);

        /**
         * @brief Creates a new \c Thread object.
         *
         * @param r The Runnable to be executed in the new Thread.
         * @param name An optional name for the new Thread.
         */
        Thread(Runnable* r, jakelib::lang::String* name = null);

	/**
	 * @brief Starts the thread. The \c run method will be executed.
	 */
	virtual void start();

	/**
	 * @brief Causes the currently executing thread object to temporarily pause 
	 * and allow other threads to execute.
         *
	 * @todo (Not yet implemented for Win32!)
	 */
	static void yield();

        /**
	 * @todo (Not yet implemented for Win32!)
         */
        virtual void join();
#endif

	/**
	 * @brief The actual thread method. This method is called after the thread
	 * has been started. Should be overridden to do whatever you
	 * want the thread to do!
	 */
        void run();

	/**  
	 * @brief Causes the currently executing thread to sleep (temporarily cease 
	 * execution) for the specified number of milliseconds. The thread 
	 * does not lose ownership of any monitors.
	 *
	 * @param      millis   the length of time to sleep in milliseconds.
	 */
	static void sleep(jlong millis);
  
        /**
         * Returns the name of this \c Thread.
         */
	virtual String* getName();

        /**
         * Returns a short description of this \c Thread.
         */
	String* toString();

        /**
	 * Returns the \c Thread object of the currently executed
         * thread.
         */
	static Thread* currentThread();
  
	int hashCode();

        //virtual void setPriority(int newPriority);

        //virtual void interrupt();

        /**
         * Does nothing if debugging is switched off.
         */
        void dumpStack();

        /**
         * @brief Called by \c Object::initJakelib2().
         * Do not use otherwise.
         */
        static void initThreadClass();

      protected:

	Thread(jboolean dummy);

	static Thread* mainThread;

	static Mutex* globalThreadLock;

	int state;

        /** This \c Thread's name */
	String* name;

	static int highestThreadNumber;

        /** The internal thread ID */
	int threadNumber;

#ifdef HAVE_WINTHREADS 
	HANDLE handle;
        static DWORD currentThreadKey;
	static int intThreadRun(Thread* thread);
#endif

#ifdef HAVE_PTHREADS
	pthread_t  threadInfo;
	static pthread_key_t currentThreadKey;
	static void* voidThreadRun(void* thread);
#endif

        Runnable* target;

        StackTrace *getStackTrace();

      private:


#ifdef JAKELIB_THREADS
        /**
         * This method is called after the \c run() method has returned.
         */
        void afterRun();

        /**
         * This method is called before the \c run() method is called.
         */
        void beforeRun();
#endif

        /** Holds references to all \c Thread objects that are still
            running. (Otherwise the garbage collector might delete
            a \c Thread object. */
        static jakelib::util::ArrayList *allThreads;

        /** This \c Thread's stack trace */
        StackTrace *stackTrace;

	JAKELIB_DECLARE_CLASS(Thread);
      };

  }
}

#endif
