// Path: src/main/java/com/flipkart/lois/channel/api/Channel.java
// public interface Channel<T> extends SendChannel<T>, ReceiveChannel<T> {
// 
// }
// 
// Path: src/main/java/com/flipkart/lois/channel/api/ReceiveChannel.java
// public interface ReceiveChannel<T> {
// 
//     /**
//      * Receive a message of Type {@link T} if message is available or block the thread and put it in wait state
//      * until there is a message available. If the channel has been closed and there are no more messages to be
//      * delivered, throw a {@link com.flipkart.lois.channel.exceptions.ChannelClosedException}
//      * @return a message of Type {@link T}
//      * @throws com.flipkart.lois.channel.exceptions.ChannelClosedException
//      * @throws InterruptedException
//      */
//     T receive() throws ChannelClosedException, InterruptedException;
// 
//     /**
//      * Receive a message of Type {@link T} if message is available or block the thread and put it in wait state
//      * until there is a message available or timeout {@link java.util.concurrent.TimeUnit}'s have passed. If the channel has been closed
//      * and there are no more messages to be delivered, throw a {@link ChannelClosedException}. If the timeout has
//      * been breached a {@link TimeoutException} is thrown.
//      * @param timeOut
//      * @param timeUnit
//      * @return a message of Type {@link T}
//      * @throws ChannelClosedException
//      * @throws InterruptedException
//      * @throws TimeoutException
//      */
//     T receive(long timeOut, TimeUnit timeUnit) throws ChannelClosedException, InterruptedException, TimeoutException;
// 
//     /**
//      * Tries to receive a messag in a non blocking way. If a message isn't available to receive "null" is returned
//      * else the value that is recieved is returned. If there was no message to recieve and the channel is closed then
//      * a {@link ChannelClosedException} is thrown
//      * @return message of type {@link T} if available else returns null
//      * @throws ChannelClosedException
//      */
//     T tryReceive() throws ChannelClosedException;
// 
//     /**
//      * Close channel so that no new messages can be sent over this channel. The messages that are already available
//      * on the channel can be consumed.
//      */
//     void close();
// 
//     /**
//      * Returns true if channel is open and false if channel is closed.
//      * @return true if channel is open, false if channel is closed
//      */
//     boolean isOpen();
// 
//     /**
//      * Returns true if a message can be received on the channel
//      * @return true if a message can be received on the channel
//      * @throws ChannelClosedException
//      */
//     boolean isReceivable() throws ChannelClosedException;
// }
// 
// Path: src/main/java/com/flipkart/lois/channel/api/SendChannel.java
// public interface SendChannel<T> {
// 
//     /**
//      * Send a message of Type {@link T} if the channel hasn't been closed and is available to send a message.
//      * If the channel is not free put the calling thread in a wait state until it becomes available to send
//      * a message. If the channel has been closed then a {@link com.flipkart.lois.channel.exceptions.ChannelClosedException} is thrown.
//      * @param message
//      * @throws com.flipkart.lois.channel.exceptions.ChannelClosedException
//      * @throws InterruptedException
//      */
//     void send(T message) throws ChannelClosedException, InterruptedException;
// 
//     /**
//      * Send a message of Type {@link T} if the channel hasn't been closed and is available to send a message.
//      * If the channel is not free put the calling thread in a wait state until it becomes available to send
//      * a message until timeOut {@link java.util.concurrent.TimeUnit}'s have passed, at which point throw a {@link java.util.concurrent.TimeoutException}.
//      * If the channel has been closed then a {@link ChannelClosedException} is thrown.
//      * @param message
//      * @param timeOut
//      * @param timeUnit
//      * @throws ChannelClosedException
//      * @throws TimeoutException
//      * @throws InterruptedException
//      */
//     void send(T message, long timeOut, TimeUnit timeUnit) throws ChannelClosedException, TimeoutException ,InterruptedException;
// 
//     /**
//      * A non blocking send of Type {@link T} if the channel hasn't been closed and is available to send a message.
//      * If the channel is not free return false, if the channel is available and send was successful return true.
//      * @param message
//      * @return true if send was successful, false if send failed at this instance.
//      * @throws ChannelClosedException
//      */
//     boolean trySend(T message) throws ChannelClosedException;
// 
//     /**
//      * Close channel so that no new messages can be sent over this channel. The messages that are already available
//      * on the channel can be consumed.
//      */
//     void close();
// 
//     /**
//      * Returns true if channel is open and false if channel is closed.
//      * @return true if channel is open, false if channel is closed
//      */
//     boolean isOpen();
// 
//     /**
//      * Returns true if a message can be sent on the channel
//      * @return true if a message can be sent on the channel
//      * @throws ChannelClosedException
//      */
//     boolean isSendable() throws ChannelClosedException;
// 
// }


