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

import java.util.LinkedList;
import java.util.List;
import net.ranides.assira.collection.ArrayUtils;
import net.ranides.assira.collection.SetUtils;
import net.ranides.assira.collection.map.LazyMap;
import static org.junit.Assert.*;
import org.junit.Test;


/**
 *
 * @author ranides
 */
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
public class EventReactorTest {

    public EventReactorTest() {
    }

    private static class HitMap extends LazyMap<String, List<Integer>>  {
        private int counter = 0;

        @Override
        public List<Integer> apply(String source) {
            return new LinkedList<>();
        }

        public class HitListener<T extends Event> implements EventListener<T> {

            private final String name;

            public HitListener(String name) {
                this.name = name;
            }

            @Override
            public void handleEvent(T event) {
                get( name ).add(counter++);
            }
        }

    };

    @Test
    public void testPropagation() {
        HitMap hits = new HitMap();
        EventReactor unknown = EventReactor.newInstance("unknown", 32, 1000);
        EventReactor main = EventReactor.newInstance("name", 32, 1000);

        main.addEventListener(Event.class, hits.new HitListener<Event>("global") );
        main.addEventListener(IOEvent.class, hits.new HitListener<IOEvent>("io") );
        main.addEventListener(ReadEvent.class, hits.new HitListener<ReadEvent>("read") );
        main.addEventListener(WriteEvent.class, hits.new HitListener<WriteEvent>("write") );
        main.addEventListener(CoreEvent.Shutdown.class, hits.new HitListener<CoreEvent.Shutdown>("shutdown") );
        main.addEventListener(CoreEvent.Stop.class, hits.new HitListener<CoreEvent.Stop>("exit") );

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

        main.stop();

        assertEquals(SetUtils.asHashSet("global", "io", "write", "read", "exit", "shutdown"), hits.keySet());
        assertEquals(ArrayUtils.asList(0,3,6,7,9,11,13), hits.get("global"));
        assertEquals(ArrayUtils.asList(1,4), hits.get("io"));
        assertEquals(ArrayUtils.asList(2), hits.get("write"));
        assertEquals(ArrayUtils.asList(5), hits.get("read"));
        assertEquals(ArrayUtils.asList(8,10), hits.get("exit"));
        assertEquals(ArrayUtils.asList(12), hits.get("shutdown"));

        unknown.dispose();
    }

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

        main.addEventListener(Event.class, hits.new HitListener<Event>("global") );
        main.addEventListener(CoreEvent.Shutdown.class, hits.new HitListener<CoreEvent.Shutdown>("shutdown") );
        main.addEventListener(CoreEvent.Stop.class, hits.new HitListener<CoreEvent.Stop>("exit") );

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

        main.stop();

        assertEquals(SetUtils.asHashSet("global", "exit", "shutdown"), hits.keySet());
        assertEquals(ArrayUtils.asList(0,2,4,6), hits.get("global"));
        assertEquals(ArrayUtils.asList(1,3), hits.get("exit"));
        assertEquals(ArrayUtils.asList(5), hits.get("shutdown"));

        unknown.dispose();
    }

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

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

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