class GeoTiffReader extends AbstractGridCoverage2DReader implements GridCoverage2DReader {

	public GridCoverage2D read(GeneralParameterValue[] params) throws IOException {
		GeneralEnvelope requestedEnvelope = null;
		Rectangle dim = null;
		Color inputTransparentColor=null;
		OverviewPolicy overviewPolicy=null;
		int[] suggestedTileSize=null;
		if (params != null) {

			//
			// Checking params
			//
			if (params != null) {
				for (int i = 0; i < params.length; i++) {
					final ParameterValue param = (ParameterValue) params[i];
					final ReferenceIdentifier name = param.getDescriptor().getName();
					if (name.equals(AbstractGridFormat.READ_GRIDGEOMETRY2D.getName())) {
						final GridGeometry2D gg = (GridGeometry2D) param.getValue();
						requestedEnvelope = new GeneralEnvelope((Envelope) gg.getEnvelope2D());
						dim = gg.getGridRange2D().getBounds();
						continue;
					}
					if (name.equals(AbstractGridFormat.OVERVIEW_POLICY.getName())) {
						overviewPolicy=(OverviewPolicy) param.getValue();
						continue;
					}	
                    if (name.equals(AbstractGridFormat.INPUT_TRANSPARENT_COLOR.getName())) {
                        inputTransparentColor = (Color) param.getValue();
                        continue;
                    }	
                    if (name.equals(AbstractGridFormat.SUGGESTED_TILE_SIZE.getName())) {
                        String suggestedTileSize_= (String) param.getValue();
                        if(suggestedTileSize_!=null&&suggestedTileSize_.length()>0){
                            suggestedTileSize_=suggestedTileSize_.trim();
                            int commaPosition=suggestedTileSize_.indexOf(",");
                            if(commaPosition<0){
                                int tileDim=Integer.parseInt(suggestedTileSize_);
                                suggestedTileSize= new int[]{tileDim,tileDim};
                            } else {
                                int tileW=Integer.parseInt(suggestedTileSize_.substring(0,commaPosition));
                                int tileH=Integer.parseInt(suggestedTileSize_.substring(commaPosition+1));
                                suggestedTileSize= new int[]{tileW,tileH};
                            }
                        }
                        continue;
                    }                                               
				}
			}
		}

		//
		// set params
		//
		Integer imageChoice = new Integer(0);
		final ImageReadParam readP = new ImageReadParam();
		try {
			imageChoice = setReadParams(overviewPolicy, readP,requestedEnvelope, dim);
		} catch (TransformException e) {
			new DataSourceException(e);
		}

		//
		// IMAGE READ OPERATION
		//
        Hints newHints = null;
		if(suggestedTileSize!=null){
		    newHints= hints.clone();
            final ImageLayout layout = new ImageLayout();
            layout.setTileGridXOffset(0);
            layout.setTileGridYOffset(0);
            layout.setTileHeight(suggestedTileSize[1]);
            layout.setTileWidth(suggestedTileSize[0]);
            newHints.add(new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout));
		}
		final ParameterBlock pbjRead = new ParameterBlock();
        if (extOvrImgChoice >= 0 && imageChoice >= extOvrImgChoice) {
            pbjRead.add(ovrInStreamSPI.createInputStreamInstance(ovrSource, ImageIO.getUseCache(),ImageIO.getCacheDirectory()));
            pbjRead.add(imageChoice - extOvrImgChoice);
        } else {
            pbjRead.add(inStreamSPI != null ? inStreamSPI.createInputStreamInstance(source, ImageIO.getUseCache(), ImageIO.getCacheDirectory()) : ImageIO.createImageInputStream(source));
            pbjRead.add(imageChoice);
        }
    	pbjRead.add(Boolean.FALSE);
		pbjRead.add(Boolean.FALSE);
		pbjRead.add(Boolean.FALSE);
		pbjRead.add(null);
		pbjRead.add(null);
		pbjRead.add(readP);
		pbjRead.add(READER_SPI.createReaderInstance());
		RenderedOp coverageRaster=JAI.create("ImageRead", pbjRead,newHints!=null?(RenderingHints) newHints:null);
		
        //
        // MASKING INPUT COLOR as indicated
        //
		if(inputTransparentColor!=null){
		    coverageRaster= new ImageWorker(coverageRaster).setRenderingHints(newHints).makeColorTransparent(inputTransparentColor).getRenderedOperation();
		}
		

        AffineTransform rasterToModel = getRescaledRasterToModel(coverageRaster);
        try {
            return createCoverage(coverageRaster, ProjectiveTransform.create(rasterToModel));
        } catch (Exception e) {
            // dispose and close file
            ImageUtilities.disposePlanarImageChain(coverageRaster);

            // rethrow
            if (e instanceof DataSourceException) {
                throw (DataSourceException) e;
            }
            throw new DataSourceException(e);
        }
	}

	public  GeoTiffReader(Object input);
	public  GeoTiffReader(Object input, Hints uHints);

}