/**
 * Copyright (c) 1998 by Cornell University.
 * All rights reserved.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL CORNELL UNIVERSITY BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF CORNELL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * CORNELL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND CORNELL UNIVERSITY HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 */
package cornell.slk.jkernel.core;

import java.io.*;
import java.util.*;

/**
 *  A thread segment is the part of a thread that is currently
 *  running in a particular task.  Each time a cross-task call
 *  is made, a new thread segment is spawned for the call to
 *  run in.</p>
 *
 *  stdlib comes with a java.lang.Thread implementation that
 *  runs directly on top of ThreadSegment, so you normally
 *  don't have to worry about ThreadSegments.
 */
public final class ThreadSegment
{
    static Object createLock = new Object(); // global lock acquired when creating threads

//    CrossTaskThread t;
    Thread t;
    ThreadTaskState tds;

    Object data;
    boolean alertFlag;
    Error stopThrow;
    boolean suspended;
//    int priority;

    // When a thread segment is active, its thread may be modified
    // (stopped, suspended, etc.).  Before modifying a thread,
    // a thread segment must acquire the thread's crossLock to ensure
    // that the thread does not change thread segments.


    public ThreadSegment(Runnable target)
    {
        if(target == null) throw new NullPointerException();

        synchronized(createLock)
        {
            CrossTaskThread cdt = new CrossTaskThread(this, target);
            t = cdt;
            tds = cdt.tds;
        }
    }

    // This is only used for creating the first thread segment:
    ThreadSegment(Runnable target, Task task)
    {
        if(target == null) throw new NullPointerException();
        CrossTaskThread cdt = new CrossTaskThread(this, target, task);
        t = cdt;
        tds = cdt.tds;
    }

    // This constructor puts a thread segment inside an already running
    // CrossTaskThread.  There is no need to call start() in this
    // case:
    ThreadSegment(/*CrossTaskThread t*/ Thread t, ThreadTaskState tds)
    {
        this.t = t;
        this.tds = tds;
    }

    public static ThreadSegment currentThreadSegment()
    {
        ThreadTaskState tds = ThreadTaskState.currentTDS();

//        synchronized(tds)
//        {
            if(tds.activeThreadSegment == null)
            {
                tds.activeThreadSegment = new ThreadSegment(tds.t, tds);
            }
            return tds.activeThreadSegment;
//        }
    }

    public void setData(Object data)
    {
        this.data = data;
    }

    public Object getData()
    {
        return data;
    }

    public final void start()
    {
        t.start();
    }

    public final void stop()
    {
        stop(new ThreadDeath());
    }

    public final synchronized void stop(Error o)
    {
        if(o == null) throw new NullPointerException();

        synchronized(tds)
        {
            suspended = false;

            if(this == tds.activeThreadSegment)
            {
                t.stop(o);
            }
            else
            {
                alertFlag = true;
                stopThrow = o;
            }
        }
    }

    public final void suspend()
    {
        synchronized(tds)
        {
            if(suspended || stopThrow != null) return;
            suspended = true;

            if(this == tds.activeThreadSegment)
            {
                t.suspend();
            }
            else
            {
                alertFlag = true;
            }
        }
    }

    public final void resume()
    {
        synchronized(tds)
        {
            if(!suspended || stopThrow != null) return;
            suspended = false;

            if(this == tds.activeThreadSegment)
            {
                if(tds.suspendWaiting) tds.notify();
                else t.resume();
            }
            else
            {
                alertFlag = true;
            }
        }
    }

    public final void join()
            throws InterruptedException
    {
        // XXX
        t.join();
    }

/*
    public final void setPriority(int newPriority)
    {
        // XXX
    }

    public final void setName(String name)
    {
        // XXX
    }

    public final void setDaemon(boolean on)
    {
        // daemon thread segments?
    }
*/
    public static void yield()
    {
        Thread.yield();
    }

    public static void sleep(long millis)
            throws InterruptedException
    {
        Thread.sleep(millis);
    }

    public static void sleep(long millis, int nanos)
            throws InterruptedException
    {
        Thread.sleep(millis, nanos);
    }

}
