package org.geogebra.web.plugin;
import java.util.ArrayList;
import org.geogebra.common.GeoGebraConstants;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.move.ggtapi.models.json.JSONObject;
import org.geogebra.common.plugin.SensorLogger;
import org.geogebra.common.util.debug.Log;
import org.geogebra.web.html5.util.JSON;
import org.geogebra.web.web.gui.view.dataCollection.DataCollectionView;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.user.client.Window;
/**
* @author gabor WebSocket logger for external mobile app
*/
public class WebsocketLogger extends SensorLogger {
private WebSocketConnection connection = null;
private ArrayList<WebSocketListener> listeners = new ArrayList<WebSocketListener>();
private String websocket_url;
public WebsocketLogger(Kernel kernel) {
super(kernel);
}
private void constructUrl() {
boolean secure = false;
if (Window.Location.getProtocol().equals("https:")) {
this.websocket_url = "wss:";
secure = true;
} else {
this.websocket_url = "ws:";
}
if (appID != null && appID.indexOf(".") > -1) {
this.websocket_url += appID + ":8080";
} else {
if (secure) {
this.websocket_url += GeoGebraConstants.DATA_LOGGING_WEBSOCKET_URL
+ ":"
+ GeoGebraConstants.DATA_LOGGING_WEBSOCKET_SECURE_PORT;
} else {
this.websocket_url += GeoGebraConstants.DATA_LOGGING_WEBSOCKET_URL
+ ":" + GeoGebraConstants.DATA_LOGGING_WEBSOCKET_PORT;
}
}
Log.debug(this.websocket_url);
}
private void createConnection() {
if (this.connection == null
|| this.connection.getReadyState() != WebSocketConnection.OPEN) {
constructUrl();
this.connection = WebSocketFactory.create(this.websocket_url);
this.connection.onOpen(new OpenEventHandler() {
@Override
public void open(JavaScriptObject event) {
startHandShake();
}
});
} else {
Log.debug("websocket connection is already established");
}
}
@Override
public boolean startLogging() {
initStartLogging();
closeSocket();
createConnection();
initMsgHandler();
initCloseHandler();
initErrorHandler();
return true;
}
private void initErrorHandler() {
connection.onError(new ErrorEventHandler() {
@Override
public void error(JavaScriptObject e) {
Log.debug("Error with webSocket");
}
});
}
private void startHandShake() {
JSONObject obj = new JSONObject();
try {
obj.put("appID", appID);
} catch (Exception e) {
Log.debug("JSON error: " + e.getMessage());
}
connection.send(obj.toString());
}
/**
* asks the mobile data app for a list of available sensors
*/
public void triggerAvailableSensors() {
JSONObject obj = new JSONObject();
try {
obj.put("appID", appID);
obj.put("availableSensors", "");
} catch (Exception e) {
Log.debug("JSON error: " + e.getMessage());
}
connection.send(obj.toString());
}
/**
* asks the mobile data app for the actual frequency
*/
public void triggerFrequency() {
JSONObject obj = new JSONObject();
try {
obj.put("appID", new JSONString(appID));
obj.put("frequency", new JSONString(""));
} catch (Exception e) {
Log.debug("JSON error: " + e.getMessage());
}
connection.send(obj.toString());
}
private void initCloseHandler() {
connection.onClose(new CloseEventHandler() {
@Override
public void close(JavaScriptObject event) {
Log.debug("Connection closed of Websocket");
}
});
}
/**
* differs between received values and list of available sensors
*
* @param json
* JSON
*/
void handle(JavaScriptObject json) {
if (JSON.get(json, Types.MOBILE_FOUND.toString()) != null) {
handleIDchecked(String.valueOf(
JSON.get(json, Types.MOBILE_FOUND.toString())).equals(
"true"));
} else if (JSON.get(json, Types.FREQUENCY.toString()) != null) {
handleFrequency(JSON.get(json, Types.FREQUENCY.toString()));
} else if (JSON.get(json, Types.ACCELEROMETER_X.toString())
.equals("true")
|| JSON.get(json, Types.ACCELEROMETER_X.toString()).equals(
"false")) {
handleAvailableSensors(json);
} else {
handleData(json);
}
}
private void handleIDchecked(boolean correctID) {
for (WebSocketListener listener : this.listeners) {
listener.onIDchecked(correctID);
}
}
private void handleFrequency(String frequency) {
for (WebSocketListener listener : this.listeners) {
listener.onFrequency(Integer.parseInt(frequency));
}
}
/**
* if sensor is available, the settings for this sensor should be visible in
* the {@link DataCollectionView}
*
* @param json
*/
private void handleAvailableSensors(JavaScriptObject json) {
handleAvailable(json, Types.ACCELEROMETER_X);
handleAvailable(json, Types.MAGNETIC_FIELD_X);
handleAvailable(json, Types.ORIENTATION_X);
handleAvailable(json, Types.LOUDNESS);
handleAvailable(json, Types.PROXIMITY);
handleAvailable(json, Types.LIGHT);
for (WebSocketListener listener : this.listeners) {
listener.onSensorActive(Types.TIMESTAMP, true);
}
}
private void handleAvailable(JavaScriptObject json, Types type) {
if (JSON.get(json, type.toString()) != null) {
for (WebSocketListener listener : this.listeners) {
listener.onSensorActive(type,
Boolean.parseBoolean(JSON.get(json, type.toString())));
}
}
}
private void handleData(JavaScriptObject json) {
beforeLog();
int dataCount = Integer.parseInt(JSON.get(json,
Types.DATA_COUNT.toString()));
int timestampMS = Integer.parseInt(JSON.get(json,
Types.TIMESTAMP.toString()));
double timestamp = Float.parseFloat(JSON.get(json,
Types.TIMESTAMP.toString())) * 0.001;
// TODO : Maybe do it faster somehow - only logging that is sent?
String sensorAx = JSON.get(json, Types.ACCELEROMETER_X.toString());
if (sensorAx != null) {
log(Types.ACCELEROMETER_X, timestamp, Float.parseFloat(sensorAx));
onDataReceived(Types.ACCELEROMETER_X, timestampMS, dataCount);
}
String sensorAy = JSON.get(json, Types.ACCELEROMETER_Y.toString());
if (sensorAy != null) {
log(Types.ACCELEROMETER_Y, timestamp, Float.parseFloat(sensorAy));
}
String sensorAz = JSON.get(json, Types.ACCELEROMETER_Z.toString());
if (sensorAz != null) {
log(Types.ACCELEROMETER_Z, timestamp, Float.parseFloat(sensorAz));
}
String sensorMx = JSON.get(json, Types.MAGNETIC_FIELD_X.toString());
if (sensorMx != null) {
log(Types.MAGNETIC_FIELD_X, timestamp, Float.parseFloat(sensorMx));
onDataReceived(Types.MAGNETIC_FIELD_X, timestampMS, dataCount);
}
String sensorMy = JSON.get(json, Types.MAGNETIC_FIELD_Y.toString());
if (sensorMy != null) {
log(Types.MAGNETIC_FIELD_Y, timestamp, Float.parseFloat(sensorMy));
}
String sensorMz = JSON.get(json, Types.MAGNETIC_FIELD_Z.toString());
if (sensorMz != null) {
log(Types.MAGNETIC_FIELD_Z, timestamp, Float.parseFloat(sensorMz));
}
String sensorOx = JSON.get(json, Types.ORIENTATION_X.toString());
if (sensorOx != null) {
log(Types.ORIENTATION_X, timestamp, Float.parseFloat(sensorOx));
onDataReceived(Types.ORIENTATION_X, timestampMS, dataCount);
}
String sensorOy = JSON.get(json, Types.ORIENTATION_Y.toString());
if (sensorOy != null) {
log(Types.ORIENTATION_Y, timestamp, Float.parseFloat(sensorOy));
}
String sensorOz = JSON.get(json, Types.ORIENTATION_Z.toString());
if (sensorOz != null) {
log(Types.ORIENTATION_Z, timestamp, Float.parseFloat(sensorOz));
}
if (JSON.get(json, Types.DATA_COUNT.toString()) != null) {
log(Types.DATA_COUNT, timestamp, dataCount);
}
if (JSON.get(json, Types.TIMESTAMP.toString()) != null) {
log(Types.TIMESTAMP, timestamp, timestamp);
}
String sensorLo = JSON.get(json, Types.LOUDNESS.toString());
if (sensorLo != null) {
onDataReceived(Types.LOUDNESS, timestampMS, dataCount);
log(Types.LOUDNESS, timestamp, Float.parseFloat(sensorLo));
}
String sensorP = JSON.get(json, Types.PROXIMITY.toString());
if (sensorP != null) {
log(Types.PROXIMITY, timestamp, Float.parseFloat(sensorP));
onDataReceived(Types.PROXIMITY, timestampMS, dataCount);
}
String sensorLi = JSON.get(json, Types.LIGHT.toString());
if (sensorLi != null) {
log(Types.LIGHT, timestamp, Float.parseFloat(sensorLi));
onDataReceived(Types.LIGHT, timestampMS, dataCount);
}
}
private void onDataReceived(Types sensor, double timestamp, int dataCount) {
for (WebSocketListener listener : this.listeners) {
listener.onDataReceived(sensor, timestamp, dataCount);
}
}
private void initMsgHandler() {
connection.onMessage(new MessageEventHandler() {
@Override
public void message(JavaScriptObject msg) {
String data = JSON.get(msg, "data");
JavaScriptObject jsonData = JSON.parse(data);
handle(jsonData);
}
});
}
@Override
protected void closeSocket() {
if (connection != null
&& connection.getReadyState() != WebSocketConnection.CONNECTING) {
connection.close();
connection = null;
}
}
public void addListener(WebSocketListener listener) {
this.listeners.add(listener);
}
public void removeListener(WebSocketListener listener) {
this.listeners.remove(listener);
}
}