class ProjectionHandler {

    public Geometry preProcess(Geometry geometry) throws TransformException, FactoryException {
        // if there is no valid area, no cutting is required either
        if(validAreaBounds == null)
            return geometry;
        
        // if not reprojection is going on, we don't need to cut
        CoordinateReferenceSystem geometryCRS = CRS.getHorizontalCRS(sourceCRS);
        if (geometryCRS == null
                || CRS.findMathTransform(geometryCRS,
                        renderingEnvelope.getCoordinateReferenceSystem()).isIdentity()) {
            return geometry;
        }
        
        Geometry mask;
        // fast path for the rectangular case, more complex one for the
        // non rectangular one
        if(validArea == null) {
            // if the geometry is within the valid area for this projection
            // just skip expensive cutting
            ReferencedEnvelope ge = new ReferencedEnvelope(geometry.getEnvelopeInternal(), geometryCRS);
            ReferencedEnvelope geWGS84 = ge.transform(WGS84, true);
            if (validAreaBounds.contains((Envelope) geWGS84)) {
                return geometry;
            }

            // we need to cut, first thing, we intersect the geometry envelope
            // and the valid area in WGS84, which is a neutral, everything can
            // be turned into it, and then turn back the intersection into
            // the origin SRS
            ReferencedEnvelope envIntWgs84 = new ReferencedEnvelope(validAreaBounds.intersection(geWGS84), WGS84);
            
            // if the intersection is empty the geometry is completely outside of the valid area, skip it
            if(envIntWgs84.isEmpty()) {
                return null;
            }
                
            ReferencedEnvelope envInt = envIntWgs84.transform(geometryCRS, true);
            mask = JTS.toGeometry((Envelope) envInt);
        } else {
            // if the geometry is within the valid area for this projection
            // just skip expensive cutting
            ReferencedEnvelope ge = new ReferencedEnvelope(geometry.getEnvelopeInternal(), geometryCRS);
            ReferencedEnvelope geWGS84 = ge.transform(WGS84, true);
            if (validaAreaTester.contains(JTS.toGeometry(geWGS84))) {
                return geometry;
            }

            // we need to cut, first thing, we intersect the geometry envelope
            // and the valid area in WGS84, which is a neutral, everything can
            // be turned into it, and then turn back the intersection into
            // the origin SRS
            ReferencedEnvelope envIntWgs84 = new ReferencedEnvelope(validAreaBounds.intersection(geWGS84), WGS84);
            
            // if the intersection is empty the geometry is completely outside of the valid area, skip it
            if(envIntWgs84.isEmpty()) {
                return null;
            } 
            
            Polygon polyIntWgs84 = JTS.toGeometry(envIntWgs84);
            Geometry maskWgs84 = intersect(validArea, polyIntWgs84, geometryCRS);
            if(maskWgs84 == null || maskWgs84.isEmpty()) {
                return null;
            }
            mask = JTS.transform(maskWgs84, CRS.findMathTransform(WGS84, geometryCRS));
        }
        
        return intersect(geometry, mask, geometryCRS);
    }

    public  ProjectionHandler(CoordinateReferenceSystem sourceCRS, Envelope validAreaBounds, ReferencedEnvelope renderingEnvelope);
    public  ProjectionHandler(CoordinateReferenceSystem sourceCRS, Geometry validArea, ReferencedEnvelope renderingEnvelope);

}