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

package net.ranides.assira.events;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import net.ranides.assira.annotations.Meta;
import net.ranides.assira.collection.SetUtils;
import net.ranides.assira.collection.map.LazyMap;
import net.ranides.assira.text.LexicalCast;
import net.ranides.assira.trace.ExceptionInspector;
import net.ranides.assira.trace.LoggerUtils;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 *
 * @author ranides
 */
public class ReflectEventListenerTest {

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

        @Override
        public List<Integer> apply(String source) {
            return new LinkedList<>();
        }
        public void add(String name) {
            get(name).add(counter++);
        }
    };
    
    static class IOEvent implements Event { } // NOPMD
    static class RIOEvent extends IOEvent { } // NOPMD
    static class WIOEvent extends IOEvent { } // NOPMD
    
    public ReflectEventListenerTest() {
        LoggerUtils.initTest();
    }

    @Test
    public void testDelegator() {
        final HitMap hits = new HitMap();

        @SuppressWarnings("PMD")
        Object delegator = new Object(){
            @Meta.EventHandler
            private void onEvent(Event event) {
                hits.add("event");
            }
            @Meta.EventHandler
            private void onEvent(IOEvent event) {
                hits.add("io");
            }
            @Meta.EventHandler
            private void onEvent(WIOEvent event) {
                hits.add("write");
            }
        };
        
        EventRouter router = new EventDispatcher();
        router.addEventListener(Event.class, new ReflectEventListener<>(delegator));
        
        router.signalEvent(new IOEvent());
        router.signalEvent(new WIOEvent());
        router.signalEvent(new RIOEvent());
        
        LoggerUtils.dump("%s\n",LexicalCast.toJSON(hits));
        
        assertEquals(SetUtils.asHashSet("event","io","write"), hits.keySet());
        
        assertEquals(3, hits.get("event").size());
        assertEquals(3, hits.get("io").size());
        assertEquals(1, hits.get("write").size());
    }
    
    @Test
    public void testErrorHandler() {
        final HitMap hits = new HitMap();

        @SuppressWarnings("PMD")
        Object delegator = new Object(){
            @Meta.EventHandler
            private void onEvent(Event event) {
                hits.add("event");
            }
            @Meta.EventHandler
            private void onEvent(RIOEvent event) {
                throw ExceptionInspector.rethrow(new IOException("rio"));
            }
            @Meta.EventHandler
            private void onEvent(WIOEvent event) {
                throw new IllegalArgumentException("");
            }
            @Meta.ErrorHandler
            private void onError(Exception cause) {
                hits.add("ex!");
            }
            @Meta.ErrorHandler
            private void onError(IllegalArgumentException cause) {
                hits.add("ia!");
            }
            @Meta.ErrorHandler 
            private void onError(IOException cause) {
                hits.add("io!");
            }
        };
        
        EventRouter router = new EventDispatcher();
        router.addEventListener(Event.class, new ReflectEventListener<>(delegator));
        
        router.signalEvent(new IOEvent());
        router.signalEvent(new WIOEvent());
        router.signalEvent(new RIOEvent());
        
        LoggerUtils.dump("%s\n",LexicalCast.toJSON(hits));
        
        assertEquals(SetUtils.asHashSet("event","io!","ex!", "ia!"), hits.keySet());
        
        assertEquals(3, hits.get("event").size());
        assertEquals(1, hits.get("io!").size());
        assertEquals(2, hits.get("ex!").size());
        assertEquals(1, hits.get("ia!").size());

    }
}
