/*
* 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.wms;
import java.awt.Dimension;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CancellationException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import org.geotoolkit.coverage.GridSampleDimension;
import org.geotoolkit.coverage.grid.GeneralGridGeometry;
import org.geotoolkit.coverage.grid.GridCoverageBuilder;
import org.geotoolkit.coverage.io.CoverageStoreException;
import org.geotoolkit.coverage.io.GridCoverageReadParam;
import org.geotoolkit.coverage.io.GridCoverageReader;
import org.geotoolkit.factory.FactoryFinder;
import org.apache.sis.geometry.GeneralEnvelope;
import org.geotoolkit.internal.referencing.CRSUtilities;
import org.geotoolkit.referencing.ReferencingUtilities;
import org.apache.sis.util.logging.Logging;
import org.geotoolkit.util.NamesExt;
import org.opengis.coverage.grid.GridCoverage;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.TransformException;
import org.opengis.util.GenericName;
import org.opengis.util.NameFactory;
import org.opengis.util.NameSpace;
import org.apache.sis.geometry.Envelopes;
import org.apache.sis.util.Utilities;
/**
*
* @author Johann Sorel (Geomatys)
* @module
*/
public class WMSCoverageReader extends GridCoverageReader{
private static final Logger LOGGER = Logging.getLogger("org.geotoolkit.wms");
public WMSCoverageReader(final WMSCoverageReference reference) {
try {
setInput(reference);
} catch (CoverageStoreException ex) {
//won't happen
LOGGER.log(Level.WARNING, ex.getMessage(), ex);
}
}
@Override
public void setInput(Object input) throws CoverageStoreException {
if(!(input instanceof WMSCoverageReference)){
throw new CoverageStoreException("Unsupported input type, can only be WMSCoverageReference.");
}
super.setInput(input);
}
@Override
public WMSCoverageReference getInput() throws CoverageStoreException {
return (WMSCoverageReference) super.getInput();
}
@Override
public List<? extends GenericName> getCoverageNames() throws CoverageStoreException, CancellationException {
final NameFactory dnf = FactoryFinder.getNameFactory(null);
final GenericName name = getInput().getName();
NameSpace ns = null;
if (NamesExt.getNamespace(name) != null) {
ns = dnf.createNameSpace(dnf.createGenericName(null, NamesExt.getNamespace(name)), null);
}
final GenericName gn = dnf.createLocalName(ns, name.tip().toString());
return Collections.singletonList(gn);
}
@Override
public GeneralGridGeometry getGridGeometry(final int index) throws CoverageStoreException, CancellationException {
final WMSCoverageReference ref = getInput();
//we only know the envelope,
final GeneralGridGeometry gridGeom = new GeneralGridGeometry(null, null, ref.getBounds());
return gridGeom;
}
@Override
public List<GridSampleDimension> getSampleDimensions(final int index) throws CoverageStoreException, CancellationException {
//unknowned
return null;
}
@Override
public GridCoverage read(final int index, GridCoverageReadParam param) throws CoverageStoreException, CancellationException {
if(index != 0){
throw new CoverageStoreException("Invalid Image index.");
}
if(param == null){
param = new GridCoverageReadParam();
}
final int[] desBands = param.getDestinationBands();
final int[] sourceBands = param.getSourceBands();
if(desBands != null || sourceBands != null){
throw new CoverageStoreException("Source or destination bands can not be used on WMS coverages.");
}
final WMSCoverageReference ref = getInput();
final WebMapClient server = (WebMapClient)ref.getStore();
CoordinateReferenceSystem crs = param.getCoordinateReferenceSystem();
Envelope wantedEnv = param.getEnvelope();
double[] resolution = param.getResolution();
//verify envelope and crs
if(crs == null && wantedEnv == null){
//use the max extent
wantedEnv = ref.getBounds();
crs = wantedEnv.getCoordinateReferenceSystem();
}else if(crs != null && wantedEnv != null){
//check the envelope crs matches given crs
if(!Utilities.equalsIgnoreMetadata(wantedEnv.getCoordinateReferenceSystem(),crs)){
throw new CoverageStoreException("Invalid parameters : envelope crs do not match given crs.");
}
}else if(wantedEnv != null){
//use the envelope crs
crs = wantedEnv.getCoordinateReferenceSystem();
}else if(crs != null){
//use the given crs
wantedEnv = ref.getBounds();
try {
wantedEnv = Envelopes.transform(wantedEnv, crs);
} catch (TransformException ex) {
throw new CoverageStoreException("Could not transform coverage envelope to given crs.");
}
}
//estimate resolution if not given
if(resolution == null){
//we arbitrarly choose 1000 pixel on first axis, wms layer have infinite resolution.
resolution = new double[2];
resolution[0] = wantedEnv.getSpan(0)/1000;
resolution[1] = resolution[0] * (wantedEnv.getSpan(1)/wantedEnv.getSpan(0));
}
final GeneralEnvelope env = new GeneralEnvelope(wantedEnv);
final GetMapRequest request = server.createGetMap();
//Filling the request header map from the map of the layer's server
final Map<String, String> headerMap = server.getRequestHeaderMap();
if (headerMap != null) {
request.getHeaderMap().putAll(headerMap);
}
//calculate image dimension
final Dimension dim = new Dimension(
(int)(env.getSpan(0) / resolution[0]),
(int)(env.getSpan(1) / resolution[1]));
try {
ref.prepareQuery(request, env, dim, null);
System.out.println(request.getURL());
} catch (TransformException ex) {
throw new CoverageStoreException(ex.getMessage(), ex);
} catch (Exception ex) {
throw new CoverageStoreException(ex.getMessage(), ex);
}
//read image
BufferedImage image = null;
InputStream stream = null;
try {
stream = request.getResponseStream();
image = ImageIO.read(stream);
final CoordinateReferenceSystem crs2d = CRSUtilities.getCRS2D(env.getCoordinateReferenceSystem());
final Envelope env2D = Envelopes.transform(env, crs2d);
final AffineTransform gridToCRS = ReferencingUtilities.toAffine(dim, env2D);
final GridCoverageBuilder gcb = new GridCoverageBuilder();
gcb.setName(ref.getCombinedLayerNames());
gcb.setRenderedImage(image);
gcb.setPixelAnchor(PixelInCell.CELL_CORNER);
gcb.setGridToCRS(gridToCRS);
gcb.setCoordinateReferenceSystem(crs2d);
return gcb.build();
} catch (IOException ex) {
throw new CoverageStoreException(ex.getMessage(), ex);
} catch (TransformException ex) {
throw new CoverageStoreException(ex.getMessage(), ex);
} finally {
if(stream != null){
try {
stream.close();
} catch (IOException ex) {
throw new CoverageStoreException(ex.getMessage(), ex);
}
}
}
}
@Override
public void dispose() throws CoverageStoreException {
//nothing to dispose, we must preserve the input
}
@Override
public void reset() throws CoverageStoreException {
//nothing to reset, we must preserve the input
}
}