/*
 *  @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 net.ranides.assira.time.TimeUtils;
import static org.junit.Assert.*;
import org.junit.Test;


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

    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 testJoin() {
        HitMap hits = new HitMap();

        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 = new EventReactor("name", 32, 1000, joiner).start();

        main.addEventListener(Event.class, hits.new HitListener<Event>("global") );
        main.addEventListener(TIOEvent.class, hits.new HitListener<TIOEvent>("io") );
        main.addEventListener(TReadEvent.class, hits.new HitListener<TReadEvent>("read") );
        main.addEventListener(TWriteEvent.class, hits.new HitListener<TWriteEvent>("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 TWriteEvent());
        TimeUtils.sleep(50);
        main.signalEvent(new TWriteEvent());
        TimeUtils.sleep(50);
        main.signalEvent(new TReadEvent());
        TimeUtils.sleep(50);
        main.signalEvent(new TReadEvent());
        TimeUtils.sleep(50);
        main.signalEvent(new TReadEvent());
        TimeUtils.sleep(50);
        main.signalEvent(new Event(){});
        TimeUtils.sleep(50);
        main.signalEvent(new TReadEvent());
        TimeUtils.sleep(50);
        main.signalEvent(new TReadEvent());
        TimeUtils.sleep(50);
        
        main.stop();
        TimeUtils.sleep(50);

        assertEquals(SetUtils.asHashSet("global", "io", "write", "read", "exit", "shutdown"), hits.keySet());
        
        assertEquals(ArrayUtils.asList(0, 3, 6, 9, 12, 15, 16, 19, 22, 24, 26), hits.get("global"));
        assertEquals(ArrayUtils.asList(1, 4, 7, 10, 13, 17, 20), hits.get("io"));
        assertEquals(ArrayUtils.asList(2, 5), hits.get("write"));
        assertEquals(ArrayUtils.asList(8, 11, 14, 18, 21), hits.get("read"));
        assertEquals(ArrayUtils.asList(23), hits.get("exit"));
        assertEquals(ArrayUtils.asList(25), hits.get("shutdown"));
        
        

    }

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

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

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