package com.pushtechnology.diffusion.transform.messaging;

import static com.pushtechnology.diffusion.client.session.Session.State.CLOSED_BY_CLIENT;
import static com.pushtechnology.diffusion.client.session.Session.State.CONNECTED_ACTIVE;
import static com.pushtechnology.diffusion.client.session.Session.State.CONNECTING;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.MockitoAnnotations.initMocks;

import java.util.Collections;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.verification.VerificationWithTimeout;

import com.pushtechnology.diffusion.client.Diffusion;
import com.pushtechnology.diffusion.client.features.Messaging.SendCallback;
import com.pushtechnology.diffusion.client.session.Session;
import com.pushtechnology.diffusion.datatype.Bytes;
import com.pushtechnology.diffusion.datatype.binary.Binary;
import com.pushtechnology.diffusion.transform.messaging.receive.MessageReceiverBuilders;
import com.pushtechnology.diffusion.transform.messaging.receive.MessageReceiverHandle;
import com.pushtechnology.diffusion.transform.messaging.receive.TransformedMessageHandler;
import com.pushtechnology.diffusion.transform.messaging.send.MessageSenderBuilders;
import com.pushtechnology.diffusion.transform.messaging.send.MessageToHandlerSender;
import com.pushtechnology.diffusion.transform.transformer.TransformationException;
import com.pushtechnology.diffusion.transform.transformer.Transformers;

/**
 * Integration test for sending messages from a session to a handler.
 * @author Matt Champion 12/04/2017
 */
public final class SessionToHandlerIT {
    @Mock
    private Session.Listener listener;
    @Mock
    private TransformedMessageHandler<Integer> handler;
    @Mock
    private SendCallback sendCallback;

    private Session session;
    private Session controlSession;

    @Before
    public void setUp() {
        initMocks(this);

        session = Diffusion
            .sessions()
            .listener(listener)
            .principal("control")
            .password("password")
            .open("ws://localhost:8080");
        verify(listener, timed()).onSessionStateChanged(session, CONNECTING, CONNECTED_ACTIVE);

        controlSession = Diffusion
            .sessions()
            .listener(listener)
            .principal("control")
            .password("password")
            .open("ws://localhost:8080");
        verify(listener, timed()).onSessionStateChanged(controlSession, CONNECTING, CONNECTED_ACTIVE);
    }

    @After
    public void postConditions() {
        session.close();
        verify(listener, timed()).onSessionStateChanged(session, CONNECTED_ACTIVE, CLOSED_BY_CLIENT);
        controlSession.close();
        verify(listener, timed()).onSessionStateChanged(controlSession, CONNECTED_ACTIVE, CLOSED_BY_CLIENT);

        verifyNoMoreInteractions(listener, handler, sendCallback);
    }

    @Test
    public void sendToHandler() throws TransformationException {
        final MessageReceiverHandle handle = MessageReceiverBuilders
            .newBinaryMessageReceiverBuilder()
            .transform(Transformers.binaryToInteger())
            .bind(controlSession)
            .register("message/path", handler);

        verify(handler, timed()).onRegistered("message/path");

        final MessageToHandlerSender<Integer> sender = MessageSenderBuilders
            .newMessageSenderBuilder()
            .transform(Transformers.<Binary, Bytes>cast(Bytes.class))
            .transform(Transformers.integerToBinary())
            .buildToHandlerSender(session);

        sender.send("message/path", 5, sendCallback);

        verify(sendCallback, timed()).onComplete();

        verify(handler, timed()).onMessageReceived(
            "message/path",
            5,
            session.getSessionId(),
            Collections.<String, String>emptyMap());

        handle.close();
        verify(handler, timed()).onClose("message/path");
    }

    private VerificationWithTimeout timed() {
        return timeout(5000L);
    }
}

@@ -316,16 +316,56 @@
 ECTING;%0A
+import static java.math.BigInteger.TEN;%0A
 import s
@@ -554,24 +554,53 @@
 initMocks;%0A%0A
+import java.math.BigInteger;%0A
 import java.
@@ -1918,16 +1918,19 @@
 Handler%3C
+Big
 Integer%3E
@@ -3345,16 +3345,19 @@
 binaryTo
+Big
 Integer(
@@ -3543,16 +3543,19 @@
 rSender%3C
+Big
 Integer%3E
@@ -3731,17 +3731,20 @@
 formers.
-i
+bigI
 ntegerTo
@@ -3834,17 +3834,19 @@
 /path%22, 
-5
+TEN
 , sendCa
@@ -4000,17 +4000,19 @@
         
-5
+TEN
 ,%0A      

Update session to handler integration test to use a big integer.