/** 
 * 
 * Copyright 2004 Hiram Chirino
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 * 
 **/
package org.activeio;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

import junit.framework.TestCase;

import org.activeio.adapter.AsynchToSynchChannelAdapter;
import org.activeio.adapter.SynchToAsynchChannelAdapter;
import org.activeio.net.AIOAsynchChannel;
import org.activeio.net.AIOSynchChannelServer;
import org.activeio.net.NIOAsynchChannel;
import org.activeio.net.NIOAsynchChannelServer;
import org.activeio.net.NIOSynchChannel;
import org.activeio.net.NIOSynchChannelServer;
import org.activeio.net.SocketSynchChannel;
import org.activeio.net.SocketSynchChannelServer;
import org.activeio.net.VMPipeAsynchChannelPipe;
import org.activeio.net.VMPipeAsynchChannelServer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import EDU.oswego.cs.dl.util.concurrent.Latch;

/**
 */
public class ChannelFactoryTest extends TestCase {

    static final Log log = LogFactory.getLog(ChannelFactoryTest.class);
    static boolean aioDisabled = System.getProperty("disable.aio.tests", "false").equals("true");

    ChannelFactory factory = new ChannelFactory();

    private SynchChannelServer synchChannelServer;
    private SynchChannel clientSynchChannel;
    private SynchChannel serverSynchChannel;

    private AsynchChannelServer asynchChannelServer;
    private AsynchChannel clientAsynchChannel;
    private AsynchChannel serverAsynchChannel;
    
    protected void setUp() throws Exception {
        log.info("Running: "+getName());
    }

    public void testSocket() throws IOException, URISyntaxException, InterruptedException {
        
        createSynchObjects("socket://localhost:0");
        assertNotNull( synchChannelServer.narrow(SocketSynchChannelServer.class) );
        assertNotNull( clientSynchChannel.narrow(SocketSynchChannel.class) );
        assertNotNull( serverSynchChannel.narrow(SocketSynchChannel.class) );
        
        createAsynchObjects("socket://localhost:0");
        assertNotNull( asynchChannelServer.narrow(SocketSynchChannelServer.class) );
        assertNotNull( clientAsynchChannel.narrow(SocketSynchChannel.class) );
        assertNotNull( serverAsynchChannel.narrow(SocketSynchChannel.class) );
        
    }

    public void testAIO() throws IOException, URISyntaxException, InterruptedException {

        if( aioDisabled ) {
            return;
        }
        
        createSynchObjects("aio://localhost:0");
        assertNotNull( synchChannelServer.narrow(AIOSynchChannelServer.class) );
        assertNotNull( clientSynchChannel.narrow(AIOAsynchChannel.class) );
        assertNotNull( serverSynchChannel.narrow(AIOAsynchChannel.class) );
        
        createAsynchObjects("aio://localhost:0");
        assertNotNull( asynchChannelServer.narrow(AIOSynchChannelServer.class) );
        assertNotNull( clientAsynchChannel.narrow(AIOAsynchChannel.class) );
        assertNotNull( serverAsynchChannel.narrow(AIOAsynchChannel.class) );
        
    }    

    public void testNIO() throws IOException, URISyntaxException, InterruptedException {
        
        createSynchObjects("nio://localhost:0");
        assertNotNull( synchChannelServer.narrow(NIOSynchChannelServer.class) );
        assertNotNull( clientSynchChannel.narrow(NIOSynchChannel.class) );
        assertNotNull( serverSynchChannel.narrow(NIOSynchChannel.class) );
        
        createAsynchObjects("nio://localhost:0");
        assertNotNull( asynchChannelServer.narrow(NIOAsynchChannelServer.class) );
        assertNotNull( clientAsynchChannel.narrow(NIOAsynchChannel.class) );
        assertNotNull( serverAsynchChannel.narrow(NIOAsynchChannel.class) );
        
    }    

    public void testVMPipe() throws IOException, URISyntaxException, InterruptedException {
        
        createSynchObjects("vmpipe://localhost");
        assertNotNull( synchChannelServer.narrow(VMPipeAsynchChannelServer.class) );
        assertNotNull( clientSynchChannel.narrow(VMPipeAsynchChannelPipe.PipeChannel.class) );
        assertNotNull( serverSynchChannel.narrow(VMPipeAsynchChannelPipe.PipeChannel.class) );
        
        createAsynchObjects("vmpipe://localhost");
        assertNotNull( asynchChannelServer.narrow(VMPipeAsynchChannelServer.class) );
        assertNotNull( clientAsynchChannel.narrow(VMPipeAsynchChannelPipe.PipeChannel.class) );
        assertNotNull( serverAsynchChannel.narrow(VMPipeAsynchChannelPipe.PipeChannel.class) );
        
    }    
    
    private void createSynchObjects(String bindURI) throws IOException, URISyntaxException {
        synchChannelServer = factory.bindSynchChannel(new URI(bindURI));
        synchChannelServer.start();
        clientSynchChannel = factory.openSynchChannel(synchChannelServer.getConnectURI());
        serverSynchChannel = AsynchToSynchChannelAdapter.adapt( synchChannelServer.accept(1000*5) );
        serverSynchChannel.dispose();        
        clientSynchChannel.dispose();        
        synchChannelServer.dispose();
    }

    private void createAsynchObjects(String bindURI) throws IOException, URISyntaxException, InterruptedException {
        asynchChannelServer = factory.bindAsynchChannel(new URI(bindURI));
        final Latch accepted = new Latch();
        asynchChannelServer.setAcceptListener(new AcceptListener() {
            public void onAccept(Channel channel) {
                serverAsynchChannel = SynchToAsynchChannelAdapter.adapt(channel);
                channel.dispose();
                accepted.release();
            }
            public void onAcceptError(IOException error) {
                error.printStackTrace();
            }
        });
        asynchChannelServer.start();
        clientAsynchChannel = factory.openAsynchChannel(asynchChannelServer.getConnectURI());
        accepted.attempt(1000*10);
        clientAsynchChannel.dispose();        
        asynchChannelServer.dispose();
    }

}
