// Path: src/main/java/org/pdfsam/eventstudio/util/RequireUtils.java
// public static void requireNotNull(Object victim) {
//     if (victim == null) {
//         throw new IllegalArgumentException("The input object cannot be null");
//     }
// }
// 
// Path: src/main/java/org/pdfsam/eventstudio/util/StringUtils.java
// public static String defaultString(String input, String defaultValue) {
//     return StringUtils.isBlank(input) ? defaultValue : input;
// }
// 
// Path: src/main/java/org/pdfsam/eventstudio/Annotations.java
// static class ReflectiveListenerDescriptor {
// 
//     private final EventListener listenerAnnotation;
//     private final Method method;
// 
//     public ReflectiveListenerDescriptor(EventListener listenerAnnotation, Method method) {
//         this.listenerAnnotation = listenerAnnotation;
//         this.method = method;
//     }
// 
//     public EventListener getListenerAnnotation() {
//         return listenerAnnotation;
//     }
// 
//     public Method getMethod() {
//         return method;
//     }
// }
// 
// Path: src/main/java/org/pdfsam/eventstudio/Annotations.java
// static class ReflectiveMetadata {
//     private String station;
//     private final Map<String, List<ReflectiveListenerDescriptor>> descriptors = new HashMap<>();
// 
//     private void put(String station, ReflectiveListenerDescriptor descriptor) {
//         List<ReflectiveListenerDescriptor> current = descriptors.computeIfAbsent(station, k -> new ArrayList<>());
//         current.add(descriptor);
//     }
// 
//     public String getStation() {
//         return station;
//     }
// 
//     public Map<String, List<ReflectiveListenerDescriptor>> getDescriptors() {
//         return descriptors;
//     }
// 
// }
// 
// Path: src/main/java/org/pdfsam/eventstudio/exception/EventStudioException.java
// public class EventStudioException extends RuntimeException {
// 
//     public EventStudioException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
//     public EventStudioException(String message) {
//         super(message);
//     }
// 
//     public EventStudioException(Throwable cause) {
//         super(cause);
//     }
// 
// }


import static org.pdfsam.eventstudio.util.RequireUtils.requireNotNull;
import static org.pdfsam.eventstudio.util.StringUtils.defaultString;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map.Entry;
import org.pdfsam.eventstudio.Annotations.ReflectiveListenerDescriptor;
import org.pdfsam.eventstudio.Annotations.ReflectiveMetadata;
import org.pdfsam.eventstudio.exception.EventStudioException;
/* 
 * This file is part of the EventStudio source code
 * Created on 10/nov/2013
 *  Copyright 2020 by Sober Lemur S.a.s di Vacondio Andrea (info@pdfsam.org).
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
package org.pdfsam.eventstudio;




/**
 * Default implementation of {@link EventStudio}. It doesn't enforce a Singleton pattern and it's up to the user to decide how to use it and how many EventStudio the application
 * needs. A singleton implementation with lazy initialization is provided with {@link org.pdfsam.eventstudio.StaticStudio} where the typical usage is:
 * 
 * <pre>
 * {@code
 * import static org.eventstudio.StaticStudio.eventStudio;
 * 
 * public class Foo{
 *     void doSomethingAndNotify(){
 *        .....
 *        eventStudio.broadcast(new ImFinished(), "station");
 *     } 
 * }
 * }
 * </pre>
 * <p>
 * <b>Hidden Station</b>: The hidden station is a pre-built station with <em>"hidden.station"</em> name that is used to hide the station abstraction. Helper method are provided by
 * {@link DefaultEventStudio} where the station name parameter is missing from the parameters list and the {@link DefaultEventStudio#HIDDEN_STATION} is used, providing a more
 * traditional event bus pub/sub pattern.
 * </p>
 * 
 * @author Andrea Vacondio
 * 
 */
public class DefaultEventStudio implements EventStudio {
    /**
     * A reserved station name that is used to hide the station abstraction. Using the provided helper methods the station concept remains totally hidden and {@link EventStudio}
     * can be used as a more traditional Event Bus with pub/sub pattern.
     */
    public static final String HIDDEN_STATION = "hidden.station";

    private Stations stations = new Stations();

    public <T> void add(Listener<T> listener, String station, int priority, ReferenceStrength strength) {
        stations.getStation(station).add(listener, priority, strength);
    }

    public <T> void add(Listener<T> listener, String station) {
        add(listener, station, 0, ReferenceStrength.STRONG);
    }

    public <T> void add(Class<T> eventClass, Listener<T> listener, String station) {
        add(eventClass, listener, station, 0, ReferenceStrength.STRONG);
    }

    public <T> void add(Class<T> eventClass, Listener<T> listener, String station, int priority,
            ReferenceStrength strength) {
        stations.getStation(station).add(eventClass, listener, priority, strength);
    }

