/*
 * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
 * Copyright (C) 2006 - Javolution (http://javolution.org/)
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software is
 * freely granted, provided that this notice is preserved.
 */
package javolution.context;

import javax.realtime.MemoryArea;
import javax.realtime.RealtimeThread;
import javolution.lang.Reflection;

/**
 * <p> This class represents the concurrent executors used by the default 
 *     implementation of {@link ConcurrentContext}. Executions
 *     are performed in the same memory area and at the same priority
 *     as the calling thread.</p>
 *
 * @author  <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
 * @version 5.1, July 1, 2007
 */
class ConcurrentThread extends RealtimeThread {

    private volatile Runnable _logic;

    private MemoryArea _memoryArea;

    private int _priority;

    private ConcurrentContext.Default _context;

    private boolean _terminate;

    private String _name;

    private Thread _parent;

    /**
     * Default constructor.
     */
    public ConcurrentThread() {
        _name = "ConcurrentThread-" + getCount();
        if (SET_NAME != null) {
            SET_NAME.invoke(this, _name);
        }
        if (SET_DAEMON != null) {
            SET_DAEMON.invoke(this, Boolean.TRUE);
        }
    }

    private synchronized int getCount() {
        return _Count++;
    }

    private static int _Count;

    private static final Reflection.Method SET_NAME = Reflection
            .getInstance().getMethod("java.lang.Thread.setName(String)");

    private static final Reflection.Method SET_DAEMON = Reflection
            .getInstance().getMethod("java.lang.Thread.setDaemon(boolean)");

    /**
     * Executes the concurrent logics sequentially.
     */
    public void run() {
        while (true) { // Main loop.
            synchronized (this) { // Waits for a task.
                try {
                    while ((_logic == null) && !_terminate)
                        this.wait();
                } catch (InterruptedException e) {
                    throw new ConcurrentException(e);
                }
            }
            if (_terminate)
                break; // Terminates.
            try {
                Thread current = Thread.currentThread();
                if (current.getPriority() != _priority) {
                    current.setPriority(_priority);
                }
                _context.started();
                _memoryArea.executeInArea(_logic);
            } catch (Throwable error) {
                _context.error(error);
            } finally {
                _context.completed();
                _parent = null;
                _context = null;
                _logic = null; // Last (ready).
            }
        }
    }

    /**
     * Executes the specified logic by this thread if ready.
     * 
     * @param logic the logic to execute.
     * @param context the concurrent context.
     */
    public boolean execute(Runnable logic, ConcurrentContext.Default context) {
        if (_logic != null)
            return false; // Shortcut to avoid synchronizing.
        synchronized (this) {
            if (_logic != null)
                return false; // Synchronized check.
            _memoryArea = RealtimeThread.getCurrentMemoryArea();
            _parent = Thread.currentThread();
            _priority = _parent.getPriority();
            _context = context;
            _logic = logic; // Must be last.
            this.notify();
            return true;
        }
    }

    // Implements ConcurrentExecutor
    public void terminate() {
        synchronized (this) {
            _terminate = true;
            this.notify();
        }
    }

    /**
     * Returns the name of this concurrent thread as well as its calling source 
     * (in parenthesis).
     * 
     * @return the string representation of this thread.
     */
    public String toString() {
        return _name + " from " + getSource();
    }

    /**
     * Returns the source of this concurrent thread (a non-concurrent thread).
     * 
     * @return the thread source.
     */
    public Thread getSource() {
        return _parent instanceof ConcurrentThread ?
                ((ConcurrentThread)_parent).getSource() : _parent;
    }
}
