import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/**
 * One hack is directly copied from SwingHacks book.
 * @author praveenm
 */
public class Dissolver extends JComponent implements Runnable {
    Window frame;
    Window fullscreen;
    int count;
    BufferedImage frame_buffer;
    BufferedImage screen_buffer;
    public static enum DISSOLVE_TYPE { VERTICAL,HORIZONTAL,BOTH,ANIMATED }


    public Dissolver(Window frame) {
        this.frame=frame;
    }

    private void dissolveWithHeightAndWidth(){
        int height = frame.getHeight();
        int width = frame.getWidth();
        for(;;){
            frame.setSize(height,width);
            height=height-5;
            width=width-5;
            frame.setLocationRelativeTo(null);
            frame.validate();
            if(height<=2) break;
        }
    }
    public void dissolve(DISSOLVE_TYPE c){
        if(c.equals(DISSOLVE_TYPE.HORIZONTAL)){
            this.dissolveWithWidth();
        }else if(c.equals(DISSOLVE_TYPE.VERTICAL)){
            this.dissolveWithHeight();
        }else if(c.equals(DISSOLVE_TYPE.BOTH)){
            this.dissolveWithHeightAndWidth();
        }else{
            this.dissolveExit();
        }
    }

    private void dissolveWithWidth(){
        int height = frame.getHeight();
        int width = frame.getWidth();
        for(;;){
            frame.setSize(height,width);
            frame.validate();
            height-=5;
            if(height<=10) break;
        }
    }
    private void dissolveWithHeight(){
        int height = frame.getHeight();
        int width = frame.getWidth();
        for(;;){
            frame.setSize(height,width);
            frame.validate();
            width-=5;
            if(width<=5) break;
        }

    }

    public void dissolveExit() {
        try {
            Robot robot = new Robot( );
            // cap screen w/ frame to frame buffer
            Rectangle frame_rect = frame.getBounds();
            frame_buffer = robot.createScreenCapture(frame_rect);
            // hide frame
            frame.setVisible(false);
            // cap screen w/o frame
            Dimension screensize = Toolkit.getDefaultToolkit()
            .getScreenSize();
            Rectangle screen_rect = new Rectangle(0,0,
                    screensize.width, screensize.height);
            screen_buffer = robot.createScreenCapture(screen_rect);

            // create big window w/o decorations
            fullscreen = new Window(new JFrame( ));
            fullscreen.setSize(screensize);
            fullscreen.add(this);
            this.setSize(screensize);
            fullscreen.setVisible(true);

            // start animation
            new Thread(this).start();
            //Thread.currentThread().sleep(1000);
        } catch (Throwable ex) {
            System.out.println(ex);
            ex.printStackTrace( );
        }

    }

    public void run( ) {
            for(int i=0; i<10; i++) {
                count = i;
                fullscreen.repaint();
                fullscreen.validate();
                try {
                Thread.currentThread().sleep(100);
                } catch (InterruptedException ex) { }
            }

        System.exit(1);
    }

    public void paint(Graphics g) {
        Graphics2D g2 = (Graphics2D)g;
        // draw the screen, offset in case the window isn't at 0,0
        g.drawImage(screen_buffer,-fullscreen.getX( ),
                -fullscreen.getY( ),null);

        // save the current transform
        AffineTransform old_trans = g2.getTransform( );

        // move to the upper-lefthand corner of the frame
        g2.translate(frame.getX( ), frame.getY( ));

        // move the frame off toward the left
        g2.translate(-((count+1) * (frame.getX( )+frame.getWidth( ))/20),0);
        // shrink the frame
        float scale = 1f / ((float)count+1);
        g2.scale(scale,scale);
        // rotate around the center
        g2.rotate(((float)count)/3.14/1.3,
                frame.getWidth( )/2, frame.getHeight( )/2);
        // finally draw the frame

        g2.drawImage(frame_buffer,0,0,null);
        // restore the current transform
        g2.setTransform(old_trans);
    }

    // Testing dissolve
    public static void main(String[] args){
        final JFrame jf = new JFrame("Dissolving Hacks");
        final Dissolver dis = new Dissolver(jf);
        JPanel jp = new JPanel();
        DISSOLVE_TYPE vals[] = DISSOLVE_TYPE.values();
        for(DISSOLVE_TYPE type:vals){
            jp.add(dis.get(type));
        }
        jf.add(new JButton("<html><body><center><b>Dissolve Hacks</b></center></body><html>"),BorderLayout.CENTER);
        jf.add(jp,BorderLayout.SOUTH);
        jf.setSize(600,600);
        jf.setVisible(true);
        jf.setMaximumSize(new Dimension(600,600));
        jf.addWindowListener(new WindowAdapter(){
            public void windowClosing(WindowEvent evt){
                Dissolver d =new Dissolver(jf);
                d.dissolveExit();
            }

        });
    }

    private JButton get(final DISSOLVE_TYPE type){
        return new JButton(new AbstractAction(type.toString()){
            public void actionPerformed(ActionEvent evt) {
                dissolve(type);
                if(!type.equals(DISSOLVE_TYPE.ANIMATED))
                 System.exit(0);
            }
        });

    }
}