/* SelectorImpl.java -- 
   Copyright (C) 2002, 2003, 2004, 2006  Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath 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
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */


package gnu.java.nio;

import java.io.IOException;
import java.nio.channels.ClosedSelectorException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.nio.channels.spi.AbstractSelector;
import java.nio.channels.spi.SelectorProvider;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class SelectorImpl extends AbstractSelector
{
  private Set keys;
  private Set selected;

  /**
   * A dummy object whose monitor regulates access to both our
   * selectThread and unhandledWakeup fields.
   */
  private Object selectThreadMutex = new Object ();
  
  /**
   * Any thread that's currently blocked in a select operation.
   */
  private Thread selectThread;
  
  /**
   * Indicates whether we have an unhandled wakeup call. This can
   * be due to either wakeup() triggering a thread interruption while
   * a thread was blocked in a select operation (in which case we need
   * to reset this thread's interrupt status after interrupting the
   * select), or else that no thread was on a select operation at the
   * time that wakeup() was called, in which case the following select()
   * operation should return immediately with nothing selected.
   */
  private boolean unhandledWakeup;

  public SelectorImpl (SelectorProvider provider)
  {
    super (provider);
    
    keys = new HashSet ();
    selected = new HashSet ();
  }

  protected void finalize() throws Throwable
  {
    close();
  }

  protected final void implCloseSelector()
    throws IOException
  {
    // Cancel any pending select operation.
    wakeup();
    
    synchronized (keys)
      {
        synchronized (selected)
          {
            synchronized (cancelledKeys ())
              {
                // FIXME: Release resources here.
              }
          }
      }
  }

  public final Set keys()
  {
    if (!isOpen())
      throw new ClosedSelectorException();

    return Collections.unmodifiableSet (keys);
  }
    
  public final int selectNow()
    throws IOException
  {
    // FIXME: We're simulating an immediate select
    // via a select with a timeout of one millisecond.
    return select (1);
  }

  public final int select()
    throws IOException
  {
    return select (0);
  }

  private final int[] getFDsAsArray (int ops)
  {
    int[] result;
    int counter = 0;
    Iterator it = keys.iterator ();

    // Count the number of file descriptors needed
    while (it.hasNext ())
      {
        SelectionKeyImpl key = (SelectionKeyImpl) it.next ();

        if ((key.interestOps () & ops) != 0)
          {
            counter++;
          }
      }

    result = new int[counter];

    counter = 0;
    it = keys.iterator ();

    // Fill the array with the file descriptors
    while (it.hasNext ())
      {
        SelectionKeyImpl key = (SelectionKeyImpl) it.next ();

        if ((key.interestOps () & ops) != 0)
          {
            result[counter] = key.getNativeFD();
            counter++;
          }
      }

    return result;
  }

  public synchronized int select (long timeout)
    throws IOException
  {
    if (!isOpen())
      throw new ClosedSelectorException();
      
    synchronized (keys)
      {
        synchronized (selected)
          {
            deregisterCancelledKeys();

            // Set only keys with the needed interest ops into the arrays.
            int[] read = getFDsAsArray (SelectionKey.OP_READ
                                        | SelectionKey.OP_ACCEPT);
            int[] write = getFDsAsArray (SelectionKey.OP_WRITE
                                         | SelectionKey.OP_CONNECT);

            // FIXME: We dont need to check this yet
            int[] except = new int [0];

            // Test to see if we've got an unhandled wakeup call,
            // in which case we return immediately. Otherwise,
            // remember our current thread and jump into the select.
            // The monitor for dummy object selectThreadMutex regulates
            // access to these fields.

            // FIXME: Not sure from the spec at what point we should
            // return "immediately". Is it here or immediately upon
            // entry to this function?
            
            // NOTE: There's a possibility of another thread calling
            // wakeup() immediately after our thread releases
            // selectThreadMutex's monitor here, in which case we'll
            // do the select anyway. Since calls to wakeup() and select()
            // among different threads happen in non-deterministic order,
            // I don't think this is an issue.
            synchronized (selectThreadMutex)
              {
                if (unhandledWakeup)
                  {
                    unhandledWakeup = false;
                    return 0;
                  }
                else
                  {
                    selectThread = Thread.currentThread ();
                  }
              }

            // Call the native select() on all file descriptors.
            int result = 0;
            try
              {
                begin();
                result = VMSelector.select (read, write, except, timeout);
              }
            finally
              {
                end();
              }

            // If our unhandled wakeup flag is set at this point,
            // reset our thread's interrupt flag because we were
            // awakened by wakeup() instead of an external thread
            // interruption.
            //
            // NOTE: If we were blocked in a select() and one thread
            // called Thread.interrupt() on the blocked thread followed
            // by another thread calling Selector.wakeup(), then race
            // conditions could make it so that the thread's interrupt
            // flag is reset even though the Thread.interrupt() call
            // "was there first". I don't think we need to care about
            // this scenario.
            synchronized (selectThreadMutex)
              {
                if (unhandledWakeup)
                  {
                    unhandledWakeup = false;
                    Thread.interrupted ();
                  }
                selectThread = null;
              }

            Iterator it = keys.iterator ();

            while (it.hasNext ())
              {
                int ops = 0;
                SelectionKeyImpl key = (SelectionKeyImpl) it.next ();

                // If key is already selected retrieve old ready ops.
                if (selected.contains (key))
                  {
                    ops = key.readyOps ();
                  }

                // Set new ready read/accept ops
                for (int i = 0; i < read.length; i++)
                  {
                    if (key.getNativeFD() == read[i])
                      {
                        if (key.channel () instanceof ServerSocketChannelImpl)
                          {
                            ops = ops | SelectionKey.OP_ACCEPT;
                          }
                        else
                          {
                            ops = ops | SelectionKey.OP_READ;
                          }
                      }
                  }

                // Set new ready write ops
                for (int i = 0; i < write.length; i++)
                  {
		    if (key.getNativeFD() == write[i])
		      {
			if (key.channel() instanceof SocketChannel)
			  {
			    if (((SocketChannel) key.channel ()).isConnected ())
			      ops = ops | SelectionKey.OP_WRITE;
			    else
			      ops = ops | SelectionKey.OP_CONNECT;
			  }
			else
			  ops = ops | SelectionKey.OP_WRITE;
		      }
                  }

                // FIXME: We dont handle exceptional file descriptors yet.

                // If key is not yet selected add it.
                if (!selected.contains (key))
                  {
                    selected.add (key);
                  }

                // Set new ready ops
                key.readyOps (key.interestOps () & ops);
              }
            deregisterCancelledKeys();
            
            return result;
          }
        }
  }
    
  public final Set selectedKeys()
  {
    if (!isOpen())
      throw new ClosedSelectorException();

    return selected;
  }

  public final Selector wakeup()
  {
    // IMPLEMENTATION NOTE: Whereas the specification says that
    // thread interruption should trigger a call to wakeup, we
    // do the reverse under the covers: wakeup triggers a thread
    // interrupt followed by a subsequent reset of the thread's
    // interrupt status within select().
    
    // First, acquire the monitor of the object regulating
    // access to our selectThread and unhandledWakeup fields.
    synchronized (selectThreadMutex)
      {
        unhandledWakeup = true;
        
        // Interrupt any thread which is currently blocked in
        // a select operation.
        if (selectThread != null)
          selectThread.interrupt ();
      }
      
    return this;
  }

  private final void deregisterCancelledKeys()
  {
    Set ckeys = cancelledKeys ();
    synchronized (ckeys)
    {
      Iterator it = ckeys.iterator();

      while (it.hasNext ())
        {
          keys.remove ((SelectionKeyImpl) it.next ());
          it.remove ();
        }
    }
  }

  protected SelectionKey register (SelectableChannel ch, int ops, Object att)
  {
    return register ((AbstractSelectableChannel) ch, ops, att);
  }

  protected final SelectionKey register (AbstractSelectableChannel ch, int ops,
                                         Object att)
  {
    SelectionKeyImpl result;
    
    if (ch instanceof SocketChannelImpl)
      result = new SocketChannelSelectionKey (ch, this);
    else if (ch instanceof DatagramChannelImpl)
      result = new DatagramChannelSelectionKey (ch, this);
    else if (ch instanceof ServerSocketChannelImpl)
      result = new ServerSocketChannelSelectionKey (ch, this);
    else if (ch instanceof gnu.java.nio.SocketChannelImpl)
      result = new gnu.java.nio.SocketChannelSelectionKeyImpl((gnu.java.nio.SocketChannelImpl)ch, this);
    else
      throw new InternalError ("No known channel type");

    synchronized (keys)
      {
        keys.add (result);

	result.interestOps (ops);
	result.attach (att);
      }

    return result;
  }
}
