/*
* This file is part of gwap, an open platform for games with a purpose
*
* Copyright (C) 2013
* Project play4science
* Lehr- und Forschungseinheit für Programmier- und Modellierungssprachen
* Ludwig-Maximilians-Universität München
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gwap.mit;
import gwap.model.action.Bet;
import gwap.model.resource.GeoPoint;
import gwap.model.resource.Location;
import gwap.model.resource.Location.LocationType;
import gwap.model.resource.LocationGeoPoint;
import gwap.model.resource.LocationHierarchy;
import gwap.model.resource.Statement;
import gwap.wrapper.LocationPercentage;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import javax.faces.model.SelectItem;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.log.Log;
/**
* Handles processing of geo data for display in the user interface
*
* @author Fabian Kneißl
*/
@Name("geoBean")
@Scope(ScopeType.SESSION)
@Path("/geodata")
public class GeoBean implements Serializable {
private static final long serialVersionUID = 1L;
@Logger private Log log;
@In
private EntityManager entityManager;
@In
private PokerScoring mitPokerScoring;
private List<Location> locations;
private List<SelectItem> locationsAsSelectItems;
private EntityManager getEntityManager() {
if (entityManager == null || !entityManager.isOpen())
entityManager = (EntityManager) Component.getInstance("entityManager");
return entityManager;
}
@GET
@Path("/markers/{hierarchyName}")
public String getMarkers(@PathParam("hierarchyName") String hierarchyName) {
return getMarkersInternal(null, hierarchyName, false);
}
@GET
@Path("/markers/{hierarchyName}/{parentId}")
public String getMarkers(@PathParam("parentId") Long parentId, @PathParam("hierarchyName") String hierarchyName) {
return getMarkersInternal(parentId, hierarchyName, false);
}
@GET
@Path("/markers-extended-title/{hierarchyName}")
public String getMarkersExtendedTitle(@PathParam("hierarchyName") String hierarchyName) {
return getMarkersInternal(null, hierarchyName, true);
}
@GET
@Path("/markers-extended-title/{hierarchyName}/{parentId}")
public String getMarkersExtendedTitle(@PathParam("parentId") Long parentId, @PathParam("hierarchyName") String hierarchyName) {
return getMarkersInternal(parentId, hierarchyName, true);
}
@GET
@Path("/percentagesbybet/{betId}")
public String getPercentagesByBet(@PathParam("betId") Long betId){
StringBuffer sb = new StringBuffer("{ \"markers\" : [");
GeoPoint min = new GeoPoint(Float.MAX_VALUE, Float.MAX_VALUE);
GeoPoint max = new GeoPoint(Float.MIN_VALUE, Float.MIN_VALUE);
Bet bet= getEntityManager().find(Bet.class, betId);
List<LocationPercentage> lp = mitPokerScoring.getStatementPercentages(bet.getResource());
Collections.sort(lp, new Comparator<LocationPercentage>() {
@Override
public int compare(LocationPercentage lp1, LocationPercentage lp2) {
return lp1.getLocation().getType().getLevel() - lp2.getLocation().getType().getLevel();
}
});
for(int i = 0; i<lp.size(); i++){
boolean highlightLocation = lp.get(i).getLocation().getId().equals(bet.getLocation().getId());
googleMapsLocation(sb, lp.get(i).getLocation(), min, max, false, lp.get(i).getPercentage(), highlightLocation);
}
sb.append("],\n");
sb.append(" \"bounds\" : new google.maps.LatLngBounds("+geoPointToLatLng(min)+","+geoPointToLatLng(max)+")");
sb.append("\n}");
return sb.toString();
}
@GET
@Path("/percentages/{statementId}")
public String getPercentages(@PathParam("statementId") Long statementId){
StringBuffer sb = new StringBuffer("{ \"markers\" : [");
GeoPoint min = new GeoPoint(Float.MAX_VALUE, Float.MAX_VALUE);
GeoPoint max = new GeoPoint(Float.MIN_VALUE, Float.MIN_VALUE);
Statement statement = getEntityManager().find(Statement.class, statementId);
List<LocationPercentage> lp = mitPokerScoring.getStatementPercentages(statement);
for(int i = 0; i<lp.size(); i++){
googleMapsLocation(sb, lp.get(i).getLocation(), min, max, false, lp.get(i).getPercentage(), false);
}
sb.append("],\n");
sb.append(" \"bounds\" : new google.maps.LatLngBounds("+geoPointToLatLng(min)+","+geoPointToLatLng(max)+")");
sb.append("\n}");
return sb.toString();
}
private String getMarkersInternal(Long parentId, String hierarchyName, boolean extendedTitle) {
log.info("Get locations for hierarchy #0 and parentId #1", hierarchyName, parentId);
boolean bottomLevel = false;
try {
Query q;
if (parentId == null) {
q = getEntityManager().createNamedQuery("location.topLevelByHierarchyName");
} else {
q = getEntityManager().createNamedQuery("location.containedIn");
q.setParameter("id", parentId);
}
q.setParameter("hierarchyName", hierarchyName);
locations = q.getResultList();
if (locations.size() == 1)
return getMarkersInternal(locations.get(0).getId(), hierarchyName, extendedTitle);
// Special case if we are at the bottom level
else if (locations.size() == 0)
bottomLevel = true;
} catch (Exception e) {
log.error("Could not get locations", e);
locations = null;
}
Location parentLocation = null;
if (parentId != null) {
parentLocation = getEntityManager().find(Location.class, parentId);
}
StringBuffer sb = new StringBuffer("{ \"markers\" : [");
GeoPoint min = new GeoPoint(Float.MAX_VALUE, Float.MAX_VALUE);
GeoPoint max = new GeoPoint(Float.MIN_VALUE, Float.MIN_VALUE);
if (!bottomLevel) {
for (Location location : locations) {
googleMapsLocation(sb, location, min, max, extendedTitle, null, false);
}
HashSet<Location> neighborLocations = new HashSet<Location>();
for (Location location : locations) {
List<Location> neighborList = location.getNeighbors();
for(Location locationTwo : neighborList)
neighborLocations.add(locationTwo);
}
for(Location neighborLocation : neighborLocations){
if(!locations.contains(neighborLocation))
googleMapsLocation(sb, neighborLocation, null, null, extendedTitle, null, false);
}
} else
googleMapsLocation(sb, parentLocation, min, max, extendedTitle, null, false);
sb.append("],\n");
sb.append(" \"bounds\" : new google.maps.LatLngBounds("+geoPointToLatLng(min)+","+geoPointToLatLng(max)+")");
if (parentLocation != null && parentLocation.getGeoRepresentation().size() > 0) {
sb.append(",\n \"parentMarker\" : ");
googleMapsLocation(sb, parentLocation, min, max, extendedTitle, null, false);
}
sb.append("\n}");
log.info("finished");
return sb.toString();
}
private void googleMapsLocation(StringBuffer sb, Location location, GeoPoint min, GeoPoint max, boolean extendedTitle, Double percentage, boolean highlightLocation) {
if (location == null)
return;
if(percentage != null && location.getType().equals(LocationType.MUNICIPALITY)) {
Location newLocation = nextHigherLocation(location);
if (newLocation == null) {
log.warn("Could not find nextLevelFromMunicipality for location #0", location);
return;
}
location = newLocation;
}
String locationName = location.getName();
if (extendedTitle)
locationName = getExtendedName(location);
if (location.getGeoRepresentation().size() == 1) {
// Point
GeoPoint geoPoint = location.getGeoRepresentation().get(0).getGeoPoint();
sb.append("new google.maps.Marker({ id : "+location.getId()+", title: \""+locationName+"\", map: gmap, " +
"position: new google.maps.LatLng("+geoPoint.getLatitude()+","+geoPoint.getLongitude()+"), " +
"icon : map.markerImage, shadow : map.shadowImage}),");
updateBounds(geoPoint, min, max);
} else if (location.getGeoRepresentation().size() > 0) {
// Polygon
sb.append("new google.maps.Polygon({ id : "+location.getId()+", title : \"");
sb.append(locationName);
sb.append("\", neighbors : [");
//Neighbors
List<Location> neighborList = location.getNeighbors();
for(int i = 0; i<neighborList.size(); i++){
if(i != 0)
sb.append(", " + neighborList.get(i).getId());
else
sb.append(neighborList.get(i).getId());
}
//Bets for visualization
sb.append("],\n");
if(percentage != null){
sb.append("percentage : ");
double aux = percentage;
sb.append((int)aux);
sb.append(",\n");
}
sb.append(" paths : [");
StringBuffer polygon = new StringBuffer("[");
GeoPoint beginPoint = new GeoPoint();
for (LocationGeoPoint point : location.getGeoRepresentation()) {
updateBounds(point.getGeoPoint(), min, max);
polygon.append(geoPointToLatLng(point.getGeoPoint()));
polygon.append(",");
if (beginPoint.getLatitude() == null || beginPoint.getLongitude() == null) {
beginPoint = point.getGeoPoint();
} else if (beginPoint.getLatitude().equals(point.getGeoPoint().getLatitude()) &&
beginPoint.getLongitude().equals(point.getGeoPoint().getLongitude())) {
polygon.append("],");
sb.append(polygon);
polygon = new StringBuffer("[");
beginPoint = new GeoPoint();
}
}
if(percentage == null){
if(highlightLocation)
sb.append("], strokeColor : \"#FF0000\", strokeOpacity : 1.0, strokeWeight : 2, fillColor : \"#0000FF\", fillOpacity : 0.05, map : gmap}), \n");
else
sb.append("], strokeColor : \"#3333FF\", strokeOpacity : 1.0, strokeWeight : 2, fillColor : \"#0000FF\", fillOpacity : 0.05, map : gmap}), \n");
}else{
double calcFillOpacity;
if(percentage <= 10.0)
calcFillOpacity = 0.3;
else if(percentage <= 20.0)
calcFillOpacity = 0.4;
else if(percentage <= 30.0)
calcFillOpacity = 0.5;
else if(percentage <= 40.0)
calcFillOpacity = 0.6;
else if(percentage <= 50.0)
calcFillOpacity = 0.7;
else
calcFillOpacity = 0.8;
if(highlightLocation)
sb.append("], strokeColor : \"#58D3F7\", strokeOpacity: 1.0, strokeWeight : 3, fillColor : \"#0000FF\", fillOpacity : " + calcFillOpacity + ", map : gmap,}), \n");
else
sb.append("], strokeColor : \"#3333FF\", strokeOpacity : 0.0, strokeWeight : 2, fillColor : \"#0000FF\", fillOpacity :" + calcFillOpacity + ", map : gmap,}), \n");
}
}
}
private Location nextHigherLocation(Location location) {
Location nextHigherLocation = null;
try {
LocationHierarchy locationHierarchy = (LocationHierarchy) entityManager
.createNamedQuery("locationHierarchy.nextLevelFromType")
.setParameter("sublocationId", location.getId())
.setParameter("locationType", LocationType.PROVINCE)
.getSingleResult();
nextHigherLocation = locationHierarchy.getLocation();
} catch (NoResultException e) {
try {
LocationHierarchy locationHierarchy = (LocationHierarchy) entityManager
.createNamedQuery("locationHierarchy.nextLevelFromType")
.setParameter("sublocationId", location.getId())
.setParameter("locationType", LocationType.CANTON)
.getSingleResult();
nextHigherLocation = locationHierarchy.getLocation();
} catch (NoResultException e2) {
}
}
return nextHigherLocation;
}
private String geoPointToLatLng(GeoPoint geoPoint) {
return "new google.maps.LatLng(" + geoPoint.getLatitude() + "," + geoPoint.getLongitude() +")";
}
private void updateBounds(GeoPoint point, GeoPoint min, GeoPoint max) {
if (min != null && max != null) {
min.setLatitude( Math.min(min.getLatitude(), point.getLatitude()));
min.setLongitude(Math.min(min.getLongitude(), point.getLongitude()));
max.setLatitude( Math.max(max.getLatitude(), point.getLatitude()));
max.setLongitude(Math.max(max.getLongitude(), point.getLongitude()));
}
}
public String getExtendedName(Location location) {
try {
Location region = (Location) entityManager.createNamedQuery("location.regionFromMunicipality")
.setParameter("id", location.getId()).setMaxResults(1).getSingleResult();
location.setExtendedName(location.getName() + " (" + region.getName() + ")");
} catch (NoResultException e) {
location.setExtendedName(location.getName());
}
return location.getExtendedName();
}
public List<SelectItem> getLocationsAsSelectItems() {
if (locationsAsSelectItems == null) {
Query q = getEntityManager().createNamedQuery("location.orderedByName");
List<Location> locations = q.getResultList();
locationsAsSelectItems = new ArrayList<SelectItem>();
for (Location location : locations) {
SelectItem item = new SelectItem(location.getId(), location.getExtendedName());
locationsAsSelectItems.add(item);
}
}
return locationsAsSelectItems;
}
public List<Location> getLocationsByApproximateName(Object search) {
if (search instanceof String) {
String startOfName = (String)search;
startOfName = startOfName.replaceAll("%", "");
List<Location> locations = getEntityManager()
.createNamedQuery("location.likeNameDefinedTypesOnly")
.setParameter("name", startOfName + "%")
.getResultList();
List<Location> sorted = new ArrayList<Location>();
int i = 0;
for (Location l : locations) {
if (l.getName().equalsIgnoreCase(startOfName))
sorted.add(i++, l); // add it to the front
else
sorted.add(l);
if (sorted.size() >= 20)
break;
}
return sorted;
}
return null;
}
public void doNothing() {
}
}