import com.flipkart.lois.Lois;
import com.flipkart.lois.channel.api.Channel;
import com.flipkart.lois.channel.api.ReceiveChannel;
import com.flipkart.lois.channel.api.SendChannel;
import com.flipkart.lois.channel.exceptions.ChannelClosedException;
import com.flipkart.lois.routine.Routine;
import org.testng.annotations.Test;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
        try {
            channel.send("dude",10,TimeUnit.MICROSECONDS);
        } catch (TimeoutException e){
            timeoutExceptionThrown = true;
        }
        assert timeoutExceptionThrown;

        Thread.sleep(100);
        channel.close();

        try {
            channel.send("dude",10,TimeUnit.MICROSECONDS);
        } catch (ChannelClosedException e){
            channelClosedExceptionThrown = true;
        }
        assert channelClosedExceptionThrown;

        channelClosedExceptionThrown = false;

        try {
            channel.send("dude");
        } catch (ChannelClosedException e){
            channelClosedExceptionThrown = true;
        }
        assert channelClosedExceptionThrown;

    }

    @Test
    public void testTrySend() throws Exception{
// Path: src/main/java/com/flipkart/lois/channel/api/Channel.java
// public interface Channel<T> extends SendChannel<T>, ReceiveChannel<T> {
// 
// }
// 
// Path: src/main/java/com/flipkart/lois/channel/api/ReceiveChannel.java
// public interface ReceiveChannel<T> {
// 
//     /**
//      * Receive a message of Type {@link T} if message is available or block the thread and put it in wait state
//      * until there is a message available. If the channel has been closed and there are no more messages to be
//      * delivered, throw a {@link com.flipkart.lois.channel.exceptions.ChannelClosedException}
//      * @return a message of Type {@link T}
//      * @throws com.flipkart.lois.channel.exceptions.ChannelClosedException
//      * @throws InterruptedException
//      */
//     T receive() throws ChannelClosedException, InterruptedException;
// 
//     /**
//      * Receive a message of Type {@link T} if message is available or block the thread and put it in wait state
//      * until there is a message available or timeout {@link java.util.concurrent.TimeUnit}'s have passed. If the channel has been closed
//      * and there are no more messages to be delivered, throw a {@link ChannelClosedException}. If the timeout has
//      * been breached a {@link TimeoutException} is thrown.
//      * @param timeOut
//      * @param timeUnit
//      * @return a message of Type {@link T}
//      * @throws ChannelClosedException
//      * @throws InterruptedException
//      * @throws TimeoutException
//      */
//     T receive(long timeOut, TimeUnit timeUnit) throws ChannelClosedException, InterruptedException, TimeoutException;
// 
//     /**
//      * Tries to receive a messag in a non blocking way. If a message isn't available to receive "null" is returned
//      * else the value that is recieved is returned. If there was no message to recieve and the channel is closed then
//      * a {@link ChannelClosedException} is thrown
//      * @return message of type {@link T} if available else returns null
//      * @throws ChannelClosedException
//      */
//     T tryReceive() throws ChannelClosedException;
// 
//     /**
//      * Close channel so that no new messages can be sent over this channel. The messages that are already available
//      * on the channel can be consumed.
//      */
//     void close();
// 
//     /**
//      * Returns true if channel is open and false if channel is closed.
//      * @return true if channel is open, false if channel is closed
//      */
//     boolean isOpen();
// 
//     /**
//      * Returns true if a message can be received on the channel
//      * @return true if a message can be received on the channel
//      * @throws ChannelClosedException
//      */
//     boolean isReceivable() throws ChannelClosedException;
// }
// 
// Path: src/main/java/com/flipkart/lois/channel/api/SendChannel.java
// public interface SendChannel<T> {
// 
//     /**
//      * Send a message of Type {@link T} if the channel hasn't been closed and is available to send a message.
//      * If the channel is not free put the calling thread in a wait state until it becomes available to send
//      * a message. If the channel has been closed then a {@link com.flipkart.lois.channel.exceptions.ChannelClosedException} is thrown.
//      * @param message
//      * @throws com.flipkart.lois.channel.exceptions.ChannelClosedException
//      * @throws InterruptedException
//      */
//     void send(T message) throws ChannelClosedException, InterruptedException;
// 
//     /**
//      * Send a message of Type {@link T} if the channel hasn't been closed and is available to send a message.
//      * If the channel is not free put the calling thread in a wait state until it becomes available to send
//      * a message until timeOut {@link java.util.concurrent.TimeUnit}'s have passed, at which point throw a {@link java.util.concurrent.TimeoutException}.
//      * If the channel has been closed then a {@link ChannelClosedException} is thrown.
//      * @param message
//      * @param timeOut
//      * @param timeUnit
//      * @throws ChannelClosedException
//      * @throws TimeoutException
//      * @throws InterruptedException
//      */
//     void send(T message, long timeOut, TimeUnit timeUnit) throws ChannelClosedException, TimeoutException ,InterruptedException;
// 
//     /**
//      * A non blocking send of Type {@link T} if the channel hasn't been closed and is available to send a message.
//      * If the channel is not free return false, if the channel is available and send was successful return true.
//      * @param message
//      * @return true if send was successful, false if send failed at this instance.
//      * @throws ChannelClosedException
//      */
//     boolean trySend(T message) throws ChannelClosedException;
// 
//     /**
//      * Close channel so that no new messages can be sent over this channel. The messages that are already available
//      * on the channel can be consumed.
//      */
//     void close();
// 
//     /**
//      * Returns true if channel is open and false if channel is closed.
//      * @return true if channel is open, false if channel is closed
//      */
//     boolean isOpen();
// 
//     /**
//      * Returns true if a message can be sent on the channel
//      * @return true if a message can be sent on the channel
//      * @throws ChannelClosedException
//      */
//     boolean isSendable() throws ChannelClosedException;
// 
// }


// Path: src/test/java/com/flipkart/lois/channel/impl/BufferedPassByRefChannelTest.java
import com.flipkart.lois.Lois;
import com.flipkart.lois.channel.api.Channel;
import com.flipkart.lois.channel.api.ReceiveChannel;
import com.flipkart.lois.channel.api.SendChannel;
import com.flipkart.lois.channel.exceptions.ChannelClosedException;
import com.flipkart.lois.routine.Routine;
import org.testng.annotations.Test;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

        try {
            channel.send("dude",10,TimeUnit.MICROSECONDS);
        } catch (TimeoutException e){
            timeoutExceptionThrown = true;
        }
        assert timeoutExceptionThrown;

        Thread.sleep(100);
        channel.close();

        try {
            channel.send("dude",10,TimeUnit.MICROSECONDS);
        } catch (ChannelClosedException e){
            channelClosedExceptionThrown = true;
        }
        assert channelClosedExceptionThrown;

        channelClosedExceptionThrown = false;

        try {
            channel.send("dude");
        } catch (ChannelClosedException e){
            channelClosedExceptionThrown = true;
        }
        assert channelClosedExceptionThrown;

    }

    @Test
    public void testTrySend() throws Exception{
        Channel<String> channel = new BufferedChannel<String>(1);