    public void addAnnotatedListeners(Object bean) {
        try {
            ReflectiveMetadata metadata = Annotations.process(bean);
            for (Entry<String, List<ReflectiveListenerDescriptor>> current : metadata.getDescriptors().entrySet()) {
                String station = defaultString(metadata.getStation(), HIDDEN_STATION);
// Path: src/main/java/org/pdfsam/eventstudio/util/RequireUtils.java
// public static void requireNotNull(Object victim) {
//     if (victim == null) {
//         throw new IllegalArgumentException("The input object cannot be null");
//     }
// }
// 
// Path: src/main/java/org/pdfsam/eventstudio/util/StringUtils.java
// public static String defaultString(String input, String defaultValue) {
//     return StringUtils.isBlank(input) ? defaultValue : input;
// }
// 
// Path: src/main/java/org/pdfsam/eventstudio/Annotations.java
// static class ReflectiveListenerDescriptor {
// 
//     private final EventListener listenerAnnotation;
//     private final Method method;
// 
//     public ReflectiveListenerDescriptor(EventListener listenerAnnotation, Method method) {
//         this.listenerAnnotation = listenerAnnotation;
//         this.method = method;
//     }
// 
//     public EventListener getListenerAnnotation() {
//         return listenerAnnotation;
//     }
// 
//     public Method getMethod() {
//         return method;
//     }
// }
// 
// Path: src/main/java/org/pdfsam/eventstudio/Annotations.java
// static class ReflectiveMetadata {
//     private String station;
//     private final Map<String, List<ReflectiveListenerDescriptor>> descriptors = new HashMap<>();
// 
//     private void put(String station, ReflectiveListenerDescriptor descriptor) {
//         List<ReflectiveListenerDescriptor> current = descriptors.computeIfAbsent(station, k -> new ArrayList<>());
//         current.add(descriptor);
//     }
// 
//     public String getStation() {
//         return station;
//     }
// 
//     public Map<String, List<ReflectiveListenerDescriptor>> getDescriptors() {
//         return descriptors;
//     }
// 
// }
// 
// Path: src/main/java/org/pdfsam/eventstudio/exception/EventStudioException.java
// public class EventStudioException extends RuntimeException {
// 
//     public EventStudioException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
//     public EventStudioException(String message) {
//         super(message);
//     }
// 
//     public EventStudioException(Throwable cause) {
//         super(cause);
//     }
// 
// }


// Path: src/main/java/org/pdfsam/eventstudio/DefaultEventStudio.java
import static org.pdfsam.eventstudio.util.RequireUtils.requireNotNull;
import static org.pdfsam.eventstudio.util.StringUtils.defaultString;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map.Entry;
import org.pdfsam.eventstudio.Annotations.ReflectiveListenerDescriptor;
import org.pdfsam.eventstudio.Annotations.ReflectiveMetadata;
import org.pdfsam.eventstudio.exception.EventStudioException;

/* 
 * This file is part of the EventStudio source code
 * Created on 10/nov/2013
 *  Copyright 2020 by Sober Lemur S.a.s di Vacondio Andrea (info@pdfsam.org).
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
package org.pdfsam.eventstudio;




/**
 * Default implementation of {@link EventStudio}. It doesn't enforce a Singleton pattern and it's up to the user to decide how to use it and how many EventStudio the application
 * needs. A singleton implementation with lazy initialization is provided with {@link org.pdfsam.eventstudio.StaticStudio} where the typical usage is:
 * 
 * <pre>
 * {@code
 * import static org.eventstudio.StaticStudio.eventStudio;
 * 
 * public class Foo{
 *     void doSomethingAndNotify(){
 *        .....
 *        eventStudio.broadcast(new ImFinished(), "station");
 *     } 
 * }
 * }
 * </pre>
 * <p>
 * <b>Hidden Station</b>: The hidden station is a pre-built station with <em>"hidden.station"</em> name that is used to hide the station abstraction. Helper method are provided by
 * {@link DefaultEventStudio} where the station name parameter is missing from the parameters list and the {@link DefaultEventStudio#HIDDEN_STATION} is used, providing a more
 * traditional event bus pub/sub pattern.
 * </p>
 * 
 * @author Andrea Vacondio
 * 
 */
public class DefaultEventStudio implements EventStudio {
    /**
     * A reserved station name that is used to hide the station abstraction. Using the provided helper methods the station concept remains totally hidden and {@link EventStudio}
     * can be used as a more traditional Event Bus with pub/sub pattern.
     */
    public static final String HIDDEN_STATION = "hidden.station";

    private Stations stations = new Stations();

    public <T> void add(Listener<T> listener, String station, int priority, ReferenceStrength strength) {
        stations.getStation(station).add(listener, priority, strength);
    }

    public <T> void add(Listener<T> listener, String station) {
        add(listener, station, 0, ReferenceStrength.STRONG);
    }

    public <T> void add(Class<T> eventClass, Listener<T> listener, String station) {
        add(eventClass, listener, station, 0, ReferenceStrength.STRONG);
    }

    public <T> void add(Class<T> eventClass, Listener<T> listener, String station, int priority,
            ReferenceStrength strength) {
        stations.getStation(station).add(eventClass, listener, priority, strength);
    }

    public void addAnnotatedListeners(Object bean) {
        try {
            ReflectiveMetadata metadata = Annotations.process(bean);
            for (Entry<String, List<ReflectiveListenerDescriptor>> current : metadata.getDescriptors().entrySet()) {
                String station = defaultString(metadata.getStation(), HIDDEN_STATION);
                stations.getStation(defaultString(current.getKey(), station)).addAll(bean, current.getValue());