package fr.gael.dhus.server.http.webapp.stub.controller;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.geotools.gml2.GMLConfiguration;
import org.geotools.xml.Configuration;
import org.geotools.xml.Parser;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.xml.sax.InputSource;
import com.spatial4j.core.context.jts.JtsSpatialContext;
import com.spatial4j.core.context.jts.JtsSpatialContextFactory;
import com.spatial4j.core.context.jts.ValidationRule;
import com.spatial4j.core.shape.jts.JtsGeometry;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Polygon;
import fr.gael.dhus.database.object.MetadataIndex;
import fr.gael.dhus.database.object.Product;
import fr.gael.dhus.server.http.webapp.stub.controller.stub_share.MetadataIndexData;
import fr.gael.dhus.server.http.webapp.stub.controller.stub_share.ProductData;
import fr.gael.dhus.spring.context.ApplicationContextProvider;
import java.util.AbstractList;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.common.SolrDocumentList;
@RestController
public class StubSearchController {
private static Log logger = LogFactory.getLog (StubSearchController.class);
@RequestMapping (value = "/products")
public List<ProductData> newsearch (@RequestParam(value="filter", defaultValue="") String filter, @RequestParam(value="offset", defaultValue="0")int startIndex,
@RequestParam(value="limit", defaultValue="")int numElement, @RequestParam(value="sortedby", defaultValue="ingestiondate") String sortedby,
@RequestParam(value="order", defaultValue="desc") String order)
{
fr.gael.dhus.service.SearchService searchService = ApplicationContextProvider
.getBean(fr.gael.dhus.service.SearchService.class);
final fr.gael.dhus.service.ProductService productService=
ApplicationContextProvider.getBean(
fr.gael.dhus.service.ProductService.class);
ArrayList<ProductData> productDatas = new ArrayList<ProductData>();
try {
SolrQuery.ORDER solrOrder = SolrQuery.ORDER.desc;
if(order.equalsIgnoreCase("asc")){
solrOrder = SolrQuery.ORDER.asc;
}
SolrQuery sQuery = new SolrQuery();
sQuery.setQuery(filter);
sQuery.setSort(sortedby, solrOrder);
sQuery.setStart(startIndex);
sQuery.setRows(numElement);
final SolrDocumentList results =
searchService.search(sQuery);
List<Product > products = new AbstractList<Product>()
{
@Override
public Product get(int index)
{
Long pid = (Long) results.get(index).get("id");
return productService.getProduct(pid);
}
@Override
public int size()
{
return results.size();
}
};
if (products != null) {
for (Product product : products) {
if(product != null) {
ProductData productData =
new ProductData(product.getId(), product.getUuid(),
product.getIdentifier());
// Set the Footprint if any
productData.setFootprint(
StubSearchController.convertGMLToDoubleLonLat(
product.getFootPrint()));
logger.debug("JTS FOOTPRINT");
logger.debug(productData.getFootprint());
ArrayList<String> summary = new ArrayList<String>();
ArrayList<MetadataIndexData> indexes =
new ArrayList<MetadataIndexData>();
for (MetadataIndex index :
productService.getIndexes(product.getId())) {
MetadataIndexData category =
new MetadataIndexData(index.getCategory(), null);
int i = indexes.indexOf(category);
if (i < 0) {
category.addChild(new MetadataIndexData(
index.getName(), index.getValue()));
indexes.add(category);
} else {
indexes.get(i).addChild(
new MetadataIndexData(index.getName(), index
.getValue()));
}
if ("summary".equals(index.getCategory())) {
summary.add(index.getName() + " : " + index.getValue());
Collections.sort(summary, null);
}
if ("Instrument".equalsIgnoreCase(index.getName())) {
productData.setInstrument(index.getValue());
}
if ("Product type".equalsIgnoreCase(index.getName())) {
productData.setProductType(index.getValue());
}
}
productData.setSummary(summary);
productData.setIndexes(indexes);
productData.setItemClass(product.getItemClass());
productData.setHasQuicklook(product.getQuicklookFlag());
productData.setHasThumbnail(product.getThumbnailFlag());
productDatas.add(productData);
}
}
}
return productDatas;
} catch (Exception e) {
e.printStackTrace();
}
return productDatas;
}
@RequestMapping (value = "/products/count")
public int getProductsCount (@RequestParam(value="filter", defaultValue="") String filter)
{
int count=0;
fr.gael.dhus.service.SearchService searchService = ApplicationContextProvider
.getBean(fr.gael.dhus.service.SearchService.class);
try {
count = searchService.getResultCount(filter);
//logger.info("Retrieved Products: " + count);
} catch (Exception e) {
logger.error("Error while getting products count: " + e.getMessage());
e.printStackTrace();
}
return count;
}
// test!
public static Double [][][]convertGMLToDoubleLonLat (String gml)
{
if (gml ==null || gml.trim ().isEmpty ()) return null;
Configuration configuration = new GMLConfiguration ();
Parser parser = new Parser (configuration);
Geometry footprint;
try
{
footprint = (Geometry) parser.parse (new InputSource (
new StringReader (gml)));
}
catch (Exception e)
{
logger.error ("Cannot read GML coordinates: " +
(gml==null?gml:gml.trim ()), e);
return null;
}
JtsSpatialContext ctx = JtsSpatialContext.GEO;
GeometryFactory geometryFactory = ctx.getGeometryFactory();
List<Coordinate> sequence = new ArrayList<Coordinate>();
for (Coordinate coord : footprint.getCoordinates ())
{
ctx.verifyX(coord.y);
ctx.verifyY(coord.x);
sequence.add(new Coordinate (coord.y, coord.x));
}
LinearRing shell = geometryFactory.createLinearRing
(sequence.toArray(new Coordinate[sequence.size()]));
Polygon p = geometryFactory.createPolygon(shell, null);
JtsSpatialContextFactory factory = new JtsSpatialContextFactory ();
ValidationRule validationRule = factory.validationRule;
JtsGeometry jts;
try {
jts = ctx.makeShape(p, true, ctx.isAllowMultiOverlap());
if (validationRule != ValidationRule.none)
jts.validate();
} catch (RuntimeException re) {
//repair:
if (validationRule == ValidationRule.repairConvexHull) {
jts = ctx.makeShape(p.convexHull(), true, ctx.isAllowMultiOverlap());
} else if (validationRule == ValidationRule.repairBuffer0) {
jts = ctx.makeShape(p.buffer(0), true, ctx.isAllowMultiOverlap());
} else if (validationRule == ValidationRule.error) {
//get original coordinates without transformations
logger.debug("ValidationRule.error");
return getDoubleLonLatFromOriginalCoordinates(footprint.getCoordinates ());
}else {
//TODO there are other smarter things we could do like repairing inner holes and subtracting
// from outer repaired shell; but we needn't try too hard.
try {
jts = ctx.makeShape(p.getBoundary());
} catch (Exception e) {
logger.error("Not possible to get JTS footprint. Error: " + e.getMessage());
e.printStackTrace();
return null;
}
re.printStackTrace();
logger.error(re.getMessage());
return null;
}
}
if (factory.autoIndex)
jts.index();
Double[][][] pts;
if (jts.getGeom () instanceof MultiPolygon)
{
pts = new Double [((MultiPolygon)jts.getGeom ()).getNumGeometries ()][][];
for (int j = 0; j < ((MultiPolygon)jts.getGeom ()).getNumGeometries (); j++)
{
pts[j] = new Double[((MultiPolygon)jts.getGeom ()).getGeometryN (j).getNumPoints ()][2];
int i = 0;
for (Coordinate coord : ((MultiPolygon)jts.getGeom ()).getGeometryN (j).getCoordinates ())
{
pts[j][i] = new Double[2];
pts[j][i][0] = coord.x;
pts[j][i][1] = coord.y;
i++;
}
}
}
else
{
pts = new Double[1][jts.getGeom ().getNumPoints ()][2];
int i = 0;
for (Coordinate coord : jts.getGeom ().getCoordinates ())
{
pts[0][i] = new Double[2];
pts[0][i][0] = coord.x;
pts[0][i][1] = coord.y;
i++;
}
}
return pts;
}
/**
*
* @param coords
* @return Double Lon Lat from Original coordinates
*/
public static Double [][][] getDoubleLonLatFromOriginalCoordinates(Coordinate[] coords) {
Double[][][] pts;
pts = new Double[1][coords.length][2];
int i = 0;
for (Coordinate coord : coords)
{
pts[0][i] = new Double[2];
pts[0][i][0] = coord.y;
pts[0][i][1] = coord.x;
i++;
}
return pts;
}
}