package org.fidonet.binkp.io;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.service.DefaultTransportMetadata;
import org.apache.mina.core.session.IoSessionConfig;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.ProtocolCodecSession;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.fidonet.binkp.Connector;
import org.fidonet.binkp.LinksInfo;
import org.fidonet.binkp.SessionContext;
import org.fidonet.binkp.SessionState;
import org.fidonet.binkp.codec.BinkDataCodecFactory;
import org.fidonet.binkp.codec.BinkDataDecoder;
import org.fidonet.binkp.config.ServerRole;
import org.fidonet.binkp.config.StationConfig;
import org.fidonet.binkp.handler.BinkSessionHandler;
import org.fidonet.types.FTNAddr;
import org.fidonet.types.Link;
import org.junit.Test;

import java.io.InputStream;
import java.net.SocketAddress;

/**
 * Created by IntelliJ IDEA.
 * Author: Vladimir Kravets
 * E-Mail: vova.kravets@gmail.com
 * Date: 9/26/12
 * Time: 4:57 PM
 */
public class ClientTest {

    private class ClientMock extends Connector implements Runnable {

        private ProtocolCodecSession session;
        private SessionContext sessionContext;

        public ClientMock(SessionContext sessionContext) {
            this.sessionContext = sessionContext;
        }

        @Override
        public void run(SessionContext sessionContext) throws Exception {
            session = new ProtocolCodecSession();
            session.getFilterChain().addFirst("codec", new ProtocolCodecFilter(new BinkDataCodecFactory()));
            session.setHandler(new BinkSessionHandler(sessionContext));
            session.setTransportMetadata(new DefaultTransportMetadata(
                    "mina", "dummy", false, true,
                    SocketAddress.class, IoSessionConfig.class, Object.class));
            sessionContext.setServerRole(ServerRole.CLIENT);
            session.getHandler().sessionOpened(session);
            sessionContext.setState(SessionState.STATE_IDLE);
        }

        @Override
        public void stop(SessionContext sessionContext) {
            session.close();
        }

        public ProtocolCodecSession getSession() {
            return session;
        }

        public void writeStreamToSession(InputStream stream) throws Exception {
            int bufSize = 10;
            int size = 0;
            byte[] bytes = new byte[bufSize];
            ProtocolDecoder decoder = new BinkDataDecoder();
            while ( ( size = stream.read(bytes) ) != -1 ) {
                IoBuffer buf = IoBuffer.allocate(size);
                buf.put(bytes, 0, size);
                buf.flip();
                decoder.decode(session, buf, session.getDecoderOutput());
                Thread.sleep(100);
            }
            Thread.sleep(2000);
            sessionContext.setState(SessionState.STATE_END);
        }

        @Override
        public void run() {
            try {
                run(sessionContext);
                InputStream recvRawData = ClientMock.class.getClassLoader().getResourceAsStream("recv_stream.bin");
                Runnable recvMessage = new Runnable() {
                    @Override
                    public void run() {
                        while (!sessionContext.getState().equals(SessionState.STATE_END)) {
                            while (!session.getDecoderOutputQueue().isEmpty()) {
                                Object msg = session.getDecoderOutputQueue().poll();
                                try {
                                    session.getHandler().messageReceived(session, msg);
                                } catch (Exception e) {
                                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                                }
                            }
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                            }
                        }
                    }
                };
                Thread recvMessageThread = new Thread(recvMessage);
                recvMessageThread.start();
                ClientMock.this.writeStreamToSession(recvRawData);
            } catch (Exception e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
    }

    @Test
    public void testBaseFlow() throws InterruptedException {
        StationConfig config = new StationConfig("Test Station", "Vasya Pupkin", "Odessa, Ukraine", "BINKP", "2:467/70.113");
        LinksInfo linksInfo = new LinksInfo(new Link(new FTNAddr("2:467/70.113"), new FTNAddr("2:467/70"), "pass_i_f", "localhost", 24554));
        SessionContext sessionContext = new SessionContext(config, linksInfo);
        sessionContext.getStationConfig().setCryptMode(true);
        Thread thread = new Thread(new ClientMock(sessionContext));
        thread.start();
        thread.join();
    }

}

@@ -814,16 +814,41 @@
 s.Link;%0A
+import org.junit.Assert;%0A
 import o
@@ -5242,21 +5242,274 @@
 ead.join();%0A
+        FileInfo fileInfo = sessionContext.getRecvFiles().peek().getInfo();%0A        Assert.assertEquals(%220000FF8F.WE5%22, fileInfo.getName());%0A        Assert.assertEquals(766, fileInfo.getSize());%0A        Assert.assertEquals(true, fileInfo.isFinished());%0A
     %7D%0A%0A%7D%0A

Add test checks.