import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.URL;
import java.applet.*;
import java.util.Vector;

/**
 * GraphicsDemo is a graphic example for painting
 * images on swing components. The demo is structured
 * using the BorderLayout, where the north area contains
 * a few style buttons and the center area contains a panel
 * for painting. On this panel several images can be created,
 * moved, dragged and animated.
 */
public class GraphicsDemo extends JFrame  {
  //the main painting panel
  private PaintPanel panel;

  //the graphic components that are painted on the panel
  private Vector comps = new Vector();

  //the currently selected component
  private MyComp currentComp = null;

  //the toolkit instance for loading images
  private Toolkit toolkit;

  //the backround image for the main painting panel
  private Image boardImage;

  //a flag determining the style of the graphic components
  private boolean round = false;

  /**
   * the constructor creates the GraphicsDemo window during
   * three steps:
   * 1. setting the layout to BorderLayout
   * 2. creating two buttons and a painting panel
   * 3. registering the eventlisteners with the buttons and the painting panel
   */
  public GraphicsDemo() {
    //step 1
    this.getContentPane().setLayout(new BorderLayout());
    this.setTitle("GraphicsDemo");

    //step 2
    toolkit = Toolkit.getDefaultToolkit();
    boardImage = toolkit.getImage("board.gif");
    MediaTracker tr = new MediaTracker(this);
    tr.addImage(boardImage,0);
    try{
      tr.waitForAll();
    }catch(Exception ex){
    }

    JButton roundRect = new JButton("Paint Round Rectangle");
    JButton normalRect = new JButton("Paint Normal Rectangle");

    JPanel northPanel = new JPanel();
    northPanel.add(normalRect);
    northPanel.add(roundRect);

    panel = new PaintPanel();
    panel.setLayout(null);
    panel.setPreferredSize(new Dimension(boardImage.getWidth(null),
                           boardImage.getHeight(null)));

    this.getContentPane().add(panel, BorderLayout.CENTER);
    this.getContentPane().add(northPanel,BorderLayout.NORTH);

    //step 3
    roundRect.addActionListener(new ActionListener(){
      public void actionPerformed(ActionEvent e){
        round = true;
        panel.repaint();
      }
    });
    normalRect.addActionListener(new ActionListener(){
      public void actionPerformed(ActionEvent e){
        round = false;
        panel.repaint();
      }
    });
    panel.addMouseListener(new SelectionMouseListener());
    panel.addMouseMotionListener(new MoveMouseListener());
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  }

  /**
   * Represents a graphical component, that can be drawn on the
   * painting panel. Consists of an image and an bounding rectangle
   * for the image.
   */
  class MyComp{
    public final static int width = 50;
    public final static int height = 80;
    private Rectangle boundingRect;
    private Image image;
    private Image[] scaledImages = new Image[6];

    public MyComp(int x,int y){
      boundingRect = new Rectangle(x,y,MyComp.width,MyComp.height);
      this.image = toolkit.getImage("image.gif");
      this.scaledImages[0] = this.image;
      for (int i = 1; i < scaledImages.length; i++) {
        scaledImages[i] = this.image.getScaledInstance( (new ImageIcon(image)).
            getIconWidth() +
            (i) * 10,
            (new ImageIcon(image)).getIconHeight() +
            (i) * 10,
            Image.SCALE_FAST);
      }
    }
    public void resetImage(){
      image = scaledImages[0];
    }
    public Rectangle getBoundingRect(){
      return this.boundingRect;
    }
    public Image getImage(){
      return this.image;
    }
    public Image[] getScaledImages(){
      return this.scaledImages;
    }
  }

