/*
 * @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 org.junit.Test;
import static org.junit.Assert.*;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class EventReactorTest {
    
    @Test
    public void testPropagation() {
        EventHitMap hits = new EventHitMap();
        EventReactor unknown = EventReactor.newInstance("unknown", 32, 1000);
        EventReactor main = EventReactor.newInstance("name", 32, 1000);

        main.addEventListener(Event.class, hits.listener("global") );
        main.addEventListener(IOEvent.class, hits.listener("io") );
        main.addEventListener(ReadEvent.class, hits.listener("read") );
        main.addEventListener(WriteEvent.class, hits.listener("write") );
        main.addEventListener(Events.Shutdown.class, hits.listener("shutdown") );
        main.addEventListener(Events.Stop.class, hits.listener("exit") );

        main.signalEvent(new WriteEvent());
        main.signalEvent(new ReadEvent());
        main.signalEvent(new Event(){});
        main.signalEvent(Events.stop(unknown));
        main.signalEvent(Events.stop(main) );
        
        assertEquals("name", main.name());
        assertEquals("EventReactor<name>", main.toString());

        main.stop();

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

        unknown.dispose();
    }
    
    @Test
    public void testPropagationNoLimits() {
        EventHitMap hits = new EventHitMap();
        EventReactor unknown = EventReactor.newInstance("unknown");
        EventReactor main = EventReactor.newInstance("name");

        main.addEventListener(Event.class, hits.listener("global") );
        main.addEventListener(IOEvent.class, hits.listener("io") );
        main.addEventListener(ReadEvent.class, hits.listener("read") );
        main.addEventListener(WriteEvent.class, hits.listener("write") );
        main.addEventListener(Events.Shutdown.class, hits.listener("shutdown") );
        main.addEventListener(Events.Stop.class, hits.listener("exit") );

        main.signalEvent(new WriteEvent());
        main.signalEvent(new ReadEvent());
        main.signalEvent(new Event(){});
        main.signalEvent(Events.stop(unknown));
        main.signalEvent(Events.stop(main) );

        main.stop();

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

        unknown.dispose();
    }

    @Test
    public void testStop() throws InterruptedException {
        EventHitMap hits = new EventHitMap();
        EventReactor unknown = EventReactor.newInstance("unknown", 32, 1000);
        EventReactor main = EventReactor.newInstance("name", 32, 1000);

        main.addEventListener(Event.class, hits.listener("global") );
        main.addEventListener(Events.Shutdown.class, hits.listener("shutdown") );
        main.addEventListener(Events.Stop.class, hits.listener("exit") );

        main.signalEvent(Events.stop(unknown) );

        main.stop();

        assertEquals(Arrays.asList("exit", "global", "shutdown"), hits.names());
        assertEquals(Arrays.asList(0,2,4,6), hits.values("global"));
        assertEquals(Arrays.asList(1,3), hits.values("exit"));
        assertEquals(Arrays.asList(5), hits.values("shutdown"));

        unknown.dispose();
        
        // sprawdzamy, czy wytrzymamy podwójne zatrzymanie
        Thread.sleep(100);
        main.stop();
        unknown.dispose();
    }

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

    @SuppressWarnings("PMD")
    class ReadEvent extends IOEvent { }

    @SuppressWarnings("PMD")
    class WriteEvent extends IOEvent { }
    
}
