import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.jdesktop.animation.timing.Animator;
import org.jdesktop.animation.timing.interpolation.PropertySetter;
import org.jdesktop.animation.transitions.Effect;
import org.jdesktop.animation.transitions.EffectsManager;
import org.jdesktop.animation.transitions.ScreenTransition;
import org.jdesktop.animation.transitions.TransitionTarget;
import org.jdesktop.animation.transitions.effects.CompositeEffect;
import org.jdesktop.animation.transitions.effects.FadeIn;
/*
 * SearchTransition.java
 *
 * Created on May 3, 2007, 3:05 PM
 *
 * Copyright (c) 2007, Sun Microsystems, Inc
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the TimingFramework project nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 *
 * @author Chet
 */
public class SearchTransition extends JComponent implements TransitionTarget, 
        ActionListener {
    //
    // GUI components used in the application screens
    //
    JLabel instructions = new JLabel("Szukajcie a znajdziecie...");
    JLabel searchLabel = new JLabel("Wyszukaj:");
    JTextField searchField = new JTextField("");
    JEditorPane results = new JEditorPane("text/html",
            "<html><body><b>Dung Beetles</b>: An Ode<br/>" +
            "My Life with <b>Dung Beetles</b><br/>" +
            "<b>Beetle</b> Bailey Gets Latrine Duty<br/>" +
            "Evolution's Oddities<br/>" +
            "Society's Parasites<br/>" +
            "You <b>Dung</b> Me Wrong: A Country Music History<br/>" +
            "Ding, <b>Dung</b>, The Witch is Dead<br/>" +
            "'To be or not to <b>beetle</b>'<br/>" +
            "Gross Insects of the World<br/>" +
            "Nature's Sanitation Engineers<br/>" +
            "Why are they here?<br/>" +
            "</body></html>");
    JScrollPane scroller = new JScrollPane(results);
    private static final int LABEL_W = 50;
    private static final int LABEL_H = 20;
    private static final int FIELD_W = 100;
    private static final int FIELD_H = 20;
    private static final int INSTRUCTIONS_W = 170;
    private static final int INSTRUCTIONS_H = 20;
    private static final int RESULTS_X = 30;
    
    //
    // Animation variables
    //
    Animator animator = new Animator(5000);    // Animate for half-second
    // Setup transition with:
    //      "this" as the transition container
    //      "this" as the TransitionTarget callback object
    //      animator as the animator that drives the transition
    ScreenTransition transition = new ScreenTransition(this,
            this, animator);
    private CompositeEffect moverFader = null;
    
    // 
    // Misc other instance variables
    //
    private int currentScreen = 0;      // Which screen are we on?
    private int prevHeight = -1;
    Paint bgGradient = null;
    int prevW, prevH;
    

    /** Creates a new instance of SearchTransition */
    public SearchTransition() {
        results.setEditable(false);
        
        // Setup the animation parameters
        animator.setAcceleration(.2f);  // Accelerate for first 20%
        animator.setDeceleration(.4f);  // Decelerate for last 40%
        
        // Set this as the listener for entries in the search field
        searchField.addActionListener(this);
        
        instructions.setFont(instructions.getFont().deriveFont(15f));
    }
    
    @Override
    public void setBounds(int x, int y, int w, int h) {
        super.setBounds(x, y, w, h);

        if (w != prevW || h != prevH) {
            // Setup GUI for current screen given new size of our container
            setupNextScreen();
            prevW = w;
            prevH = h;
        }
    }
    
    /**
     * Arrange the GUI for the initial search screen.
     */
    private void setupSearchScreen() {
        int instructionsX =  (getWidth() - INSTRUCTIONS_W) / 2;
        int instructionsY = getHeight() / 4;
        int searchX = (getWidth() - LABEL_W - FIELD_W - 10) / 2;
        int searchY = instructionsY + INSTRUCTIONS_H + 20;
        int fieldX = searchX + LABEL_W + 10;
        int fieldY = searchY;
        add(instructions);
        add(searchLabel);
        add(searchField);
        instructions.setBounds(instructionsX, instructionsY, 
                INSTRUCTIONS_W, INSTRUCTIONS_H);
        searchLabel.setBounds(searchX, searchY, LABEL_W, LABEL_H);
        searchField.setBounds(fieldX, fieldY, FIELD_W, FIELD_H);
    }
    
    /**
     * Arrange the GUI for the results screen
     */
    public void setupResultsScreen() {
        int searchX = getWidth() - LABEL_W - FIELD_W - RESULTS_X - 10;
        int searchY = 10;
        int fieldX = searchX + LABEL_W + 10;
        int fieldY = searchY;
        int resultsX = RESULTS_X;
        int resultsY = searchY + LABEL_H + 20;
        add(searchLabel);
        add(searchField);
        add(scroller);
        searchLabel.setBounds(searchX, 10, LABEL_W, LABEL_H);
        searchField.setBounds(fieldX, fieldY, FIELD_W, FIELD_H);
        scroller.setBounds(resultsX, resultsY, 
                getWidth() - (2 * resultsX), getHeight() - resultsY - 20);
    }
    
    /**
     * Change the gradient and effect according to the new window size
     */
    private void setupBackgroundAndEffect() {
        // init the background gradient according to current height
        bgGradient = new GradientPaint(0, 0, Color.LIGHT_GRAY.brighter(), 
                0, getHeight(), Color.DARK_GRAY.brighter());
        
        // Init resultsEffect with current component size info
        MoveIn mover = new MoveIn(RESULTS_X, getHeight());
        FadeIn fader = new FadeIn();
        moverFader = new CompositeEffect(mover);
        moverFader.addEffect(fader);
        EffectsManager.setEffect(scroller, moverFader, EffectsManager.TransitionType.APPEARING);
        prevHeight = getHeight();
    }
    
    /**
     * Override of paintComponent() to draw the gradient background
     */
    @Override
    protected void paintComponent(Graphics g) {
        if (bgGradient == null || getHeight() != prevHeight) {
            setupBackgroundAndEffect();
        }
        ((Graphics2D)g).setPaint(bgGradient);
        g.fillRect(0, 0, getWidth(), getHeight());
    }

    /**
     * TransitionTarget callback; clear current state and set up
     * state for next screen
     */
    public void setupNextScreen() {
        // Clear out current GUI state
	removeAll();
        switch (currentScreen) {
            case 0:
                setupSearchScreen();
                break;
            case 1:
                setupResultsScreen();
                break;
            default:
                break;
        }
    }
    
    // Handle user hitting Enter in the search field
    public void actionPerformed(ActionEvent ae) {
        if (moverFader == null || prevHeight != getHeight()) {
            setupBackgroundAndEffect();
        }
        // Change currentScreen, used later in setupNextScreen() callback
        currentScreen = (currentScreen == 0) ? 1 : 0;
        transition.start();
    }
    
    private static void createAndShowGUI() {
	JFrame f = new JFrame();
	f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	f.setSize(400, 300);
	SearchTransition component = new SearchTransition();
	f.add(component);
	f.setVisible(true);
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        } catch (InstantiationException ex) {
            ex.printStackTrace();
        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
        } catch (UnsupportedLookAndFeelException ex) {
            ex.printStackTrace();
        }
	Runnable doCreateAndShowGUI = new Runnable() {
	    public void run() {
		createAndShowGUI();
	    }
	};
	SwingUtilities.invokeLater(doCreateAndShowGUI);
    }
}

/**
 * Custom effect: moves a component in to its end location
 * from a specified starting point
 */
class MoveIn extends Effect {
    
    private Point startLocation = new Point();
    
    public MoveIn(int x, int y) {
        startLocation.x = x;
        startLocation.y = y;
    }

    /**
     * Handles setup of animation that will vary the location during the
     * transition
     */
    @Override
    public void init(Animator animator, Effect parentEffect) {
        Effect targetEffect = (parentEffect == null) ? this : parentEffect;
        PropertySetter ps;
        ps = new PropertySetter(targetEffect, "location", 
                startLocation, new Point(getEnd().getX(), getEnd().getY()));
        animator.addTarget(ps);
        super.init(animator, parentEffect);
    }
}
