package com.example.wearablesensorbase.ble;

import java.util.concurrent.ConcurrentHashMap;

import android.util.Log;

import com.example.wearablesensorbase.data.SensorMeasurement;

public abstract class IncomingDataParser {
	
	ConcurrentHashMap<String, DataParserHelper> parsers;
	
	public IncomingDataParser() {
		parsers = new ConcurrentHashMap<String, IncomingDataParser.DataParserHelper>();
	}

	public abstract void handleSensorMeasurement(String connection, SensorMeasurement measurement);
	
	public void parse(String connection, byte[] data) {
		DataParserHelper helper = getDataParserHelper(connection);
		helper.parse(this, data);
	}
	
	private DataParserHelper getDataParserHelper(String connection) {
		DataParserHelper helper = parsers.get(connection);
		if (helper == null) {
			helper = new DataParserHelper(connection);
			parsers.put(connection, helper);
		}
		
		return helper;
	}
	
	public class DataParserHelper {
		
		private String connection;
		private StringBuilder buffer;
		
		public DataParserHelper(String connection) {
			this.connection = connection;
		}
		
		public void parse(IncomingDataParser parser, byte[] data) {
			buffer.append(data.toString());
			
			String section;
			synchronized (this) {
				int end = buffer.lastIndexOf("##");
				section = buffer.substring(0, end);
				buffer = buffer.delete(0, end);
			}
			
			String[] chunks = section.split("#");
			for (String chunk : chunks) {
				SensorMeasurement measurement = parseMeasurement(chunk);
				if (measurement != null) {
					parser.handleSensorMeasurement(connection, measurement);
				}
			}
		}
		
		private SensorMeasurement parseMeasurement(String data) {
			String[] chunks = data.replaceAll("#", "").split("\\|");
			if (chunks.length < 8 || !chunks[0].startsWith("MEASUREMENT")) {
				return null;
			}
			
			try {
				double accelerationX = Double.parseDouble(chunks[1]);
				double accelerationY = Double.parseDouble(chunks[2]);
				double accelerationZ = Double.parseDouble(chunks[3]);
				
				double orientationX = Double.parseDouble(chunks[4]);
				double orientationY = Double.parseDouble(chunks[5]);
				double orientationZ = Double.parseDouble(chunks[6]);
				
				double loudness = Double.parseDouble(chunks[7]);
				
				SensorMeasurement measurement = 
					new SensorMeasurement(System.currentTimeMillis(), 
						accelerationX, accelerationY, accelerationZ, 
						orientationX, orientationY, orientationZ, 
						loudness);
				
				return measurement;
			} catch (NumberFormatException e) {
				Log.e("IncomingDataParser", "Failed to parse measurement: " + e.getMessage());
				return null;
			}
		}
	}
}

@@ -38,16 +38,61 @@
 e.ble;%0A%0A
+import java.io.UnsupportedEncodingException;%0A
 import j
@@ -1026,11 +1026,10 @@
 ngBu
-ild
+ff
 er b
@@ -1118,16 +1118,48 @@
 ection;%0A
+%09%09%09buffer = new StringBuffer();%0A
 %09%09%7D%0A%09%09%0A%09
@@ -1226,40 +1226,212 @@
 %0A%09%09%09
-buffer.append(data.toS
+try %7B%0A%09%09%09%09buffer = buffer.append(new String(data, %22UTF-8%22));%0A%09%09%09%7D catch (UnsupportedEncodingException e) %7B%0A%09%09%09%09System.err.println(%22IncomingDataParser%7Cparse: Input data is not a s
 tring
-()
+%22
 );%0A
+%09%09%09%09return;%0A%09%09%09%7D%0A
 %09%09%09%0A
@@ -1509,20 +1509,174 @@
 dexOf(%22#
-#
 %22);
+%0A%09%09%09%09if (end %3C 0) %7B%0A%09%09%09%09%09System.err.println(buffer);%0A%09%09%09%09%09System.err.println(%22IncomingDataParser%7Cparse: No measurement in buffer%22);%0A%09%09%09%09%09return;%0A%09%09%09%09%7D%0A%09%09%09%09
 %0A%09%09%09%09sec
@@ -2059,16 +2059,87 @@
 data) %7B%0A
+%09%09%09if (data == null %7C%7C data.length() == 0) %7B%0A%09%09%09%09return null;%0A%09%09%09%7D%0A%09%09%09%0A
 %09%09%09Strin
@@ -2254,24 +2254,110 @@
 REMENT%22)) %7B%0A
+%09%09%09%09System.err.println(%22IncomingDataParser%7CparseMeasurement: Malformed measurement%22);%0A
 %09%09%09%09return n

Fix exceptions in string parsing and buffering