/* 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<SelectionKey> keys;
  private Set<SelectionKey> 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<SelectionKey> ();
    selected = new HashSet<SelectionKey> ();
  }

  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<SelectionKey> 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<SelectionKey> 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<SelectionKey> 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<SelectionKey> 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<SelectionKey> ckeys = cancelledKeys ();
    synchronized (ckeys)
    {
      Iterator<SelectionKey> 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;
  }
}