  /**
   * Represents the painting panel of the demo.
   * Draws the backround image, the mouse cursor (x,y) location
   * and the graphical components.
   */
  class PaintPanel extends JPanel{
    private String coordinates = new String();
    public PaintPanel() {
      super();
    }
    public void setCoordinates(String coordinates){
      this.coordinates = coordinates;
    }
    public void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (g != null) {
        g.drawImage(boardImage, 0, 0, null);
        g.drawString(coordinates,0,10);
        for (int i = 0; i < comps.size(); i++) {
          MyComp comp = (MyComp) comps.get(i);
          if (comp == currentComp) {
            if(round){
              g.fillRoundRect((int)comp.getBoundingRect().getX(),
                              (int)comp.getBoundingRect().getY(),
                              MyComp.width,
                              MyComp.height, 10, 10);
            }
            else{
              g.fillRect((int)comp.getBoundingRect().getX(),
                         (int)comp.getBoundingRect().getY(),
                         MyComp.width,
                         MyComp.height);
            }
          }
          else {
            if(round){
              g.drawRoundRect((int)comp.getBoundingRect().getX(),
                              (int)comp.getBoundingRect().getY(),
                              MyComp.width,
                              MyComp.height, 10, 10);
            }
            else{
              g.drawRect((int)comp.getBoundingRect().getX(),
                         (int)comp.getBoundingRect().getY(),
                         MyComp.width,
                         MyComp.height);
            }
          }
          g.drawImage(comp.getImage(), (int)comp.getBoundingRect().getX(),
                      (int)comp.getBoundingRect().getY(),
                      new ImageIcon(comp.getImage()).getImageObserver());
        }
      }
    }
  }

  /**
   * MouseListener for the painting panel.
   * Catches mouse clicks, double clicks, right clicks and mouse releases.
   * A right click on the painting panel creates a new graphic component at the mouse location.
   * A double click on a created graphic component starts the animation for
   * this component.
   * A simple click on a created graphic component selects the component.
   * A simple click on the painting panel moves a before selected graphic component
   * to this destination.
   * A mouse release simply repaints the painting panel.
   */
  class SelectionMouseListener extends MouseAdapter {
    public void mousePressed(MouseEvent evt) {
      int x= evt.getX(), y = evt.getY();

      //right click
      if(evt.isMetaDown()){
        comps.addElement(new MyComp(x,y));
        repaint();
      }
      //double click
      else if(evt.getClickCount() > 1){
        for(int i=0;i<comps.size();i++){
          MyComp c = (MyComp) comps.get(i);
          if(c.getBoundingRect().contains(x,y)){
	    //sound example, before starting the animation a simple sound file is loaded
	    //and played
	    /*try{
            AudioClip clip;
	    clip = Applet.newAudioClip(new URL("file:" + System.getProperty("user.dir") + "/bottle-open.wav"));
	    clip.play();
	    }catch(Exception e){
	      e.printStackTrace();
	    }*/

            TimerActionListener l = new TimerActionListener(c);
            Timer tim = new Timer(300,l);
            tim.start();
            l.setTimer(tim);
            break;
          }
        }
      }
      //simple click
      else{
        boolean found = false;
        for(int i=0;i<comps.size();i++){
          MyComp c = (MyComp) comps.get(i);
          if(c.getBoundingRect().contains(x,y)){
              currentComp = c;
              comps.removeElement(currentComp);
              comps.addElement(currentComp);
              found = true;
          }
        }
        if(!found && currentComp!=null){
          currentComp.getBoundingRect().setLocation(evt.getX(),evt.getY());
          currentComp = null;
	  panel.repaint();
        }
      }
    }

    public void mouseReleased(MouseEvent evt) {
      panel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
      panel.repaint();
    }
  }

  /**
   * MouseMotionListener for the painting panel.
   * Catches mouse moving and dragging.
   * Moving the mouse over the painting panel draws the (x,y) location
   * of the mouse on the paiting panel.
   */
  class MoveMouseListener extends MouseMotionAdapter{
    public void mouseDragged(MouseEvent evt) {
    }
    public void mouseMoved(MouseEvent evt){
      panel.setCoordinates("X: " + evt.getX() + "// Y: " + evt.getY());
      panel.repaint();
    }
  }



  /**
   *ActionListener for the animation timer.
   * Loads the scaled images of the graphic components
   * and displays them with a delay of 300 ms.
   */
  class TimerActionListener implements ActionListener{
    private MyComp cmp;
    private Timer tim;
    private int timerCount = 1;

    public TimerActionListener(MyComp cmp) {
      this.cmp = cmp;
    }
    public void setTimer(Timer tim) {
      this.tim = tim;
    }
    public void actionPerformed(ActionEvent e) {
      if (cmp != null) {
        if (timerCount < cmp.getScaledImages().length) {
          synchronized(cmp){
            cmp.image = cmp.getScaledImages()[timerCount];
            panel.repaint();
          }
          timerCount++;
        }
        else {
          tim.stop();
          synchronized(cmp){
            cmp.resetImage();
            panel.repaint();
          }
        }
      }
    }
  }

  public static void main(String[] args){
    GraphicsDemo demo = new GraphicsDemo();
    demo.setResizable(false);
    demo.pack();demo.show();
    //demo.setVisible(true);
  }
}



