/*
 * @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 EventProactorTest {
    
    @Test
    public void testPropagation() throws InterruptedException {
        EventHitMap hits = new EventHitMap();
        EventProactor unknown = EventProactor.newInstance("unknown", 2);
        EventProactor main = EventProactor.newInstance("name", 10);

        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(FloodEvent.class, hits.listener("flood") );
        main.addEventListener(Events.Shutdown.class, hits.listener("shutdown") );
        main.addEventListener(Events.Stop.class, hits.listener("exit") );

        assertEquals("EventProactor<name:0>", main.toString());
        
        // we consume thread, but not lock handler
        Thread.sleep(25);


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

        for(int i=0; i<100; i++) {
            main.signalEvent(new FloodEvent());
        }
        
        assertEquals("name", main.name());
        assertEquals("EventProactor<name:10>", main.toString());

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

        assertEquals(Arrays.asList("exit", "flood","global", "io", "read", "shutdown" ,"write"), hits.names());
        
        assertEquals(108, hits.values("global").size());
        assertEquals(100, hits.values("flood").size());
        assertEquals(2, hits.values("io").size());
        assertEquals(1, hits.values("write").size());
        assertEquals(1, hits.values("read").size());
        assertEquals(3, hits.values("exit").size());
        assertEquals(1, hits.values("shutdown").size());

        unknown.dispose();
    }
    
    @Test
    public void testStop() throws InterruptedException {
        EventHitMap hits = new EventHitMap();
        EventProactor unknown = EventProactor.newInstance("unknown", 32);
        EventProactor main = EventProactor.newInstance("name", 32);
        
        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();
        
        // kolejność komunikatów jest nieokreślona
        assertEquals(Arrays.asList("exit", "global", "shutdown"), hits.names());
        assertEquals(4, hits.values("global").size());
        assertEquals(2, hits.values("exit").size());
        assertEquals(1, hits.values("shutdown").size());

        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 { }

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