/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2012, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library 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
* Lesser General Public License for more details.
*/
package org.geotoolkit.coverage.postgresql;
import java.awt.Dimension;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.logging.Level;
import org.apache.sis.geometry.GeneralDirectPosition;
import org.geotoolkit.storage.coverage.DefaultPyramid;
import org.geotoolkit.storage.coverage.DefaultPyramidSet;
import org.geotoolkit.storage.coverage.Pyramid;
import org.geotoolkit.referencing.cs.DiscreteReferencingFactory;
import org.geotoolkit.temporal.object.TemporalUtilities;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.util.FactoryException;
/**
*
* @author Johann Sorel (Geomatys)
*/
public class PGPyramidSet extends DefaultPyramidSet{
private final PGCoverageReference ref;
private boolean updated = false;
public PGPyramidSet(PGCoverageReference ref) {
this.ref = ref;
}
void mustUpdate(){
updated = false;
}
@Override
public synchronized Collection<Pyramid> getPyramids() {
updateModel();
return super.getPyramids();
}
/**
* Explore pyramids and rebuild model
*/
private synchronized void updateModel(){
if(updated) return;
super.getPyramids().clear();
final PGCoverageStore store = ref.getStore();
Connection cnx = null;
Statement stmt = null;
ResultSet rs = null;
try{
cnx = store.getDataSource().getConnection();
stmt = cnx.createStatement();
final int layerId = store.getLayerId(cnx,ref.getName().tip().toString());
final StringBuilder query = new StringBuilder();
query.append("SELECT p.id, p.epsg, pp.value FROM ");
query.append(store.encodeTableName("Pyramid"));
query.append(" as p ");
query.append("LEFT OUTER JOIN ");
query.append(store.encodeTableName("PyramidProperty"));
query.append(" AS pp ON pp.\"pyramidId\" = p.id");
query.append(" WHERE p.\"layerId\" = ");
query.append(layerId);
query.append(" AND (pp.key IS NULL OR pp.key = 'version')"); //grab version
if(ref.version==null || ref.version.getLabel().equals(PGVersionControl.UNSET)){
query.append(" AND pp.value IS NULL");
}else{
query.append(" AND pp.value = '");
query.append(TemporalUtilities.toISO8601Z(ref.version.getDate(), PGVersionControl.GMT0));
query.append("'");
}
final Map<Integer,String> map = new HashMap<Integer, String>();
rs = stmt.executeQuery(query.toString());
while(rs.next()){
map.put(rs.getInt(1),rs.getString(2));
}
store.closeSafe(null,stmt,rs);
for(Entry<Integer,String> entry : map.entrySet()){
super.getPyramids().add(readPyramid(cnx, entry.getKey(), entry.getValue()));
}
}catch(SQLException ex){
store.getLogger().log(Level.WARNING, ex.getMessage(),ex);
}catch(FactoryException ex){
store.getLogger().log(Level.WARNING, ex.getMessage(),ex);
}finally{
store.closeSafe(cnx, stmt, rs);
}
updated = true;
}
private Pyramid readPyramid(final Connection cnx, final int pyramidId, final String epsgcode) throws SQLException, FactoryException{
final CoordinateReferenceSystem crs = ref.getStore().getEPSGFactory().createCoordinateReferenceSystem(epsgcode);
DefaultPyramid pyramid = new DefaultPyramid(String.valueOf(pyramidId), this, crs);
final PGCoverageStore store = ref.getStore();
Statement stmt = null;
ResultSet rs = null;
try{
stmt = cnx.createStatement();
//get mosaic additional axis values to recreate discret axis
final SortedSet[] discretValues = new SortedSet[crs.getCoordinateSystem().getDimension()];
for(int i=0;i<discretValues.length;i++){
discretValues[i] = new TreeSet();
}
StringBuilder query = new StringBuilder();
query.append("SELECT ma.\"indice\", ma.\"value\" FROM ");
query.append(store.encodeTableName("Mosaic"));
query.append(" AS m , ");
query.append(store.encodeTableName("MosaicAxis"));
query.append(" AS ma WHERE m.\"pyramidId\" = ");
query.append(pyramidId);
query.append(" AND ma.\"mosaicId\" = m.\"id\"");
rs = stmt.executeQuery(query.toString());
while(rs.next()){
final int indice = rs.getInt(1);
final double value = rs.getDouble(2);
discretValues[indice].add(value);
}
store.closeSafe(rs);
final double[][] table = new double[discretValues.length][0];
for(int i=0;i<discretValues.length;i++){
final Object[] ds = discretValues[i].toArray();
final double[] vals = new double[ds.length];
for(int k=0;k<ds.length;k++){
vals[k] = (Double)ds[k];
}
table[i] = vals;
}
final CoordinateReferenceSystem dcrs = DiscreteReferencingFactory.createDiscreteCRS(crs, table);
pyramid = new DefaultPyramid(String.valueOf(pyramidId), this, dcrs);
query = new StringBuilder();
query.append("SELECT \"id\",\"upperCornerX\",\"upperCornerY\",\"gridWidth\",\"gridHeight\",\"scale\",\"tileWidth\",\"tileHeight\" FROM ");
query.append(store.encodeTableName("Mosaic"));
query.append(" WHERE \"pyramidId\" = ");
query.append(pyramidId);
rs = stmt.executeQuery(query.toString());
while(rs.next()){
final long mosaicId = rs.getLong(1);
final double cornerX = rs.getDouble(2);
final double cornerY = rs.getDouble(3);
final int gridWidth = rs.getInt(4);
final int gridHeight = rs.getInt(5);
final double scale = rs.getDouble(6);
final int tileWidth = rs.getInt(7);
final int tileHeight = rs.getInt(8);
final GeneralDirectPosition position = new GeneralDirectPosition(crs);
position.setOrdinate(0, cornerX);
position.setOrdinate(1, cornerY);
if(crs.getCoordinateSystem().getDimension() > 2){
//retrieve additional axis value
Statement stmt2 = null;
ResultSet rs2 = null;
try{
stmt2 = cnx.createStatement();
query = new StringBuilder();
query.append("SELECT \"indice\",\"value\" FROM ");
query.append(store.encodeTableName("MosaicAxis"));
query.append(" WHERE \"mosaicId\" = ");
query.append(mosaicId);
rs2 = stmt2.executeQuery(query.toString());
while(rs2.next()){
position.setOrdinate(rs2.getInt(1), rs2.getDouble(2));
}
}finally{
store.closeSafe(null, stmt2, rs2);
}
}
final PGGridMosaic mosaic = new PGGridMosaic(ref,
mosaicId, pyramid, position,
new Dimension(gridWidth, gridHeight),
new Dimension(tileWidth, tileHeight), scale);
pyramid.getMosaicsInternal().add(mosaic);
}
}catch(SQLException ex){
store.getLogger().log(Level.WARNING, ex.getMessage(),ex);
}finally{
store.closeSafe(null, stmt, rs);
}
return pyramid;
}
}