package com.geoloqi.mapattack;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.MathContext;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.util.concurrent.locks.ReentrantLock;
import android.content.Context;
import com.geoloqi.Installation;
import com.geoloqi.data.Fix;
import com.geoloqi.interfaces.GeoloqiFixSocket;
public class UDPClient implements GeoloqiFixSocket {
public final String uploadHost = "loki.geoloqi.com";
public final int uploadPort = 40000;
private ReentrantLock lock = new ReentrantLock(true);
private DatagramSocket uploadSocket;
private static UDPClient client = null;
Context context;
public static UDPClient getApplicationClient(Context context) {
if (client == null) {
client = new UDPClient(context);
}
return client;
}
private UDPClient(Context context) {
this.context = context;
try {
uploadSocket = new DatagramSocket();
uploadSocket.connect(new InetSocketAddress(uploadHost, uploadPort));
uploadSocket.send(new DatagramPacket(new byte[] { 0, 0, 0 }, 3));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void pushFix(Fix fix) {
lock.lock();
try {
uploadSocket.send(encode(fix));
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
public void close() {
lock.lock();
try {
uploadSocket.close();
} finally {
lock.unlock();
}
}
static MathContext math = MathContext.DECIMAL64;
private static final BigDecimal NINETY = new BigDecimal(90., math);
private static final BigDecimal ONE_EIGHTY = new BigDecimal(180., math);
private static final BigDecimal THREE_SIXTY = new BigDecimal(360., math);
private static final BigDecimal MAX = new BigDecimal(4294967295., math);
private DatagramPacket encode(Fix fix) {
byte[] bytes = new byte[39];
long lat = new BigDecimal(fix.getLatitude()).add(NINETY).divide(ONE_EIGHTY, math).multiply(MAX).round(math).longValue();
long lng = new BigDecimal(fix.getLongitude()).add(ONE_EIGHTY).divide(THREE_SIXTY, math).multiply(MAX).round(math).longValue();
bytes[0] = 0x41;
blitInt(fix.getTime() / 1000L, bytes, 1);
blitInt(lat, bytes, 5);
blitInt(lng, bytes, 9);
blitShort(fix.getSpeed(), bytes, 13);
blitShort(fix.getBearing(), bytes, 15);
blitShort(fix.getAltitude(), bytes, 17);
blitShort(fix.getAccuracy(), bytes, 19);
blitShort(fix.getExtras() == null ? 0 : fix.getExtras().getInt("battery"), bytes, 21);
blitUUID(bytes, 23);
return new DatagramPacket(bytes, bytes.length);
}
private void blitInt(long val, byte[] out, int offset) {
out[offset] = (byte) ((val & 0xff000000) >>> 24);
out[offset + 1] = (byte) ((val & 0x00ff0000) >>> 16);
out[offset + 2] = (byte) ((val & 0x0000ff00) >>> 8);
out[offset + 3] = (byte) ((val & 0x000000ff));
}
private void blitShort(int integer, byte[] out, int offset) {
out[offset] = (byte) ((integer & 0x0000ff00) >>> 8);
out[offset + 1] = (byte) ((integer & 0x000000ff));
}
private void blitShort(double val, byte[] out, int offset) {
blitShort((int) val, out, offset);
}
private void blitUUID(byte[] out, int offset) {
byte[] uuid = Installation.getIDAsBytes(context);
for (int i = 0; i < uuid.length; i++) {
out[offset + i] = uuid[i];
}
}
}