package com.esri.geoevent.solutions.adapter.esd;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.esri.core.geometry.MapGeometry;
import com.esri.core.geometry.Point;
import com.esri.core.geometry.SpatialReference;
import com.esri.ges.adapter.AdapterDefinition;
import com.esri.ges.adapter.InboundAdapterBase;
import com.esri.ges.core.component.ComponentException;
import com.esri.ges.core.geoevent.FieldException;
import com.esri.ges.core.geoevent.GeoEvent;
import com.esri.ges.messaging.MessagingException;
public class ESDInboundAdapter extends InboundAdapterBase
{
private static final Log LOG = LogFactory.getLog(ESDInboundAdapter.class);
private String currentSentence = "";
private boolean started=false;
public ESDInboundAdapter(AdapterDefinition definition) throws ComponentException
{
super(definition);
}
@Override
public void receive(ByteBuffer buffer, String channelId) {
// TODO Auto-generated method stub
super.receive(buffer, channelId);
}
public GeoEvent adapt(ByteBuffer buffer, String channelId)
{
try
{
String sentence = "";
final int TOOLONG = 2048;
boolean ended=false;
while (!ended)
{
char character = (char)buffer.get(); // get the char but don't advance the mark
if (!started)
{
if (currentSentence.contentEquals("T") && character == 'a') // start
{
started = true;
currentSentence += 'a';
}
else if (character == 'T')
{
currentSentence = "T";
}
else
{
currentSentence = "";
}
}
else
{
if (currentSentence.endsWith("T") && character == 'a') // start of next sentence
{
ended = true;
sentence = currentSentence.substring(0, currentSentence.length()-1);
currentSentence = "Ta"; // start of next sentence leave started = true
}
else
{
currentSentence += character;
}
}
// if the incoming data is malformed we need to eventually give up and clear the buffer
if(currentSentence.length() > TOOLONG)
{
currentSentence = "";
started = false;
LOG.info("Received 2408 characters without two \"Ta\" fields, probably not ESD data.");
return null;
}
}
final String tagsRegex = "Ta|To|Te|Tw|Sr|Sp|Se|Fv|Sl|Sa|So|Sn|Ic|Cd|Ct|Mn|Md|Mt|Cl|Pc|Iv|Ir|Ip|Ih";
final String notTagsRegex = "[^"+tagsRegex+"]+";
String[] fields = sentence.split(tagsRegex); // get array of the fields divided by the tags
String[] tags = sentence.split(notTagsRegex); // get array of the tags
GeoEvent msg = createGeoEvent(fields, tags);
return msg;
}
catch (Exception ex)
{
// not enough data for a complete sentence yet so try again later
return null;
}
}
//ESD format has the following tags
//Ta - target latitude (deg)
//To - target longitude (deg)
//Tw - target_width
//Sr - slant range
//Sp - sensor pointing azimuth (deg)
//Se - sensor depression angle (deg)
//Fv - field of view (deg)
//Sl - sensor altitude (ft)
//Sa - sensor latitude (deg)
//So - sensor longitude (deg)
//Sn - sensor name (this is a number 1-5)
//Ic - image coordinate system // currently ignored (Always assume geographic coordinated not geocentric
//Cd - date of collection YYYYMMDD
//Ct - time of collection HHMMSS
//Mn - mission number
//Md - mission start date
//Mt - mission start time
//Cl - classification
//Pc - project id code (platform code)
//Iv - ESD icd version
//Ir - undocumented token
//Ip - undocumented token
//Ih - undocumented token
private GeoEvent createGeoEvent(String[] fields, String[] tags) {
if (fields.length < 15)
{
return null;
}
// Create an instance of the message using the guid that we generated when
// we started up.
GeoEvent msg;
try
{
msg = geoEventCreator.create(((AdapterDefinition)definition).getGeoEventDefinition("ESDGeoEventDefinition").getGuid());
}
catch (MessagingException e)
{
return null;
}
double targetLat=-999.0;
double targetLon=-999.0;
double targetElevation=0.0;
double sensorLat=-999.0;
double sensorLon=-999.0;
double sensorAlt=-999.0;
String collectionDate="";
String collectionTime="";
String missionDate = "";
String missionTime="";
for(int i = 1; i<fields.length ; i++) // the 0th element is any junk before the first tag
{
try {
if (tags[i-1].equals("Ta")) //PDDMMSST
{
if(fields[i].length()==8)
{
int dd = Integer.parseInt(fields[i].substring(1, 3));
int mm = Integer.parseInt(fields[i].substring(3, 5));
int ss = Integer.parseInt(fields[i].substring(5, 7));
int t = Integer.parseInt(fields[i].substring(7, 8));
targetLat = dd + (mm+((ss+(t/10))/60.0))/60.0;
if (fields[i].charAt(0) == '-')
targetLat = targetLat*(-1);
}
else if(fields[i].length()==7) // some version leave off the "+"
{
int dd = Integer.parseInt(fields[i].substring(0, 2));
int mm = Integer.parseInt(fields[i].substring(2, 4));
int ss = Integer.parseInt(fields[i].substring(4, 6));
int t = Integer.parseInt(fields[i].substring(6, 7));
targetLat = dd + (mm+((ss+(t/10))/60.0))/60.0;
} }
else if (tags[i-1].equals("To")) //PDDDMMSST
{
if(fields[i].length()==9)
{
int ddd = Integer.parseInt(fields[i].substring(1, 4));
int mm = Integer.parseInt(fields[i].substring(4, 6));
int ss = Integer.parseInt(fields[i].substring(6, 8));
int t = Integer.parseInt(fields[i].substring(8, 9));
targetLon = ddd + (mm+((ss+(t/10))/60.0))/60.0;
if (fields[i].charAt(0) == '-')
targetLon = targetLon*(-1);
}
else if(fields[i].length()==8) // some version leave off the "+"
{
int dd = Integer.parseInt(fields[i].substring(0, 3));
int mm = Integer.parseInt(fields[i].substring(3, 5));
int ss = Integer.parseInt(fields[i].substring(5, 7));
int t = Integer.parseInt(fields[i].substring(7, 8));
targetLon = dd + (mm+((ss+(t/10))/60.0))/60.0;
}
}
else if (tags[i-1].equals("Te")) // target_width
{
float targetFeet = Float.parseFloat(fields[i]);
targetElevation = targetFeet / 3.28084; // store TargetElevation in meters to use in geometry field
}
else if (tags[i-1].equals("Tw")) // target_width
{
msg.setField(2, (long)Float.parseFloat(fields[i]));
}
else if (tags[i-1].equals("Sr")) //slant range
{
msg.setField(3, (long)Float.parseFloat(fields[i]));
}
else if (tags[i-1].equals("Sp")) //sensor pointing azimuth
{
msg.setField(4, Float.parseFloat(fields[i]));
}
else if (tags[i-1].equals("Se")) //sensor depression angle
{
msg.setField(5, Float.parseFloat(fields[i]));;
}
else if (tags[i-1].equals("Fv")) //sensor_field_of_view
{
msg.setField(6, Float.parseFloat(fields[i]));;
}
else if (tags[i-1].equals("Sl")) // Sensor_altitude
{
long sensorFeet = Long.parseLong(fields[i]);
sensorAlt = sensorFeet / 3.28084; // store sensor Altitude in meters to use in geometry field
msg.setField(7, sensorFeet );
}
else if (tags[i-1].equals("Sa")) // these get converted to a geometry for sensor location in field 8
{
if(fields[i].length()==8)
{
int dd = Integer.parseInt(fields[i].substring(1, 3)); //eg +34 skip the sign
int mm = Integer.parseInt(fields[i].substring(3, 5));
int ss = Integer.parseInt(fields[i].substring(5, 7));
int t = Integer.parseInt(fields[i].substring(7, 8));
sensorLat = dd + (mm+((ss+(t/10))/60.0))/60.0;
if (fields[i].charAt(0) == '-')
sensorLat = sensorLat*(-1);
}
else if(fields[i].length()==7) // some version leave off the "+"
{
int dd = Integer.parseInt(fields[i].substring(0, 2));
int mm = Integer.parseInt(fields[i].substring(2, 4));
int ss = Integer.parseInt(fields[i].substring(4, 6));
int t = Integer.parseInt(fields[i].substring(6, 7));
sensorLat = dd + (mm+((ss+(t/10))/60.0))/60.0;
}
}
else if (tags[i-1].equals("So")) //PDDDMMSST
{
if(fields[i].length()==9)
{
int ddd = Integer.parseInt(fields[i].substring(1, 4)); //eg -117 skip sign
int mm = Integer.parseInt(fields[i].substring(4, 6));
int ss = Integer.parseInt(fields[i].substring(6, 8));
int t = Integer.parseInt(fields[i].substring(8, 9));
sensorLon = ddd + (mm+((ss+(t/10))/60.0))/60.0;
if (fields[i].charAt(0) == '-')
sensorLon = sensorLon*(-1);
}
else if(fields[i].length()==8) // some version leave off the "+"
{
int dd = Integer.parseInt(fields[i].substring(0, 3)); //DDD
int mm = Integer.parseInt(fields[i].substring(3, 5)); //MM
int ss = Integer.parseInt(fields[i].substring(5, 7)); //SS
int t = Integer.parseInt(fields[i].substring(7, 8)); //T
sensorLon = dd + (mm+((ss+(t/10))/60.0))/60.0;
}
}
else if (tags[i-1].equals("Sn")) // sensor name enum
{
msg.setField(9, Short.parseShort(fields[i]));
}
else if (tags[i-1].equals("Cd")) // Collection date yyyymmdd next two fieild get combined into 10
{
collectionDate = fields[i];
}
else if (tags[i-1].equals("Ct")) // collection time HHMMSS
{
collectionTime = fields[i];
}
else if (tags[i-1].equals("Mn")) //Mission Number
{
msg.setField(11, Long.parseLong(fields[i]));
}
else if (tags[i-1].equals("Md")) // mission date yyyymmdd next two fields get combined into 12
{
missionDate = fields[i];
}
else if (tags[i-1].equals("Mt")) // mission time HHMMSS
{
missionTime = fields[i];
}
else if (tags[i-1].equals("Cl")) // Security Classification
{
msg.setField(13,fields[i]);
}
else if (tags[i-1].equals("Pc")) // Project/platform code
{
msg.setField(14, Short.parseShort(fields[i]));
}
} catch (NumberFormatException e) {
LOG.debug("parse exception fields "+tags[i-1]+fields[i]);
//return null;
} catch (FieldException e) {
LOG.debug("FieldException fields "+tags[i-1]+fields[i]);
}
}
try {
msg.setField(0, 1);
// for now set the track ID to 1 ultimately we might want to utilize the channel ID or the mission number
if (targetLat>=-90 && targetLat<= 90 && targetLon <= 180 && targetLon >= -180)
{
int wkid = 4326;
SpatialReference sr = SpatialReference.create(wkid);
Point p = new Point(targetLon, targetLat);
MapGeometry mapGeo = new MapGeometry(p, sr);
msg.setField(1, mapGeo);
}
if (sensorLat>=-90 && sensorLat<= 90 && sensorLon <= 180 && sensorLon >= -180)
{
int wkid = 4326;
SpatialReference sr = SpatialReference.create(wkid);
Point p = new Point(sensorLon, sensorLat, sensorAlt);
MapGeometry mapGeo = new MapGeometry(p, sr);
msg.setField(8, mapGeo);
}
if (collectionDate.length() == 8 && collectionTime.length() == 6 )
{
DateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
Date date;
try {
date = (Date)formatter.parse(collectionDate+collectionTime);
} catch (ParseException e) {
date=null;
}
if (date!=null)
{
msg.setField(10,date);
}
}
if (missionDate.length() == 8 && missionTime.length() == 6 )
{
DateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
Date date;
try {
date = (Date)formatter.parse(missionDate+missionTime);
} catch (ParseException e) {
date=null;
}
if (date!=null)
{
msg.setField(12,date);
}
}
return msg;
} catch (FieldException e1) {
LOG.debug("FieldException: "+e1.getMessage());
return null;
}
}
}