/**
 * Created on 30 Oct. 2009
 * Created by Takaki Tsue, Masato Kawahashi
 * Copyright (C) 2009 HIMACS,Ltd. 
 * Licensed under the Apache License, Version 2.0
 *
 */
/**
 * To avoid the follwing bug
 * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6230761
 */
package jp.himacs.avoidbugs.ipv6.bug6230761;

import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.nio.channels.spi.AbstractSelector;
import java.nio.channels.spi.SelectorProvider;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;

/**
 * @author t-tsue
 * to avoid the follwing bug
 * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6230761
 */
public class SelectorIPv6 extends AbstractSelector {
	
	/**
	 * DatagramChannel instance.
	 */
	private DatagramChannelImplIPv6 datagramChannel;
	
	/**
	 * SelectorProvider.
	 */
	private SelectorProvider myProvider;
	
	/**
	 * key set of selections.
	 */
	private TreeSet<SelectionKey> keys = new TreeSet<SelectionKey>();
	
	/*
	 * map of att object
	 * 
	 */
	private HashMap objMap = new HashMap();
	
	private static Selector instance;
	
	/**
	 * 
	 */
	public static Selector getInstance(SelectorProvider selectorProvider) {
		if (instance == null) {
			instance = new SelectorIPv6(selectorProvider);
		}
		return instance;
	}
	/**
	 * @param selectorProvider SelectorProvider instance;
	 */
	public SelectorIPv6(SelectorProvider selectorProvider) {
		super(selectorProvider);
		myProvider = selectorProvider;
	}

	/* (non-Javadoc)
	 * @see java.nio.channels.spi.AbstractSelector#implCloseSelector()
	 */
	@Override
	protected void implCloseSelector() throws IOException {
		keys = new TreeSet<SelectionKey>(); 
	}

	/* (non-Javadoc)
	 * @see java.nio.channels.spi.AbstractSelector#register(java.nio.channels.spi.AbstractSelectableChannel, int, java.lang.Object)
	 */
	@Override
	protected SelectionKey register(AbstractSelectableChannel channel, int opts,
			Object attr) {
		if (channel instanceof DatagramChannelImplIPv6) {
			datagramChannel = (DatagramChannelImplIPv6)channel;
		} else {
		}
		SelectionKey key = null;
		if (attr!=null && (key=(SelectionKey)objMap.get(attr))!=null) {
			IPv6Logger.IPV6.info("register without Object:"+channel);
			return key;
		}
		key = new SelectionKeyIPv6(this, channel).interestOps(opts);
		keys.add(key);
		objMap.put(attr, key);
		IPv6Logger.IPV6.info("register with Object:"+channel);
		return key;
	}

	public SelectionKey register(AbstractSelectableChannel channel, int ops) {
		return register(channel,ops,null);
	}
	/* (non-Javadoc)
	 * @see java.nio.channels.Selector#keys()
	 */
	@Override
	public Set<SelectionKey> keys() {
		return keys;
	}

	/* (non-Javadoc)
	 * @see java.nio.channels.Selector#select()
	 */
	@Override
	public int select() throws IOException {
		return select(-1);
	}

	/* (non-Javadoc)
	 * @see java.nio.channels.Selector#select(long)
	 */
	@Override
	public int select(long timeout) throws IOException {
		int result = WinsockIPv6.select(keys,(int)timeout);
		return result;
	}

	/* (non-Javadoc)
	 * @see java.nio.channels.Selector#selectNow()
	 */
	@Override
	public int selectNow() throws IOException {
		int result = WinsockIPv6.select(keys,(int)0);
		return result;
	}

	/* (non-Javadoc)
	 * @see java.nio.channels.Selector#selectedKeys()
	 */
	@Override
	public Set<SelectionKey> selectedKeys() {
		return new TreeSet<SelectionKey>(keys);
	}

	/* (non-Javadoc)
	 * @see java.nio.channels.Selector#wakeup()
	 */
	@Override
	public Selector wakeup() {
		return this;
	}

}
