/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.geronimo.gshell.remote.request;

import java.util.concurrent.TimeUnit;

import org.apache.geronimo.gshell.remote.message.Message;
import org.apache.geronimo.gshell.remote.transport.Transport;
import org.apache.mina.common.IoFutureListener;
import org.apache.mina.common.IoSession;
import org.apache.mina.common.WriteFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Provides support to send a request and receive it's response.
 *
 * @version $Rev$ $Date$
 */
public class Requestor
{
    public static final long DEFAULT_TIMEOUT = 10;

    public static final TimeUnit DEFAULT_TIMEOUT_UNIT = TimeUnit.SECONDS;

    private final Logger log = LoggerFactory.getLogger(getClass());
    
    private final MessageWriter writer;

    private final long timeout;

    private final TimeUnit unit;

    private Requestor(final MessageWriter writer, final long timeout, final TimeUnit unit) {
        this.writer = writer;
        this.timeout = timeout;
        this.unit = unit;
    }

    public Requestor(final IoSession session, final long timeout, final TimeUnit unit) {
        this(new SessionMessageWriter(session), timeout, unit);
    }

    public Requestor(final IoSession session) {
        this(session, DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_UNIT);
    }

    public Requestor(final Transport transport, final long timeout, final TimeUnit unit) {
        this(new TransportMessageWriter(transport), timeout, unit);
    }

    public Requestor(final Transport transport) {
        this(transport, DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_UNIT);
    }

    public RequestWriteFuture submit(final Message msg, final long timeout, final TimeUnit unit) throws Exception {
        assert msg != null;

        Request req = new Request(msg, timeout, unit);

        WriteFuture wf = writer.write(req);

        return new RequestWriteFuture(wf, req);
    }

    public RequestWriteFuture submit(final Message msg) throws Exception {
        return submit(msg, timeout, unit);
    }

    public Message request(final Message msg, final long timeout, final TimeUnit unit) throws Exception {
        assert msg != null;

        RequestWriteFuture wf = submit(msg, timeout, unit);

        Request req = wf.getRequest();

        Response resp = req.awaitResponse();

        return resp.getMessage();
    }

    public Message request(final Message msg) throws Exception {
        return request(msg, timeout, unit);
    }

    //
    // MessageWriter
    //

    /**
     * An abstraction to allow an {@link IoSession} or {@link Transport} instance to be used to send messages.
     */
    private static interface MessageWriter
    {
        WriteFuture write(Object message) throws Exception;
    }

    private static class SessionMessageWriter
        implements MessageWriter
    {
        private final IoSession session;

        public SessionMessageWriter(final IoSession session) {
            this.session = session;
        }

        public WriteFuture write(final Object message) throws Exception {
            return session.write(message);
        }
    }

    private static class TransportMessageWriter
        implements MessageWriter
    {
        private final Transport transport;

        public TransportMessageWriter(final Transport transport) {
            this.transport = transport;
        }

        public WriteFuture write(final Object message) throws Exception {
            return transport.send(message);
        }
    }

    //
    // RequestWriteFuture
    //

    public class RequestWriteFuture
        implements WriteFuture
    {
        private final WriteFuture delegate;

        private final Request request;

        public RequestWriteFuture(final WriteFuture wf, final Request req) {
            this.delegate = wf;
            this.request = req;
        }

        public Request getRequest() {
            return request;
        }

        public boolean isWritten() {
            return delegate.isWritten();
        }

        public void setWritten(final boolean written) {
            delegate.setWritten(written);
        }

        public IoSession getSession() {
            return delegate.getSession();
        }

        public void join() {
            delegate.join();
        }

        public boolean join(final long timeout) {
            return delegate.join(timeout);
        }

        public boolean isReady() {
            return delegate.isReady();
        }

        public void addListener(final IoFutureListener listener) {
            delegate.addListener(listener);
        }

        public void removeListener(final IoFutureListener listener) {
            delegate.removeListener(listener);
        }
    }
}
@@ -1546,36 +1546,33 @@
 e final 
-MessageWriter writer
+IoSession session
 ;%0A%0A    p
@@ -1665,28 +1665,25 @@
 nal 
-MessageWriter writer
+IoSession session
 , fi
@@ -1740,23 +1740,25 @@
 his.
-writer = writer
+session = session
 ;%0A  
@@ -1824,168 +1824,8 @@
  %7D%0A%0A
-    public Requestor(final IoSession session, final long timeout, final TimeUnit unit) %7B%0A        this(new SessionMessageWriter(session), timeout, unit);%0A    %7D%0A%0A
     
@@ -2045,21 +2045,17 @@
 his(
-new T
+t
 ransport
 Mess
@@ -2054,31 +2054,20 @@
 port
-MessageWriter(transport
+.getSession(
 ), t
@@ -2439,14 +2439,15 @@
 f = 
-writer
+session
 .wri
@@ -3078,1042 +3078,12 @@
   %7D%0A
-%0A
     
-//%0A    // MessageWriter%0A    //%0A%0A    /**%0A     * An abstraction to allow an %7B@link IoSession%7D or %7B@link Transport%7D instance to be used to send messages.%0A     */%0A    private static interface MessageWriter%0A    %7B%0A        WriteFuture write(Object message) throws Exception;%0A    %7D%0A%0A    private static class SessionMessageWriter%0A        implements MessageWriter%0A    %7B%0A        private final IoSession session;%0A%0A        public SessionMessageWriter(final IoSession session) %7B%0A            this.session = session;%0A        %7D%0A%0A        public WriteFuture write(final Object message) throws Exception %7B%0A            return session.write(message);%0A        %7D%0A    %7D%0A%0A    private static class TransportMessageWriter%0A        implements MessageWriter%0A    %7B%0A        private final Transport transport;%0A%0A        public TransportMessageWriter(final Transport transport) %7B%0A            this.transport = transport;%0A        %7D%0A%0A        public WriteFuture write(final Object message) throws Exception %7B%0A            return transport.send(message);%0A        %7D%0A    %7D%0A
 %0A   

Remove the writer muck, transport now has a getSession() so just use that