/* 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;
  }
}
