package me.osm.gazetter.join.out_handlers; import java.util.ArrayList; import java.util.Collections; import java.util.List; import me.osm.gazetter.out.AddrRowValueExctractorImpl; import me.osm.gazetter.striper.FeatureTypes; import org.json.JSONArray; import org.json.JSONObject; /** * Writes objects address as individual features. * * Originally objects like building, poi or highways * may have more than one address. * * For such objects, takes all address, and writes them * with data for object as individual objects. * * But preserve information that these objects linked to one * real world object via feature_id property. * */ public abstract class AddressPerRowJOHBase extends SingleWriterJOHBase { protected volatile boolean dropEmptyAddresses = true; @Override public void handle(JSONObject object, String stripe) { List<JSONObject> addresses = listAddresses(object, stripe); if(addresses != null && !addresses.isEmpty()) { for(JSONObject address : addresses) { handle(object, address, stripe); } } else if (!dropEmptyAddresses) { handle(object, null, stripe); } } /** * Get unique id for address row * * @param oject subject * @param addressRow subjects address * * @return unique id * */ public static String getUID(JSONObject oject, JSONObject addressRow) { return AddrRowValueExctractorImpl.getUID(oject, addressRow, oject.getString("ftype")); } protected void handle(JSONObject object, JSONObject address, String stripe) { String ftype = object.optString("ftype"); // Process only those of boundaries which wasn't splitted. // They are stored in binx.gjson if(ftype.equals(FeatureTypes.ADMIN_BOUNDARY_FTYPE) && stripe.startsWith("binx")) { handleAdminBoundaryAddrRow(object, address, stripe); } if(FeatureTypes.PLACE_POINT_FTYPE.equals(ftype)) { handlePlacePointAddrRow(object, address, stripe); } if(FeatureTypes.PLACE_BOUNDARY_FTYPE.equals(ftype)) { handlePlaceBoundaryAddrRow(object, address, stripe); } if(FeatureTypes.HIGHWAY_FEATURE_TYPE.equals(ftype)) { handleHighwayAddrRow(object, address, stripe); } if(FeatureTypes.HIGHWAY_NET_FEATURE_TYPE.equals(ftype)) { handleHighwayNetAddrRow(object, address, stripe); } if(FeatureTypes.JUNCTION_FTYPE.equals(ftype)) { handleHighwaysJunction(object, address, stripe); } if(FeatureTypes.ADDR_POINT_FTYPE.equals(ftype)) { handleAddrNodeAddrRow(object, address, stripe); } if(FeatureTypes.POI_FTYPE.equals(ftype)) { handlePoiPointAddrRow(object, address, stripe); } } /** * Override to process AdminBoundaries * */ protected void handleAdminBoundaryAddrRow(JSONObject object, JSONObject address, String stripe) { } /** * Override to process Place points * */ protected void handlePlacePointAddrRow(JSONObject object, JSONObject address, String stripe) { } /** * Override to process Highways * */ protected void handleHighwayAddrRow(JSONObject object, JSONObject address, String stripe) { } /** * Override to process Highways * */ protected void handlePlaceBoundaryAddrRow(JSONObject object, JSONObject address, String stripe) { } /** * Override to process Highways networks * */ protected void handleHighwayNetAddrRow(JSONObject object, JSONObject address, String stripe) { } /** * Override to process Highways Junctions * */ protected void handleHighwaysJunction(JSONObject object, JSONObject address, String stripe) { } /** * Override to process Address nodes * */ protected void handleAddrNodeAddrRow(JSONObject object, JSONObject address, String stripe) { } /** * Override to process Poi nodes * */ protected void handlePoiPointAddrRow(JSONObject object, JSONObject address, String stripe) { } protected List<JSONObject> listAddresses(JSONObject jsonObject, String stripe) { String ftype = jsonObject.optString("ftype"); if(FeatureTypes.ADDR_POINT_FTYPE.equals(ftype)) { JSONArray addresses = jsonObject.optJSONArray("addresses"); if(addresses != null) { List<JSONObject> result = new ArrayList<JSONObject>(); for(int ri = 0; ri < addresses.length(); ri++ ) { result.add(addresses.getJSONObject(ri)); } return result; } } else if(FeatureTypes.HIGHWAY_FEATURE_TYPE.equals(ftype)) { JSONArray boundaries = jsonObject.optJSONArray("boundaries"); if(boundaries != null) { List<JSONObject> result = new ArrayList<JSONObject>(); for(int i = 0; i < boundaries.length(); i++) { result.add(boundaries.getJSONObject(i)); } return result; } } else if(FeatureTypes.HIGHWAY_NET_FEATURE_TYPE.equals(ftype)) { JSONArray boundaries = jsonObject.optJSONArray("boundaries"); if(boundaries != null) { List<JSONObject> result = new ArrayList<JSONObject>(); for(int i = 0; i < boundaries.length(); i++) { result.add(boundaries.getJSONObject(i)); } return result; } } else if(FeatureTypes.PLACE_POINT_FTYPE.equals(ftype)) { JSONObject boundaries = jsonObject.optJSONObject("boundaries"); if(boundaries != null) { List<JSONObject> result = new ArrayList<JSONObject>(); result.add(boundaries); return result; } } else if(FeatureTypes.POI_FTYPE.equals(ftype)) { List<JSONObject> addresses = new ArrayList<JSONObject>(); String poiAddrMatch = fillPoiAddresses(jsonObject, addresses); if(addresses.isEmpty() || "nearest".equals(poiAddrMatch)) { if(jsonObject.optJSONObject("boundaries") == null) { return null; } poiAddrMatch = "boundaries"; addresses = new ArrayList<JSONObject>(Collections.singletonList(jsonObject.optJSONObject("boundaries"))); } for(JSONObject addrO : addresses) { addrO.put("poiAddrMatch", poiAddrMatch); } return addresses; } JSONObject b =jsonObject.optJSONObject("boundaries"); if(b != null) { return Collections.singletonList(jsonObject.optJSONObject("boundaries")); } return null; } private String fillPoiAddresses(JSONObject poi, List<JSONObject> result) { JSONObject joinedAddresses = poi.optJSONObject("joinedAddresses"); if(joinedAddresses != null) { //"sameSource" if(getAddressesFromObj(result, joinedAddresses, "sameSource")) { return "sameSource"; } //"contains" if(getAddressesFromCollection(result, joinedAddresses, "contains")) { return "contains"; } //"shareBuildingWay" if(getAddressesFromCollection(result, joinedAddresses, "shareBuildingWay")) { return "shareBuildingWay"; } //"nearestShareBuildingWay" if(getAddressesFromCollection(result, joinedAddresses, "nearestShareBuildingWay")) { return "nearestShareBuildingWay"; } //"nearest" if(getAddressesFromObj(result, joinedAddresses, "nearest")) { return "nearest"; } } return null; } private boolean getAddressesFromObj(List<JSONObject> result, JSONObject joinedAddresses, String key) { boolean founded = false; JSONObject ss = joinedAddresses.optJSONObject(key); if(ss != null) { JSONArray addresses = ss.optJSONArray("addresses"); if(addresses != null) { for(int i = 0; i < addresses.length(); i++) { result.add(addresses.getJSONObject(i)); } founded = true; } } return founded; } private boolean getAddressesFromCollection(List<JSONObject> result, JSONObject joinedAddresses, String key) { boolean founded = false; JSONArray contains = joinedAddresses.optJSONArray("contains"); if(contains != null && contains.length() > 0) { for(int ci = 0; ci < contains.length(); ci++) { JSONObject co = contains.getJSONObject(ci); JSONArray addresses = co.optJSONArray("addresses"); if(addresses != null) { for(int i = 0; i < addresses.length(); i++) { result.add(addresses.getJSONObject(i)); founded = true; } } } } return founded; } }