001package org.intellimate.izou.sdk.frameworks.presence.provider.template; 002 003import org.intellimate.izou.events.EventModel; 004import org.intellimate.izou.sdk.Context; 005import org.intellimate.izou.sdk.events.EventsController; 006import org.intellimate.izou.sdk.frameworks.presence.provider.Presence; 007import org.intellimate.izou.sdk.frameworks.presence.provider.PresenceHelper; 008import org.intellimate.izou.sdk.frameworks.presence.provider.PresenceIndicatorLevel; 009import org.intellimate.izou.sdk.frameworks.presence.provider.PresenceResourceProvider; 010import org.intellimate.izou.sdk.frameworks.presence.resources.PresenceResource; 011 012import java.util.ArrayList; 013import java.util.Optional; 014import java.util.concurrent.CompletableFuture; 015import java.util.concurrent.atomic.AtomicBoolean; 016 017/** 018 * the base template class for addons able to conclude about constant presence. 019 * <p> 020 * If the addon is based on encounters with the user and not able to conclude constant presence from the information, 021 * it should pass not extend this class, if not (for example if it monitors wifi) it can. They can just fire the 022 * Presence-Event on encountering. 023 * It is expected that addons extending this class are pretty sure that the user is around and not a random person. 024 * </p> 025 * @author LeanderK 026 * @version 1.0 027 */ 028public abstract class PresenceConstant extends EventsController implements PresenceHelper, PresenceResourceProvider { 029 private boolean present = false; 030 private boolean globalPresent = false; 031 private boolean globalStrictPresent = false; 032 private final boolean strict; 033 private final PresenceIndicatorLevel level; 034 /** 035 * if the PresenceIndicatorLevel is under Weak, it will control events if it is still (one of) the most Vague 036 */ 037 private AtomicBoolean mostVague = new AtomicBoolean(true); 038 039 /** 040 * @param context the context 041 * @param ID the ID 042 * @param strict whether it is strict (very high probability that the user is around) 043 * @param level the level 044 * 045 */ 046 public PresenceConstant(Context context, String ID, boolean strict, PresenceIndicatorLevel level) { 047 super(context, ID); 048 this.strict = strict; 049 this.level = level; 050 } 051 052 /** 053 * Controls whether the fired Event should be dispatched to all the listeners. This method should execute quickly 054 * 055 * @param eventModel the Event 056 * @return true if it should dispatch, false if not 057 */ 058 @Override 059 public boolean controlEvents(EventModel eventModel) { 060 if (level.compareTo(PresenceIndicatorLevel.WEAK) >= 0) { 061 return present; 062 } else //noinspection SimplifiableIfStatement 063 if (level.compareTo(PresenceIndicatorLevel.WEAK) < 0 && mostVague.get()) { 064 return present; 065 } else { 066 return true; 067 } 068 } 069 070 /** 071 * true if the addon can guarantee that the user is around, false if not 072 * 073 * @return true if it can guarantee it, false if not 074 */ 075 @Override 076 public boolean isStrict() { 077 return strict; 078 } 079 080 /** 081 * whether it is known that the user caused the presence 082 * 083 * @return true if known, false if not 084 */ 085 @Override 086 public boolean isKnown() { 087 return true; 088 } 089 090 /** 091 * gets the PresenceIndicatorLevel of the addon (mainly used for communication between presence-providing addons) 092 * 093 * @return the Level 094 */ 095 @Override 096 public PresenceIndicatorLevel getLevel() { 097 return level; 098 } 099 100 /** 101 * returns true if the user might be/is present 102 * 103 * @return true if present 104 */ 105 @Override 106 public boolean isPresent() { 107 return present; 108 } 109 110 /** 111 * when this method is called the present-status was changed 112 * 113 * @param present true if present, false if not 114 */ 115 @Override 116 public void setGlobalPresent(boolean present) { 117 globalPresent = present; 118 } 119 120 /** 121 * returns true if the user is first encountered in the current mode 122 */ 123 @Override 124 public boolean isFirstEncountering() { 125 if (strict && !globalStrictPresent) { 126 return true; 127 } else if (!globalPresent) { 128 return true; 129 } 130 return false; 131 } 132 133 /** 134 * when this method is called, the strict-present status was changed 135 * 136 * @param present true if present, false if not 137 */ 138 @Override 139 public void setGlobalStrictPresent(boolean present) { 140 globalStrictPresent = present; 141 } 142 143 /** 144 * sets the presence 145 * @param present true for presence, false if not 146 */ 147 public void setPresence(boolean present) { 148 if (this.present == present) 149 return; 150 this.present = present; 151 updateVague(); 152 if (present) { 153 firePresence(true); 154 } else { 155 fireLeaving(); 156 } 157 } 158 159 /** 160 * updates the boolean whether it is the mode vague 161 */ 162 private void updateVague() { 163 generateResource(PresenceResource.ID) 164 .orElse(CompletableFuture.completedFuture(new ArrayList<>())) 165 .thenAccept(list -> mostVague.set(list.stream() 166 .map(Presence::importPresence) 167 .filter(Optional::isPresent) 168 .map(Optional::get) 169 .map(Presence::getLevel) 170 .noneMatch(level -> level.compareTo(getLevel()) > 0)) 171 ); 172 } 173}