/*
 * Created on 26 oct. 2005
 *
 */
package archean.util;

import java.io.IOException;
import java.net.SocketAddress;

import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.IdleStatus;
import org.apache.mina.io.IoFilter;
import org.apache.mina.io.IoSession;
import org.apache.mina.protocol.ProtocolProvider;
import org.apache.mina.protocol.io.IoProtocolConnector;

/**
 * A simple auto reconnection filter.
 * Retry to reconnect a closed session until it's connected.
 * A delay between the reconnection is avaible as parameter. 
 * @author Julien Vermillard - Archean
 *
 */
public class ReconnectionFilter implements IoFilter {

	/** 
	 * @param delay delay in mili-seconds between 2 reconnections
	 * @param connector the ProtocolConnector to reconnect
	 * @param timeout connection timeout
	 * @param provider protocol provider to use for the connection
	 */
	public ReconnectionFilter(int delay,IoProtocolConnector connector,int timeout, ProtocolProvider provider, SocketAddress address, SocketAddress localAddress) {
		this.delay=delay;
		this.connector=connector;
		this.timeout=timeout;
		this.provider=provider;
		this.address=address;
		this.localAddress=localAddress;
		
	}

	private int delay;
	private IoProtocolConnector connector;
	private int timeout;
	private ProtocolProvider provider; 
	private SocketAddress address;
	private SocketAddress localAddress;
	
	public void sessionOpened(NextFilter nextFilter, IoSession session) throws Exception {
		nextFilter.sessionOpened(session);
	}

	public void sessionClosed(NextFilter nextFilter, IoSession session) throws Exception {
		// fire a connection retrying Thread
		ConnectionThread connectionThread=new ConnectionThread();
		connectionThread.start();
		nextFilter.sessionClosed(session);
	}

	public void sessionIdle(NextFilter nextFilter, IoSession session, IdleStatus status) throws Exception {
		nextFilter.sessionIdle(session,status);
		
	}

	public void exceptionCaught(NextFilter nextFilter, IoSession session, Throwable cause) throws Exception {
		nextFilter.exceptionCaught(session,cause);
	}

	public void dataRead(NextFilter nextFilter, IoSession session, ByteBuffer buf) throws Exception {
		nextFilter.dataRead(session,buf);
	}

	public void dataWritten(NextFilter nextFilter, IoSession session, Object marker) throws Exception {
		nextFilter.dataWritten(session,marker);
	}

	public void filterWrite(NextFilter nextFilter, IoSession session, ByteBuffer buf, Object marker) throws Exception {
		nextFilter.filterWrite(session,buf,marker);
		
	}

	private class ConnectionThread extends Thread {
		private ConnectionThread() {
			super();
		}

		public void run() {
			for(;;) {
				try {
					connector.connect(address,localAddress,timeout,provider);
					return;
				} catch (IOException e1) {
					// better hide those looping exception no ?
				}
				synchronized (this) {
					try {
						sleep(delay);
					} catch (InterruptedException e) {
					}
				}
			}
		}
	}

}
