package com.esri.geoevent.solutions.processor.bearing;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.esri.core.geometry.Geometry;
import com.esri.core.geometry.GeometryEngine;
import com.esri.core.geometry.MapGeometry;
import com.esri.core.geometry.Point;
import com.esri.core.geometry.Polyline;
import com.esri.core.geometry.Segment;
import com.esri.core.geometry.SpatialReference;
import com.esri.ges.core.component.ComponentException;
import com.esri.ges.core.geoevent.DefaultFieldDefinition;
import com.esri.ges.core.geoevent.FieldDefinition;
import com.esri.ges.core.geoevent.FieldType;
import com.esri.ges.core.geoevent.GeoEvent;
import com.esri.ges.core.geoevent.GeoEventDefinition;
import com.esri.ges.core.geoevent.Tag;
import com.esri.ges.core.validation.ValidationException;
import com.esri.ges.manager.geoeventdefinition.GeoEventDefinitionManager;
import com.esri.ges.messaging.GeoEventCreator;
import com.esri.ges.messaging.Messaging;
import com.esri.ges.processor.GeoEventProcessorBase;
import com.esri.ges.processor.GeoEventProcessorDefinition;
public class BearingProcessor extends GeoEventProcessorBase {
Messaging messaging;
GeoEventDefinitionManager manager;
private String oGeoFldName;
private String dGeoFldName;
private String oXFldName;
private String oYFldName;
private String dXFldName;
private String dYFldName;
private Boolean oUseGeo = false;
private Boolean dUseGeo = false;
private String bfldName;
private String gedName;
private Boolean createGeo = false;
private Integer wkid;
private static final Log LOG = LogFactory
.getLog(BearingProcessor.class);
public BearingProcessor(GeoEventProcessorDefinition definition)
throws ComponentException {
super(definition);
}
public void setMessaging(Messaging m)
{
messaging = m;
}
public void setGDManager(GeoEventDefinitionManager m)
{
manager = m;
}
@Override
public GeoEvent process(GeoEvent ge) throws Exception {
Double ox = null;
Double oy = null;
Double dx = null;
Double dy = null;
if(oUseGeo)
{
MapGeometry mg = (MapGeometry)ge.getField(oGeoFldName);
Geometry o = mg.getGeometry();
if(o==null)
{
Exception e = new Exception();
LOG.error("error retrieving origin geometry");
throw(e);
}
if(o instanceof Point)
{
ox = ((Point)o).getX();
oy = ((Point)o).getY();
}
else
{
Exception e = new IOException();
LOG.error("Invalid Origin geometry");
throw(e);
}
}
else
{
ox = (Double)ge.getField(oXFldName);
oy = (Double)ge.getField(oYFldName);
if(ox == null){
Exception e = new Exception();
LOG.error("error retrieving origin's x value");
throw(e);
}
if(oy == null)
{
Exception e = new Exception();
LOG.error("error retrieving origin's y value");
throw(e);
}
}
if(dUseGeo)
{
MapGeometry mg = (MapGeometry)ge.getField(dGeoFldName);
Geometry d=mg.getGeometry();
if(d==null)
{
Exception e = new Exception();
LOG.error("error retrieving destination geometry");
throw(e);
}
if(d instanceof Point)
{
dx = ((Point)d).getX();
dy = ((Point)d).getY();
}
else
{
Exception e = new IOException();
LOG.error("Invalid Destination geometry");
throw(e);
}
}
else
{
dx = (Double)ge.getField(dXFldName);
dy = (Double)ge.getField(dYFldName);
if(dx == null){
Exception e = new Exception();
LOG.error("error retrieving destinations's x value");
throw(e);
}
if(dy == null)
{
Exception e = new Exception();
LOG.error("error retrieving origin's y value");
throw(e);
}
}
Double b = generateBearing(ox,oy,dx,dy);
GeoEventDefinition geDef = ge.getGeoEventDefinition();
List<FieldDefinition> fdefs = geDef.getFieldDefinitions();
Boolean hasGeo = false;
for(FieldDefinition fldDef: fdefs)
{
List<String> tags = fldDef.getTags();
for (String tag:tags)
{
if(tag.equals("GEOMETRY"))
{
hasGeo = true;
}
}
}
GeoEventDefinition outDef = null;
Collection<GeoEventDefinition> defs = manager.searchGeoEventDefinitionByName(gedName);
if(defs.size() == 0)
{
List<FieldDefinition> newPropertyDefs = new ArrayList<FieldDefinition>();
FieldDefinition bfDef = new DefaultFieldDefinition(bfldName, FieldType.Double);
newPropertyDefs.add(bfDef);
if(!hasGeo && createGeo)
{
FieldDefinition geoFld = new DefaultFieldDefinition("geometry", FieldType.Geometry, "GEOMETRY");
newPropertyDefs.add(geoFld);
}
outDef = geDef.augment(newPropertyDefs);
outDef.setOwner(geDef.getOwner());
outDef.setName(gedName);
manager.addGeoEventDefinition(outDef);
}
else
{
outDef = (GeoEventDefinition) defs.toArray()[0];
}
GeoEventCreator creator = messaging.createGeoEventCreator();
GeoEvent newEvent = creator.create(outDef.getGuid());
newEvent.setField(bfldName, b);
for(FieldDefinition fDef:fdefs)
{
String name = fDef.getName();
Object val = ge.getField(name);
newEvent.setField(name, val);
}
if(createGeo)
{
SpatialReference sr;
SpatialReference srout = null;
Boolean projectGeo = false;
if(!hasGeo)
{
sr = SpatialReference.create(wkid);
}
else
{
sr = ge.getGeometry().getSpatialReference();
if(sr.getID() != wkid)
{
projectGeo = true;
srout = SpatialReference.create(wkid);
}
}
MapGeometry mapGeo = null;
if(projectGeo)
{
mapGeo = GenerateGeometry(ox,oy,dx,dy,sr,srout);
}
else
{
mapGeo = GenerateGeometry(ox,oy,dx,dy,sr);
}
newEvent.setGeometry(mapGeo);
}
return newEvent;
}
private MapGeometry GenerateGeometry(Double ox, Double oy, Double dx, Double dy, SpatialReference sr)
{
Point origin = new Point();
Point destination = new Point();
origin.setXY(ox, oy);
destination.setXY(dx, dy);
Polyline ln = new Polyline();
ln.startPath(origin);
ln.lineTo(destination);
MapGeometry mapGeo = new MapGeometry(ln, sr);
return mapGeo;
}
private MapGeometry GenerateGeometry(Double ox, Double oy, Double dx, Double dy, SpatialReference srin, SpatialReference srout)
{
Point origin = new Point();
Point destination = new Point();
origin.setXY(ox, oy);
destination.setXY(dx, dy);
Polyline ln = new Polyline();
ln.startPath(origin);
ln.lineTo(destination);
MapGeometry tmp_mapGeo = new MapGeometry(ln, srin);
Geometry projected = GeometryEngine.project(tmp_mapGeo.getGeometry(), srin, srout);
MapGeometry mapGeo = new MapGeometry(projected, srout);
return mapGeo;
}
public Double generateBearing(Double ox, Double oy, Double dx, Double dy)
{
Double bearing = 0.0;
Double lon1 = Math.toRadians(ox);
Double lat1 = Math.toRadians(oy);
Double lon2 = Math.toRadians(dx);
Double lat2 = Math.toRadians(dy);
Double dLon = lon2 - lon1;
Double y = Math.sin(dLon) * Math.cos(lat2);
Double x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
Double bRad = Math.atan2(y, x);
Double tmpB = Math.toDegrees(bRad);
//bearing =360.0-(tmpB+270.0)%360.0;
bearing = tmpB;
return bearing;
}
@Override
public boolean isGeoEventMutator() {
return true;
}
@Override
public void shutdown() {
// Destruction Phase
super.shutdown();
}
@Override
public synchronized void validate() throws ValidationException {
try
{
super.validate();
}
catch(Exception e)
{
LOG.error(e.getMessage());
}
}
@Override
public void afterPropertiesSet() {
try{
String osrc = properties.get("osrc").getValueAsString();
// if(osrc.equals("Geometry"))
oXFldName = properties.get("oxFld").getValueAsString();
oYFldName = properties.get("oyFld").getValueAsString();
oGeoFldName = properties.get("oGeoFld").getValueAsString();
if (osrc.equals("geo")) {
oUseGeo = true;
//oGeoFldName = properties.get("oGeoFld").getValueAsString();
} else {
//oXFldName = properties.get("oxFld").getValueAsString();
//oYFldName = properties.get("oyFld").getValueAsString();
}
String dsrc = properties.get("dsrc").getValueAsString();
dXFldName = properties.get("dxFld").getValueAsString();
dYFldName = properties.get("dyFld").getValueAsString();
dGeoFldName = properties.get("dGeoFld").getValueAsString();
if (dsrc.equals("geo")) {
dUseGeo = true;
//dGeoFldName = properties.get("dGeoFld").getValueAsString();
} else {
//dXFldName = properties.get("dxFld").getValueAsString();
//dYFldName = properties.get("dyFld").getValueAsString();
}
bfldName = properties.get("newfld").getValueAsString();
gedName = properties.get("newdef").getValueAsString();
createGeo = (Boolean) properties.get("generateGeo").getValue();
wkid = (Integer) properties.get("wkidout").getValue();
}
catch(Exception e)
{
LOG.error(e.getMessage());
}
}
}