import com.sun.j3d.utils.image.*;
import java.awt.*;
import java.io.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.awt.image.BufferedImage;
import com.sun.image.codec.jpeg.*;
import java.util.*;

public class CaptureCanvas3D extends Canvas3D{
    private Timer timer = new Timer();

    private Vector captureRequests = new Vector();

    public CaptureCanvas3D( GraphicsConfiguration gc ){
        super( gc );
    }
    public void captureOne( File file ){
        ImageHandler request = createRequest( file );
        synchronized( captureRequests ){
            captureRequests.add( request );
        }
    }
    public TimerTask startCapturing( final File destFolder, final String filePrefix, int period, final int startIndex ){
        TimerTask task = new TimerTask(){
            int index = startIndex;
            public void run(){
                captureOne( new File( destFolder, filePrefix + index + ".jpg" ) );
                index++;
            }
        };
        timer.scheduleAtFixedRate( task, 0, period );
        return task;
    }
    public void stopCapturing( TimerTask task ){
        task.cancel();
    }
    public void postSwap(){
        boolean pendingRequests = false;
        synchronized( captureRequests ){
            if( captureRequests.size() > 0 ){
                pendingRequests = true;
            }
        }
        if( pendingRequests ){
            BufferedImage img = createBufferedImage();
            handleRequests( img );
        }
    }
    private void handleRequests( BufferedImage img ){
        ImageHandler[] requests;
        synchronized( captureRequests ){
            requests = (ImageHandler[])captureRequests.toArray( new ImageHandler[captureRequests.size()] );
            captureRequests.clear();
        }
        for( int i = 0; i < requests.length; ++i ){
            requests[i].handleImage( img );
        }
    }
    private ImageHandler createRequest( final File f ){//must be called from postSwap
        ImageHandler request = new ImageHandler(){
            public void handleImage( BufferedImage img ){
                System.out.println( "Writing JPEG to " + f.getAbsolutePath() );
                writeToFile( img, f );
            }
        };
        return request;
    }
    private void writeToFile( BufferedImage image, File file ){
        try{
            FileOutputStream out = new FileOutputStream( file );
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder( out );
            JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam( image );
            param.setQuality( 1.0f, false );
            encoder.setJPEGEncodeParam( param );
            encoder.encode( image );
            out.close();
        }catch ( IOException e ){
            System.out.println("I/O exception!");
        }
    }
    private BufferedImage createBufferedImage(){
        GraphicsContext3D  ctx = getGraphicsContext3D();
        int w = getWidth();
        int h = getHeight();
        BufferedImage bi = new BufferedImage( w, h, BufferedImage.TYPE_INT_RGB );
        ImageComponent2D im = new ImageComponent2D( ImageComponent.FORMAT_RGB, bi );
        Raster ras = new Raster( new Point3f( -1.0f, -1.0f, -1.0f ), Raster.RASTER_COLOR, 0, 0, w, h, im, null );
        ctx.readRaster( ras );
        return ras.getImage().getImage();
    }
    interface ImageHandler{
        public void handleImage( BufferedImage img );
    }
}
