
package forager.server;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.nio.channels.SocketChannel;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import galileo.event.Event;
import galileo.event.EventHandler;
import galileo.event.EventTypeMap;
import galileo.net.GalileoMessage;
import galileo.net.MessageListener;
import galileo.net.NetworkDestination;
import galileo.serialization.SerializationInputStream;
import galileo.serialization.Serializer;

public class EventMapper implements MessageListener {

    private static final Logger logger = Logger.getLogger("galileo");

    private Class<?> handlerClass;
    private Object handlerObject;

    private EventMap eventMap;

    private Map<Class<?>, Method> classToMethod = new HashMap<>();

    public EventMapper(Object handlerObject, EventMap eventMap) {
        this.handlerClass = handlerObject.getClass();
        this.handlerObject = handlerObject;
        this.eventMap = eventMap;
        System.out.println(eventMap.getClass(1));
    }

    public void linkEventHandlers() {
        for (Method m : handlerClass.getMethods()) {
            for (Annotation a : m.getAnnotations()) {
                if (a.annotationType().equals(EventHandler.class)) {
                    /* This method is an event handler */
                    Class<?>[] params = m.getParameterTypes();
                    Class<?> eventClass = extractEventClass(params);
                    logger.log(Level.INFO,
                            "Linking handler method [{0}] to class [{1}]",
                            new Object[] { m.getName(), eventClass.getName() });
                    classToMethod.put(eventClass, m);
                    break;
                }
            }
        }
    }

    private Class<?> extractEventClass(Class<?>[] parameters) {
        if (parameters.length <= 0) {
            //TODO throw new exception
        }

        List<Class<?>> interfaces
            = Arrays.asList(parameters[0].getInterfaces());
        if (interfaces.contains(Event.class) == false) {
            //TODO throw error
        }

        return parameters[0];
        //classToMethod.put(parameters[0], m);
    }


    @Override
    public void onConnect(NetworkDestination endpoint) {

    }

    @Override
    public void onDisconnect(NetworkDestination endpoint) {

    }

    @Override
    public void onMessage(GalileoMessage message) {
        ByteArrayInputStream byteIn
            = new ByteArrayInputStream(message.getPayload());
        BufferedInputStream buffIn = new BufferedInputStream(byteIn);
        SerializationInputStream in = new SerializationInputStream(buffIn);

        try {
            int type = in.readInt();
            Class<? extends Event> clazz = eventMap.getClass(type);
            if (clazz == null) {
                logger.log(Level.WARNING,
                        "Class mapping for event type {0} not found!", type);
                in.close();
                return;
            }
            Event e = Serializer.deserializeFromStream(clazz, in);
            Method m = classToMethod.get(clazz);
            m.invoke(handlerObject, e);
            in.close();
        } catch (Exception e) {
            logger.log(Level.WARNING, "Error handling incoming message", e);
        }
    }
}

@@ -324,24 +324,168 @@
 va.util.Map;
+%0A%0Aimport java.util.concurrent.BlockingQueue;%0Aimport java.util.concurrent.ConcurrentLinkedQueue;%0Aimport java.util.concurrent.LinkedBlockingQueue;
 %0Aimport java
@@ -1136,24 +1136,129 @@
 shMap%3C%3E();%0A%0A
+    private ConcurrentLinkedQueue%3CGalileoMessage%3E messageQueue%0A        = new ConcurrentLinkedQueue%3C%3E();%0A%0A
     public E
@@ -2886,24 +2886,63 @@
  message) %7B%0A
+        messageQueue.offer(message);%0A//
         Byte
@@ -2965,16 +2965,18 @@
  byteIn%0A
+//
         
@@ -3025,24 +3025,26 @@
 Payload());%0A
+//
         Buff
@@ -3097,24 +3097,26 @@
 am(byteIn);%0A
+//
         Seri
@@ -3179,17 +3179,21 @@
 uffIn);%0A
-%0A
+//%0A//
         
@@ -3198,16 +3198,18 @@
   try %7B%0A
+//
         
@@ -3233,24 +3233,26 @@
 .readInt();%0A
+//
             
@@ -3303,24 +3303,26 @@
 lass(type);%0A
+//
             
@@ -3338,24 +3338,26 @@
  == null) %7B%0A
+//
             
@@ -3386,16 +3386,18 @@
 ARNING,%0A
+//
         
@@ -3462,24 +3462,26 @@
 d!%22, type);%0A
+//
             
@@ -3488,32 +3488,34 @@
     in.close();%0A
+//
                 
@@ -3522,16 +3522,18 @@
 return;%0A
+//
         
@@ -3530,32 +3530,34 @@
 //            %7D%0A
+//
             Even
@@ -3607,16 +3607,18 @@
 z, in);%0A
+//
         
@@ -3658,16 +3658,18 @@
 clazz);%0A
+//
         
@@ -3696,24 +3696,26 @@
 Object, e);%0A
+//
             
@@ -3722,24 +3722,26 @@
 in.close();%0A
+//
         %7D ca
@@ -3756,24 +3756,26 @@
 eption e) %7B%0A
+//
             
@@ -3839,16 +3839,18 @@
 e%22, e);%0A
+//
         

Move incoming messages to a separate queue