001package org.intellimate.izou.sdk.events;
002
003import org.intellimate.izou.events.EventBehaviourControllerModel;
004import org.intellimate.izou.events.EventLifeCycle;
005import org.intellimate.izou.events.EventModel;
006import org.intellimate.izou.identification.Identification;
007import org.intellimate.izou.resource.ListResourceProvider;
008import org.intellimate.izou.resource.ResourceModel;
009import org.intellimate.izou.sdk.resource.*;
010
011import java.util.*;
012import java.util.concurrent.ConcurrentHashMap;
013import java.util.function.Consumer;
014
015/**
016 * This class represents an Event.
017 * This class is immutable! for every change it will return an new instance!
018 */
019public class Event implements EventModel<Event> {
020    private final String type;
021    private final Identification source;
022    private final List<String> descriptors;
023    private final ListResourceProvider listResourceContainer;
024    private final EventBehaviourController eventBehaviourController;
025    private final ConcurrentHashMap<EventLifeCycle, List<Consumer<EventLifeCycle>>> lifeCycleListeners = new ConcurrentHashMap<>();
026
027    /**
028     * Creates a new Event Object
029     * @param type the Type of the Event, try to use the predefined Event types
030     * @param source the source of the Event, most likely a this reference.
031     * @param descriptors the descriptors to initialize the Event with
032     * @throws IllegalArgumentException if one of the Arguments is null or empty
033     */
034    protected Event(String type, Identification source, List<String> descriptors) throws IllegalArgumentException {
035        if(type == null || type.isEmpty()) throw new IllegalArgumentException("illegal type");
036        if(source == null) throw new IllegalArgumentException("source is null");
037        this.type = type;
038        this.source = source;
039        this.descriptors = Collections.unmodifiableList(descriptors);
040        listResourceContainer = new ListResourceProviderImpl();
041        eventBehaviourController = new EventBehaviourController();
042    }
043
044    /**
045     * Creates a new Event Object
046     * @param type the Type of the Event, try to use the predefined Event types
047     * @param source the source of the Event, most likely a this reference.
048     * @param listResourceContainer the ResourceContainer
049     * @param descriptors the descriptors to initialize the Event with
050     * @param eventBehaviourController the Controller of the Event
051     * @throws IllegalArgumentException if one of the Arguments is null or empty
052     */
053    protected Event(String type, Identification source, ListResourceProvider listResourceContainer, List<String> descriptors,
054                    EventBehaviourController eventBehaviourController)throws IllegalArgumentException {
055        if(type == null || type.isEmpty()) throw new IllegalArgumentException("illegal type");
056        if(source == null) throw new IllegalArgumentException("source is null");
057        this.type = type;
058        this.source = source;
059        this.descriptors = Collections.unmodifiableList(new ArrayList<>(descriptors));
060        this.listResourceContainer = listResourceContainer;
061        this.eventBehaviourController = eventBehaviourController;
062    }
063
064    /**
065     * Creates a new Event Object
066     * @param type the Type of the Event, try to use the predefined Event types
067     * @param source the source of the Event, most likely a this reference.
068     * @return an Optional, that may be empty if type is null or empty or source is null
069     */
070    public static Optional<Event> createEvent(String type, Identification source) {
071        try {
072            return Optional.of(new Event(type, source, new ArrayList<>()));
073        } catch (IllegalArgumentException e) {
074            return Optional.empty();
075        }
076    }
077
078    /**
079     * Creates a new Event Object
080     * @param type the Type of the Event, try to use the predefined Event types
081     * @param source the source of the Event, most likely a this reference.
082     * @param descriptors the descriptors
083     * @return an Optional, that may be empty if type is null or empty or source is null
084     */
085    public static Optional<Event> createEvent(String type, Identification source, List<String> descriptors) {
086        try {
087            return Optional.of(new Event(type, source, descriptors));
088        } catch (IllegalArgumentException e) {
089            return Optional.empty();
090        }
091    }
092
093    /**
094     * The ID of the Event.
095     * It describes the Type of the Event.
096     * @return A String containing an ID
097     */
098    @Override
099    public String getID() {
100        return type;
101    }
102
103    /**
104     * The type of the Event.
105     * It describes the Type of the Event.
106     * @return A String containing an ID
107     */
108    @Override
109    public String getType() {
110        return type;
111    }
112
113    /**
114     * returns the Source of the Event, e.g. the object who fired it.
115     * @return an identifiable
116     */
117    @Override
118    public Identification getSource() {
119        return source;
120    }
121
122    /**
123     * returns all the Resources the Event currently has
124     * @return an instance of ListResourceContainer
125     */
126    @Override
127    public ListResourceProvider getListResourceContainer() {
128        return listResourceContainer;
129    }
130
131    /**
132     * adds a Resource to the Container
133     * @param resource an instance of the resource to add
134     * @return the resulting Event (which is the same instance)
135     */
136    @Override
137    public Event addResource(ResourceModel resource) {
138        listResourceContainer.addResource(resource);
139        return this;
140    }
141
142    /**
143     * adds a List of Resources to the Container
144     * @param resources a list containing all the resources
145     */
146    @Override
147    public Event addResources(List<ResourceModel> resources) {
148        listResourceContainer.addResource(resources);
149        return this;
150    }
151
152    /**
153     * returns a List containing all the Descriptors.
154     * @return a List containing the Descriptors
155     */
156    @Override
157    public List<String> getDescriptors() {
158        return descriptors;
159    }
160
161    /**
162     * returns a List containing all the Descriptors and the type.
163     * @return a List containing the Descriptors
164     */
165    @Override
166    public List<String> getAllInformations() {
167        ArrayList<String> strings = new ArrayList<>(descriptors);
168        strings.add(type);
169        return strings;
170    }
171
172    /**
173     * sets the Descriptors (but not the Event-Type).
174     * <p>
175     * Replaces all existing descriptors.
176     * Since Event is immutable, it will create a new Instance.
177     * </p>
178     * @param descriptors a List containing all the Descriptors
179     * @return the resulting Event (which is the same instance)
180     */
181    public Event setDescriptors(List<String> descriptors) {
182        return new Event(getType(), getSource(), descriptors);
183    }
184
185    /**
186     * sets the Descriptors (but not the Event-Type).
187     * @param descriptor a String describing the Event.
188     * @return the resulting Event (which is the same instance)
189     */
190    public Event addDescriptor(String descriptor) {
191        List<String> newDescriptors = new ArrayList<>();
192        newDescriptors.addAll(descriptors);
193        newDescriptors.add(descriptor);
194        return new Event(getType(), getSource(), newDescriptors);
195    }
196
197
198    /**
199     * replaces the Descriptors
200     * @param descriptors a list containing the Descriptors.
201     * @return the resulting Event (which is the same instance)
202     */
203    public Event replaceDescriptors(List<String> descriptors) {
204        return new Event(getType(), getSource(), descriptors);
205    }
206
207    /**
208     * returns whether the event contains the specific descriptor.
209     * this method also checks whether it matches the type.
210     * @param descriptor a String with the ID of the Descriptor
211     * @return boolean when the Event contains the descriptor, false when not.
212     */
213    @Override
214    public boolean containsDescriptor(String descriptor) {
215        return descriptors.contains(descriptor) || type.equals(descriptor);
216    }
217
218    /**
219     * returns the associated EventBehaviourController
220     * @return an instance of EventBehaviourController
221     */
222    @Override
223    public EventBehaviourControllerModel getEventBehaviourController() {
224        return eventBehaviourController;
225    }
226
227    @Override
228    public void lifecycleCallback(EventLifeCycle eventLifeCycle) {
229        lifeCycleListeners.getOrDefault(eventLifeCycle, new LinkedList<>()).stream()
230                .forEach(eventLifeCycleConsumer -> eventLifeCycleConsumer.accept(eventLifeCycle));
231    }
232
233    /**
234     * adds the Consumer to the specified EventLifeCycle.
235     * In its current implementation the invocation of the Callback method is parallel, but the notificaton of the listners not.
236     * @param eventLifeCycle the EventLifeCycle to target
237     * @param cycleCallback the callback
238     */
239    @SuppressWarnings("unused")
240    public Event addEventLifeCycleListener(EventLifeCycle eventLifeCycle, Consumer<EventLifeCycle> cycleCallback) {
241        lifeCycleListeners.compute(eventLifeCycle, (unused, list) -> {
242            if (list == null)
243                list = new ArrayList<>();
244            list.add(cycleCallback);
245            return list;
246        });
247        return this;
248    }
249
250    @Override
251    public String toString() {
252        return "Event{" +
253                "type='" + type + '\'' +
254                ", source=" + source +
255                ", descriptors=" + descriptors +
256                ", listResourceContainer=" + listResourceContainer +
257                '}';
258    }
259}