/*
* 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.io.ByteArrayOutputStream;
import java.io.StringWriter;
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.waterforpeople.mapping.dao.AccessPointDao;
import org.waterforpeople.mapping.domain.AccessPoint;
import org.waterforpeople.mapping.domain.AccessPoint.AccessPointType;
import org.waterforpeople.mapping.domain.TechnologyType;
import com.gallatinsystems.common.util.ZipUtil;
import com.gallatinsystems.framework.dao.BaseDAO;
import com.gallatinsystems.gis.geography.domain.Country;
import com.gallatinsystems.gis.map.dao.MapControlDao;
import com.gallatinsystems.gis.map.dao.MapFragmentDao;
import com.gallatinsystems.gis.map.domain.MapControl;
import com.gallatinsystems.gis.map.domain.MapFragment;
import com.gallatinsystems.gis.map.domain.MapFragment.FRAGMENTTYPE;
import com.google.appengine.api.datastore.Blob;
public class KMLHelper {
private static final Logger log = Logger.getLogger(KMLHelper.class
.getName());
private VelocityEngine engine;
public KMLHelper() {
engine = new VelocityEngine();
engine.setProperty("runtime.log.logsystem.class",
"org.apache.velocity.runtime.log.NullLogChute");
try {
engine.init();
} catch (Exception e) {
log.log(Level.SEVERE, "Could not initialize velocity", e);
}
}
/**
* merges a hydrated context with a template identified by the templateName passed in.
*
* @param context
* @param templateName
* @return
* @throws Exception
*/
private String mergeContext(VelocityContext context, String templateName)
throws Exception {
Template t = engine.getTemplate(templateName);
StringWriter writer = new StringWriter();
t.merge(context, writer);
return writer.toString();
}
public String bindPlacemark(AccessPoint ap, String vmName) throws Exception {
if (ap.getCountryCode() != null && !ap.getCountryCode().equals("MW")) {
VelocityContext context = new VelocityContext();
if (ap.getCollectionDate() != null) {
String formattedDate = DateFormat.getDateInstance(
DateFormat.SHORT).format(ap.getCollectionDate());
context.put("collectionDate", formattedDate);
} else {
context.put("collectionDate", "N/A");
}
context.put("latitude", ap.getLatitude());
context.put("longitude", ap.getLongitude());
context.put("altitude", ap.getAltitude());
if (ap.getCommunityCode() != null)
context.put("communityCode", ap.getCommunityCode());
else
context.put("communityCode", "Unknown" + new Date());
if (ap.getPhotoURL() != null)
context.put("photoUrl", ap.getPhotoURL());
else
context
.put("photoUrl",
"http://waterforpeople.s3.amazonaws.com/images/wfplogo.jpg");
if (ap.getPointType() != null) {
if (ap.getPointType().equals(
AccessPoint.AccessPointType.WATER_POINT)) {
context.put("typeOfPoint", "Water");
context.put("type", "water");
} else if (ap.getPointType().equals(
AccessPointType.SANITATION_POINT)) {
context.put("typeOfPoint", "Sanitation");
context.put("type", "sanitation");
} else if (ap.getPointType().equals(
AccessPointType.PUBLIC_INSTITUTION)) {
context.put("typeOfPoint", "Public Institutions");
context.put("type", "public_institutions");
} else if (ap.getPointType().equals(
AccessPointType.HEALTH_POSTS)) {
context.put("typeOfPoint", "Health Posts");
context.put("type", "health_posts");
} else if (ap.getPointType().equals(AccessPointType.SCHOOL)) {
context.put("typeOfPoint", "School");
context.put("type", "school");
}
} else {
context.put("typeOfPoint", "Water");
context.put("type", "water");
}
if (ap.getTypeTechnologyString() == null) {
context.put("primaryTypeTechnology", "Unknown");
} else {
context.put("primaryTypeTechnology", ap
.getTypeTechnologyString());
}
if (ap.getHasSystemBeenDown1DayFlag() == null) {
context.put("down1DayFlag", "Unknown");
} else {
context.put("down1DayFlag", encodeBooleanDisplay(ap
.getHasSystemBeenDown1DayFlag()));
}
if (ap.getInstitutionName() == null) {
context.put("institutionName", "Unknown");
} else {
context.put("institutionName", "Unknown");
}
if (ap.getConstructionDateYear() == null
|| ap.getConstructionDateYear().trim().equals("")) {
context.put("constructionDateOfWaterPoint", "Unknown");
} else {
context.put("constructionDateOfWaterPoint", ap
.getConstructionDateYear());
}
if (ap.getNumberOfHouseholdsUsingPoint() == null) {
context.put("numberOfHouseholdsUsingWaterPoint", "Unknown");
} else {
context.put("numberOfHouseholdsUsingWaterPoint", ap
.getNumberOfHouseholdsUsingPoint());
}
if (ap.getCostPer() == null) {
context.put("costPer", "N/A");
} else {
context.put("costPer", ap.getCostPer());
}
if (ap.getFarthestHouseholdfromPoint() == null
|| ap.getFarthestHouseholdfromPoint().trim().equals("")) {
context.put("farthestHouseholdfromWaterPoint", "N/A");
} else {
context.put("farthestHouseholdfromWaterPoint", ap
.getFarthestHouseholdfromPoint());
}
if (ap.getCurrentManagementStructurePoint() == null) {
context.put("currMgmtStructure", "N/A");
} else {
context.put("currMgmtStructure", ap
.getCurrentManagementStructurePoint());
}
if (ap.getPointPhotoCaption() == null
|| ap.getPointPhotoCaption().trim().equals("")) {
context.put("waterPointPhotoCaption", "Water For People");
} else {
context
.put("waterPointPhotoCaption", ap
.getPointPhotoCaption());
}
if (ap.getCommunityName() == null) {
context.put("communityName", "Unknown");
} else {
context.put("communityName", ap.getCommunityName());
}
if (ap.getHeader() == null) {
context.put("header", "Water For People");
} else {
context.put("header", ap.getHeader());
}
if (ap.getFooter() == null) {
context.put("footer", "Water For People");
} else {
context.put("footer", ap.getFooter());
}
if (ap.getPhotoName() == null) {
context.put("photoName", "Water For People");
} else {
context.put("photoName", ap.getPhotoName());
}
if (ap.getMeetGovtQualityStandardFlag() == null) {
context.put("meetGovtQualityStandardFlag", "N/A");
} else {
context.put("meetGovtQualityStandardFlag",
encodeBooleanDisplay(ap
.getMeetGovtQualityStandardFlag()));
}
if (ap.getMeetGovtQuantityStandardFlag() == null) {
context.put("meetGovtQuantityStandardFlag", "N/A");
} else {
context.put("meetGovtQuantityStandardFlag",
encodeBooleanDisplay(ap
.getMeetGovtQuantityStandardFlag()));
}
if (ap.getWhoRepairsPoint() == null) {
context.put("whoRepairsPoint", "N/A");
} else {
context.put("whoRepairsPoint", ap.getWhoRepairsPoint());
}
if (ap.getSecondaryTechnologyString() == null) {
context.put("secondaryTypeTechnology", "N/A");
} else {
context.put("secondaryTypeTechnology", ap
.getSecondaryTechnologyString());
}
if (ap.getProvideAdequateQuantity() == null) {
context.put("provideAdequateQuantity", "N/A");
} else {
context.put("provideAdequateQuantity", encodeBooleanDisplay(ap
.getProvideAdequateQuantity()));
}
if (ap.getBalloonTitle() == null) {
context.put("title", "Water For People");
} else {
context.put("title", ap.getBalloonTitle());
}
if (ap.getProvideAdequateQuantity() == null) {
context.put("provideAdequateQuantity", "N/A");
} else {
context.put("provideAdequateQuantity", encodeBooleanDisplay(ap
.getProvideAdequateQuantity()));
}
if (ap.getDescription() != null)
context.put("description", ap.getDescription());
else
context.put("description", "Unknown");
// Need to check this
if (ap.getPointType() != null)
encodeStatus(ap.getPointType(), ap.getPointStatus(), context);
else {
context.put("pinStyle", "pushpinblk");
}
String output = mergeContext(context, vmName);
return output;
}
return null;
}
private String encodeBooleanDisplay(Boolean value) {
if (value) {
return "Yes";
} else {
return "No";
}
}
private void encodeStatus(AccessPointType type, AccessPoint.Status status,
VelocityContext context) {
if (type.equals(AccessPointType.SANITATION_POINT)) {
context.put("pinStyle", "pushpinpurple");
} else {
if (status.equals(AccessPoint.Status.FUNCTIONING_HIGH)) {
context.put("pinStyle", "pushpingreen");
} else if (status.equals(AccessPoint.Status.FUNCTIONING_OK)) {
context.put("pinStyle", "pushpinyellow");
} else if (status
.equals(AccessPoint.Status.FUNCTIONING_WITH_PROBLEMS)) {
context.put("pinStyle", "pushpinred");
} else if (status.equals(AccessPoint.Status.NO_IMPROVED_SYSTEM)) {
context.put("pinStyle", "pushpinblk");
} else {
context.put("pinStyle", "pushpinblk");
}
}
encodeStatusString(status, context);
}
private String encodeStatusString(AccessPoint.Status status,
VelocityContext context) {
if (status != null) {
if (status.equals(AccessPoint.Status.FUNCTIONING_HIGH)) {
context.put("waterSystemStatus",
"System Functioning and Meets Government Standards");
return "System Functioning and Meets Government Standards";
} else if (status.equals(AccessPoint.Status.FUNCTIONING_OK)) {
context.put("waterSystemStatus",
"Functioning but with Problems");
return "Functioning but with Problems";
} else if (status
.equals(AccessPoint.Status.FUNCTIONING_WITH_PROBLEMS)) {
context.put("waterSystemStatus", "Broken-down system");
return "Broken-down system";
} else if (status.equals(AccessPoint.Status.NO_IMPROVED_SYSTEM)) {
context.put("waterSystemStatus", "No Improved System");
return "No Improved System";
} else {
context.put("waterSystemStatus", "Unknown");
return "Unknown";
}
} else {
context.put("waterSystemStatus", "Unknown");
return "Unknown";
}
}
private String generateFolderContents(String countryCode, String techType,
String mapFragmentText) throws Exception {
VelocityContext context = new VelocityContext();
StringBuilder techFolders = new StringBuilder();
context.put("techFolderName", techType);
context.put("techPlacemarks", mapFragmentText);
techFolders.append(mergeContext(context, "techFolders.vm"));
return techFolders.toString();
}
public void buildMap() {
// Select all individual placemarks, but techtype and country
// Save Each tech type to MapFragment
// Select all Placemarks by techType order by techType for a country
// bind to folder vm
// Save a complete country order by countryName
// Save complete kml to mapfragment
// Save to s3?
BaseDAO<Country> countryDao = new BaseDAO<Country>(Country.class);
MapControl mc = new MapControl();
mc.setStartDate(new Date());
List<Country> countryList = countryDao.list("all");
if (countryList != null)
for (Country country : countryList) {
if (country != null) {
/*
* Queue mapAssemblyQueue = QueueFactory .getQueue("mapAssembly"); TaskOptions
* task = url("/app_worker/mapassembly").param( "action",
* Constants.BUILD_COUNTRY_FRAGMENTS).param( "countryCode",
* country.getIsoAlpha2Code()); mapAssemblyQueue.add(task);
*/
}
}
}
public void buildCountryFragments(String countryCode) {
BaseDAO<TechnologyType> techTypeDao = new BaseDAO<TechnologyType>(
TechnologyType.class);
List<TechnologyType> techTypeList = techTypeDao.list("all");
if (countryCode != null)
for (TechnologyType tt : techTypeList) {
if (tt != null) {
/*
* Queue mapAssemblyQueue = QueueFactory .getQueue("mapAssembly"); TaskOptions
* task = url("/app_worker/mapassembly").param( "action",
* Constants.BUILD_COUNTRY_FRAGMENTS).param( "countryCode",
* countryCode).param("techType", tt.getCode()); mapAssemblyQueue.add(task);
*/
}
}
}
public void assembleCountryTechTypeFragments(String countryCode,
String techType) {
MapFragmentDao mfDao = new MapFragmentDao();
StringBuilder kml = new StringBuilder();
List<MapFragment> mfList = mfDao.searchMapFragments(countryCode, null,
null, FRAGMENTTYPE.COUNTRY_TECH_PLACEMARK_LIST, "all",
null, null);
StringBuilder sbAllCountryPlacemark = new StringBuilder();
for (MapFragment mfItem : mfList) {
try {
sbAllCountryPlacemark.append(ZipUtil.unZip(mfItem.getBlob()
.getBytes()));
} catch (Exception e) {
log.log(Level.SEVERE,
"Could not assemble country tech type fragments", e);
}
}
VelocityContext context = new VelocityContext();
context.put("country", countryCode);
context.put("techFolders", sbAllCountryPlacemark.toString());
try {
kml.append(mergeContext(context, "Folders.vm"));
} catch (Exception e) {
log.log(Level.SEVERE, "Could not generate folders", e);
}
}
public void assembleCompleteMap() {
VelocityContext context = new VelocityContext();
// context.put("folderContents", kml.toString());
try {
String completeKML = mergeContext(context, "Document.vm");
MapFragment mf = new MapFragment();
mf.setCountryCode("ALL");
mf.setFragmentType(FRAGMENTTYPE.GLOBAL_ALL_PLACEMARKS);
ByteArrayOutputStream bos = ZipUtil.generateZip(completeKML,
"waterforpeoplemapping.kml");
mf.setBlob(new Blob(bos.toByteArray()));
// mfDao.save(mf);
// mc.setEndDate(new Date());
// mc.setStatus(MapControl.Status.SUCCESS);
// mcDao.save(mc);
} catch (Exception e) {
log.log(Level.SEVERE, "Could not assemble map", e);
// mc.setEndDate(new Date());
// mc.setStatus(MapControl.Status.FAILURE);
// mcDao.save(mc);
}
}
public void buildCountryTechTypeFragment(String countryCode, String techType) {
StringBuilder sbTechList = new StringBuilder();
MapFragmentDao mfDao = new MapFragmentDao();
String mfTechItemsByCountry = null;
List<MapFragment> mfList = mfDao.listFragmentsByCountryAndTechType(
countryCode, techType);
for (MapFragment mfItem : mfList) {
sbTechList.append(mfItem.getFragmentValue().getValue());
}
try {
mfTechItemsByCountry = generateFolderContents(countryCode,
techType, sbTechList.toString());
} catch (Exception e) {
// log.Log(LogLevel.ERROR,
// "Could not generate country tech folders for: " + countryCode +
// ":" + techType + e);
}
MapFragment mf = new MapFragment();
mf.setFragmentType(FRAGMENTTYPE.COUNTRY_TECH_PLACEMARK_LIST);
mf.setCountryCode(countryCode);
mf.setTechnologyType(techType);
// mf.setFragmentValue(new Text(mfTechItemsByCountry));
ByteArrayOutputStream os = ZipUtil.generateZip(mfTechItemsByCountry,
"waterforpeoplemapping.kml");
Blob blob = new Blob(os.toByteArray());
mf.setBlob(blob);
log.log(Level.INFO, "Size of techItemsByCountry: "
+ mfTechItemsByCountry.length());
mfDao.save(mf);
}
public Boolean checkCreateNewMap() {
Boolean runFlag = false;
Date lastPointDate = null;
AccessPointDao apDao = new AccessPointDao();
List<AccessPoint> apList = apDao.listAccessPointsByDateOrdered(
"createdDateTime", "desc", null);
MapControlDao mcDao = new MapControlDao();
MapControl mc = mcDao.getLatestRunTime();
if (apList != null)
if (apList.size() > 0)
if (apList.get(0) != null)
lastPointDate = apList.get(0).getCreatedDateTime();
if (lastPointDate != null
&& (mc == null || mc.getCreatedDateTime().before(lastPointDate)))
runFlag = true;
return runFlag;
}
}