001package org.intellimate.izou.sdk.frameworks.presence.provider.template;
002
003import org.intellimate.izou.events.EventLifeCycle;
004import org.intellimate.izou.events.EventListenerModel;
005import org.intellimate.izou.events.EventModel;
006import org.intellimate.izou.identification.IdentificationManager;
007import org.intellimate.izou.sdk.Context;
008import org.intellimate.izou.sdk.activator.Activator;
009import org.intellimate.izou.sdk.events.CommonEvents;
010import org.intellimate.izou.sdk.events.Event;
011import org.intellimate.izou.sdk.frameworks.presence.events.LeavingEvent;
012import org.intellimate.izou.sdk.frameworks.presence.events.PresenceEvent;
013import org.intellimate.izou.sdk.frameworks.presence.resources.PresenceResourceHelper;
014import org.intellimate.izou.sdk.util.ResourceUser;
015
016import java.time.LocalDateTime;
017import java.time.temporal.ChronoUnit;
018import java.util.ArrayList;
019import java.util.Arrays;
020import java.util.List;
021import java.util.Optional;
022import java.util.concurrent.ExecutionException;
023import java.util.concurrent.TimeUnit;
024import java.util.concurrent.TimeoutException;
025
026/**
027 * the base class for all presence-things that have no CONSTANT information (for example a motion-sensor).
028 * if it is the first encountering with the user since he was discovered (and at least an hour has passed),
029 * the event also contains CommonEvents.Response.Major_Response as a descriptor.
030 * @author LeanderK
031 * @version 1.0
032 */
033public abstract class PresenceNonConstant extends Activator implements PresenceResourceHelper, EventListenerModel, ResourceUser {
034    private boolean present;
035    private boolean strictPresent = false;
036    private LocalDateTime lastSeen = LocalDateTime.now();
037    private final boolean strict;
038    private final boolean fireUnknownIfNotPresent;
039
040    /**
041     * @deprecated addResponseDescriptors not used anymore
042     */
043    @Deprecated
044    public PresenceNonConstant(Context context, String ID, boolean strict, boolean fireUnknownIfNotPresent,
045                                                                                        boolean addResponseDescriptors) {
046       this(context, ID, strict, fireUnknownIfNotPresent);
047    }
048    @SuppressWarnings("unused")
049    public PresenceNonConstant(Context context, String ID, boolean strict, boolean fireUnknownIfNotPresent) {
050        super(context, ID);
051        this.strict = strict;
052        this.fireUnknownIfNotPresent = fireUnknownIfNotPresent;
053        getContext().getEvents().registerEventListener(Arrays.asList(LeavingEvent.ID, PresenceEvent.ID), this);
054        try {
055            present = getIsPresent(false, true)
056                    .get(1, TimeUnit.SECONDS);
057        } catch (InterruptedException | ExecutionException | TimeoutException e) {
058            present = true;
059        }
060    }
061
062    /**
063     * call this method when you have encountered the user
064     */
065    @SuppressWarnings("unused")
066    public void userEncountered() {
067        List<String> descriptors = new ArrayList<>();
068        /*
069        if (strict && ((!present && !fireUnknownIfNotPresent)|| !strictPresent) && addResponseDescriptors) {
070            if (lastSeen.until(LocalDateTime.now(), ChronoUnit.MINUTES) > getMajorMinuteThresholdNotPresent()) {
071                descriptors.add(CommonEvents.Response.MAJOR_RESPONSE_DESCRIPTOR);
072            } else if (lastSeen.until(LocalDateTime.now(), ChronoUnit.MINUTES) > getMinorMinuteThresholdNotPresent()) {
073                descriptors.add(CommonEvents.Response.MINOR_RESPONSE_DESCRIPTOR);
074            }
075        } else if (present && strict && addResponseDescriptors) {
076            if (lastSeen.until(LocalDateTime.now(), ChronoUnit.MINUTES) > getMajorMinuteThresholdPresent()) {
077                descriptors.add(CommonEvents.Response.MAJOR_RESPONSE_DESCRIPTOR);
078            } else if (lastSeen.until(LocalDateTime.now(), ChronoUnit.MINUTES) > getMinorMinuteThresholdNotPresent()) {
079                descriptors.add(CommonEvents.Response.MINOR_RESPONSE_DESCRIPTOR);
080            }
081        }*/
082        descriptors.add(CommonEvents.Descriptors.NOT_INTERRUPT);
083        boolean known = !fireUnknownIfNotPresent || present;
084        boolean firstPresent = (!strict && !present) || (strict && !strictPresent);
085        long lastSeen = this.lastSeen.until(LocalDateTime.now(), ChronoUnit.SECONDS);
086        Optional<Event> presenceEvent = IdentificationManager.getInstance()
087                .getIdentification(this)
088                .flatMap(id -> PresenceEvent.createPresenceEvent(id, strict, known, firstPresent, descriptors, lastSeen))
089                .map(event -> event.addEventLifeCycleListener(EventLifeCycle.APPROVED, lifeCycle -> {
090                    if (known) {
091                        this.lastSeen = LocalDateTime.now();
092                        if (strict)
093                            this.strictPresent = true;
094                        present = true;
095                    }
096                }));
097        if (!presenceEvent.isPresent()) {
098            error("unable to create PresenceEvent");
099        } else {
100            fire(presenceEvent.get(), 5);
101        }
102    }
103
104
105    /**
106     * Invoked when an activator-event occurs.
107     *
108     * @param event an instance of Event
109     */
110    @Override
111    public void eventFired(EventModel event) {
112        if (event.containsDescriptor(LeavingEvent.ID) || event.containsDescriptor(PresenceEvent.ID)) {
113            if (event.containsDescriptor(LeavingEvent.ID)) {
114                if (event.containsDescriptor(LeavingEvent.GENERAL_DESCRIPTOR)) {
115                    present = false;
116                    strictPresent = false;
117                } else if (event.containsDescriptor(LeavingEvent.STRICT_DESCRIPTOR)) {
118                    nonStrictAvailable().thenAccept(available -> {
119                        if (!available)
120                            present = false;
121                        strictPresent = false;
122                    });
123                }
124            } else {
125                present = true;
126                if (event.containsDescriptor(PresenceEvent.STRICT_DESCRIPTOR))
127                    strictPresent = true;
128            }
129            if (event.containsDescriptor(PresenceEvent.STRICT_DESCRIPTOR))
130                lastSeen = LocalDateTime.now();
131        }
132    }
133}