/*
* Copyright (C) 2010-2012 Stichting Akvo (Akvo Foundation)
*
* This file is part of Akvo FLOW.
*
* Akvo FLOW is free software: you can redistribute it and modify it under the terms of
* the GNU Affero General Public License (AGPL) as published by the Free Software Foundation,
* either version 3 of the License or any later version.
*
* Akvo FLOW is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License included below for more details.
*
* The full license text can also be seen at <http://www.gnu.org/licenses/agpl.html>.
*/
package org.waterforpeople.mapping.helper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.waterforpeople.mapping.dao.GeoIndexDao;
import org.waterforpeople.mapping.domain.AccessPoint;
import com.gallatinsystems.common.Constants;
import com.gallatinsystems.framework.dao.BaseDAO;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.index.strtree.STRtree;
/**
* This helper performs mapping summarization as well as abstracts clients from Some of the methods
* (addPointToPoly, for instance) are STATEFUL in that they can be used to accumulate points over
* multiple method invocations in member variables so that they can eventually be flushed to an
* index in a single operation
*
* @author Christopher Fagiani
*/
public class MappingSummarizationHelper {
private BaseDAO<AccessPoint> accessPointDao;
private GeoIndexDao geoIndexDao;
private Map<String, StringBuilder> regionMap;
private Map<String, String> firstPositionInPolys;
public MappingSummarizationHelper() {
accessPointDao = new BaseDAO<AccessPoint>(AccessPoint.class);
geoIndexDao = new GeoIndexDao();
}
/**
* adds the lat,lon point to the polygon identified by the UUID passed in. This method is
* STATEFUL in that this class will continue to accumulate points in a member variable each time
* this method is called. If you want to reset the internal member, call resetPoly
*
* @param uuid
* @param lat
* @param lon
*/
public void addPointToRegion(String uuid, String lat, String lon) {
if (regionMap == null) {
resetPoly();
}
StringBuilder buf = regionMap.get(uuid);
if (buf == null) {
buf = new StringBuilder();
buf.append(lat + " " + lon);
regionMap.put(uuid, buf);
firstPositionInPolys.put(uuid, lat + " " + lon);
} else {
buf.append("," + lat + " " + lon);
}
}
/**
* Persists all the accumulated points in the region map and resets the internal member
* variables
*/
public void saveRegions() {
if (regionMap != null) {
GeoIndexDao indexDao = new GeoIndexDao();
Map<String, String> regionStrings = new HashMap<String, String>();
for (String region : regionMap.keySet()) {
regionStrings.put(region, "POLYGON((" + regionMap.get(region)
+ "," + firstPositionInPolys.get(region) + "))");
}
indexDao.saveRegionIndex(regionStrings);
resetPoly();
}
}
/**
* resets the internal store
*/
public void resetPoly() {
regionMap = new HashMap<String, StringBuilder>();
firstPositionInPolys = new HashMap<String, String>();
}
/**
* executes a summarization action for a given region. It will iterate over all access points in
* that region and use the rule type to evalute what should be done
*
* @param regionUUID
* @param type
* @return
*/
public String processSummarization(String regionUUID, String type) {
String result = null;
List<AccessPoint> accessPoints = findPointsInRegion(regionUUID);
if (accessPoints != null && accessPoints.size() > 0) {
// now we have the list of access points in the region
// so run the rule
// 1 rule we have. once we have more, this will be abstracted out
int functionalCount = 0;
for (AccessPoint ap : accessPoints) {
if (AccessPoint.Status.FUNCTIONING_HIGH == ap.getPointStatus()) {
functionalCount++;
}
}
double pctFunctional = functionalCount / accessPoints.size();
if (pctFunctional >= 0.75) {
result = "GREEN";
} else if (pctFunctional >= .5) {
result = "YELLOW";
} else {
result = "RED";
}
}
return result;
}
/**
* returns the list of AccessPoint objects that are within the region identified by the uuid
*
* @param regionUUID
* @return
*/
public List<AccessPoint> findPointsInRegion(String regionUUID) {
// first, get the index for the region since, if we don't have that, we
// can't do anything
STRtree regionIndex = geoIndexDao.findGeoIndex(regionUUID);
// TODO: filter access points!!! for now, we get them all
List<AccessPoint> accessPoints = accessPointDao
.list(Constants.ALL_RESULTS);
List<AccessPoint> pointsInRegion = new ArrayList<AccessPoint>();
if (accessPoints != null && regionIndex != null) {
GeometryFactory geomFactory = new GeometryFactory();
for (AccessPoint p : accessPoints) {
Point point = geomFactory.createPoint(new Coordinate(p
.getLatitude(), p.getLongitude()));
if (!regionIndex.query(point.getEnvelopeInternal()).isEmpty()) {
pointsInRegion.add(p);
}
}
}
return pointsInRegion;
}
}