package pl.llp.aircasting.model;
import android.content.Context;
import android.widget.Toast;
import pl.llp.aircasting.R;
import pl.llp.aircasting.activity.ApplicationState;
import pl.llp.aircasting.activity.events.SessionChangeEvent;
import pl.llp.aircasting.activity.events.SessionStartedEvent;
import pl.llp.aircasting.android.Logger;
import pl.llp.aircasting.event.ConnectionUnsuccessfulEvent;
import pl.llp.aircasting.event.ui.StreamUpdateEvent;
import pl.llp.aircasting.event.ui.ViewStreamEvent;
import pl.llp.aircasting.helper.ResourceHelper;
import pl.llp.aircasting.helper.SettingsHelper;
import pl.llp.aircasting.model.events.MeasurementLevelEvent;
import pl.llp.aircasting.model.events.SensorEvent;
import pl.llp.aircasting.model.internal.MeasurementLevel;
import pl.llp.aircasting.model.internal.SensorName;
import pl.llp.aircasting.sensor.ExternalSensorDescriptor;
import pl.llp.aircasting.sensor.SensorStoppedEvent;
import pl.llp.aircasting.sensor.builtin.SimpleAudioReader;
import pl.llp.aircasting.sensor.external.ExternalSensors;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newConcurrentMap;
import static com.google.common.collect.Sets.newHashSet;
@Singleton
public class SensorManager
{
@Inject ResourceHelper resourceHelper;
@Inject ExternalSensors externalSensors;
@Inject SessionManager sessionManager;
@Inject EventBus eventBus;
@Inject ApplicationState state;
@Inject SettingsHelper settingsHelper;
@Inject Context context;
final Sensor AUDIO_SENSOR = SimpleAudioReader.getSensor();
private volatile Sensor visibleSensor = AUDIO_SENSOR;
private volatile Map<SensorName, Sensor> sensors = newConcurrentMap();
private volatile Set<Sensor> disabled = newHashSet();
@Inject
public void init()
{
eventBus.register(this);
}
@Subscribe
public void onEvent(SensorEvent event)
{
if(state.recording().isShowingOldSession())
{
return;
}
// IOIO
Sensor visibleSensor = getVisibleSensor();
if (visibleSensor != null && visibleSensor.matches(getSensorByName(event.getSensorName())))
{
MeasurementLevel level = null;
if (sessionManager.isSessionSaved())
{
level = MeasurementLevel.TOO_LOW;
}
else
{
double now = (int) sessionManager.getNow(visibleSensor);
level = resourceHelper.getLevel(visibleSensor, now);
}
eventBus.post(new MeasurementLevelEvent(visibleSensor, level));
}
// end of IOIO
if(sensors.containsKey(SensorName.from(event.getSensorName())))
{
return;
}
if(externalSensors.knows(event.getAddress()))
{
Sensor sensor = new Sensor(event);
if (disabled.contains(sensor)) {
sensor.toggle();
}
SensorName name = SensorName.from(sensor.getSensorName());
if(!sensors.containsKey(name))
{
sensors.put(name, sensor);
}
}
}
@Subscribe
public void onEvent(ViewStreamEvent event)
{
String sensorName = event.getSensor().getSensorName();
visibleSensor = sensors.get(SensorName.from(sensorName));
if(visibleSensor == null) visibleSensor = AUDIO_SENSOR;
eventBus.post(new StreamUpdateEvent(visibleSensor));
}
@Subscribe
public void onEvent(SensorStoppedEvent event)
{
disconnectSensors(event.getDescriptor());
}
public Sensor getVisibleSensor() {
String sensorName = visibleSensor.getSensorName();
Sensor sensor = sensors.get(SensorName.from(sensorName));
return sensor != null ? sensor : AUDIO_SENSOR;
}
public List<Sensor> getSensors() {
ArrayList<Sensor> result = newArrayList();
result.addAll(sensors.values());
return result;
}
public Sensor getSensorByName(String name) {
SensorName sensorName = SensorName.from(name);
Sensor sensor = sensors.get(sensorName);
return sensor;
}
/**
* @param sensor toggle enabled/disabled status of this Sensor
*/
public void toggleSensor(Sensor sensor) {
String name = sensor.getSensorName();
Sensor actualSensor = sensors.get(SensorName.from(name));
if(isSensorToggleable(actualSensor))
actualSensor.toggle();
else
Toast.makeText(context, R.string.sensor_is_disabled_in_settings, Toast.LENGTH_SHORT).show();
}
public void setSensorsStatusesToDefaultsFromSettings() {
if (settingsHelper.isSoundLevelMeasurementsDisabled())
sensors.get(SensorName.from("Phone Microphone")).disable();
else
sensors.get(SensorName.from("Phone Microphone")).enable();
}
public boolean isSensorToggleable(Sensor sensor) {
if (sensor.getSensorName() == "Phone Microphone" && settingsHelper.isSoundLevelMeasurementsDisabled())
return false;
else
return true;
}
@Subscribe
public void onEvent(SessionStartedEvent event) {
setSensorsStatusesToDefaultsFromSettings();
}
@Subscribe
public void onEvent(SessionChangeEvent event) {
disabled = newHashSet();
for (Sensor sensor : sensors.values()) {
if (!sensor.isEnabled()) {
disabled.add(sensor);
}
}
sensors = newConcurrentMap();
Session session = event.getSession();
for (MeasurementStream stream : session.getMeasurementStreams())
{
if (stream.isMarkedForRemoval())
{
continue;
}
Sensor sensor = new Sensor(stream);
String name = sensor.getSensorName();
sensors.put(SensorName.from(name), sensor);
visibleSensor = sensor;
}
}
public boolean isSessionBeingRecorded()
{
return sessionManager.isSessionStarted();
}
public void deleteSensorFromCurrentSession(Sensor sensor)
{
String sensorName = sensor.getSensorName();
sensors.remove(SensorName.from(sensorName));
sessionManager.deleteSensorStream(sensor);
}
public boolean isSessionBeingViewed()
{
return sessionManager.isSessionSaved();
}
@Subscribe
public void onEvent(ConnectionUnsuccessfulEvent e) {
disconnectSensors(new ExternalSensorDescriptor(e.getDevice()));
}
public void disconnectSensors(ExternalSensorDescriptor descriptor)
{
String address = descriptor.getAddress();
Collection<MeasurementStream> streams = sessionManager.getMeasurementStreams();
for (MeasurementStream stream : streams)
{
if(address.equals(stream.getAddress()))
{
stream.markAs(MeasurementStream.Visibility.INVISIBLE_DISCONNECTED);
}
}
Set<SensorName> newSensorNames = newHashSet();
for (Map.Entry<SensorName, Sensor> entry : sensors.entrySet())
{
if (!address.equals(entry.getValue().getAddress()))
{
newSensorNames.add(entry.getKey());
}
}
Map<SensorName, Sensor> newSensors = newConcurrentMap();
for (SensorName sensorName : newSensorNames)
{
Sensor sensor = sensors.get(sensorName);
newSensors.put(sensorName, sensor);
}
sensors = newSensors;
String sensorName = visibleSensor.getSensorName();
if(!sensors.containsKey(SensorName.from(sensorName)))
{
eventBus.post(new ViewStreamEvent(SimpleAudioReader.getSensor()));
}
}
}