/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.events;

import java.util.Arrays;
import net.ranides.assira.events.mockup.EventHitMap;
import net.ranides.assira.trace.ExceptionUtils;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class EventJoinerTest {
    
    @Test
    public void testJoin() {
        EventHitMap hits = new EventHitMap();

        EventJoiner joiner = new EventJoiner() {
            @Override
            public boolean isJoinable(Event first, Event second) {
                return first!=null && second!=null && first.getClass().equals(second.getClass());
            }
            @Override
            public Event join(Event first, Event second) {
                return second;
            }
        };

        EventReactor main = EventReactor.newInstance("name", joiner);

		main.addEventListener(Event.class, e -> sleep(200));
        main.addEventListener(Event.class, hits.listener("global") );
        main.addEventListener(TIOEvent.class, hits.listener("io") );
        main.addEventListener(TReadEvent.class, hits.listener("read") );
        main.addEventListener(TWriteEvent.class, hits.listener("write") );
        main.addEventListener(Events.Shutdown.class, hits.listener("shutdown") );
        main.addEventListener(Events.Stop.class, hits.listener("exit") );

        // handle 0
        main.signalEvent(new Event(){});
        // join (ignore)
        main.signalEvent(new TWriteEvent());
        // join (handle) 1 2 3
        main.signalEvent(new TWriteEvent());
        // join (ignore)
        main.signalEvent(new TReadEvent());
        // join (ignore)
        main.signalEvent(new TReadEvent());
        // join (handle) 4 5 6
        main.signalEvent(new TReadEvent());
        // handle 7
        main.signalEvent(new Event(){});
        // join (ignore) 
        main.signalEvent(new TReadEvent());
        // join (handle) 8 9 10
        main.signalEvent(new TReadEvent());
        
        main.stop();
        sleep(100);

        assertEquals(Arrays.asList("exit", "global", "io", "read", "shutdown", "write"), hits.names());
        
//		System.out.printf("global   = %s%n", hits.values("global"));
//		System.out.printf("io       = %s%n", hits.values("io"));
//		System.out.printf("write    = %s%n", hits.values("write"));
//		System.out.printf("read     = %s%n", hits.values("read"));
//		System.out.printf("exit     = %s%n", hits.values("exit"));
//		System.out.printf("shutdown = %s%n", hits.values("shutdown"));

        assertEquals(Arrays.asList(0, 1, 4, 7, 8, 11, 13, 15), hits.values("global"));
        assertEquals(Arrays.asList(2, 5, 9), hits.values("io"));
        assertEquals(Arrays.asList(3), hits.values("write"));
        assertEquals(Arrays.asList(6, 10), hits.values("read"));
        assertEquals(Arrays.asList(12), hits.values("exit"));
        assertEquals(Arrays.asList(14), hits.values("shutdown"));
    }

    @SuppressWarnings("PMD")
    class TIOEvent implements Event { }

    @SuppressWarnings("PMD")
    class TReadEvent extends TIOEvent { }

    @SuppressWarnings("PMD")
    class TWriteEvent extends TIOEvent { }
    
	private static void sleep(long ms) {
		try {
			Thread.sleep(ms);
		} catch (InterruptedException cause) {
			throw ExceptionUtils.rethrow(cause);
		}
	}
}
