import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Label;
import java.awt.Font;
import java.awt.Color;

/**
   Eine Klasse zu pädagogischen Zwecken (Einführung in die Informatik:
   Programmierung und Software-Entwicklung im WS 02/03, Institut für
   Informatik der Universität München). Erlaubt die Eingabe von Punktkoordinaten
   mittels Mausklicks sowie das Zeichnen von Linien.
   @version 1.1
*/

public class GraphicsWindow extends JFrame implements MouseListener {
  
    private static int fensterZahl;
    private static int fensterNr;
    private Label label;
    private GraphicsWindowPanel panel;
    private Point mousePos;
    /**
       Erzeugt ein Fenster mit Textausgabe, Mauseingabe und Grafikausgabe.
    */
    public GraphicsWindow() {
	super();
	setTitle("Grafikfenster " + ++fensterNr);
	fensterZahl++;
	setSize(600,600);
	
	addWindowListener(new WindowAdapter(){
		public void windowClosing(WindowEvent e) {
		    dispose(); // nicht gleich alle Fenster abschiessen
		    if (--fensterZahl<1) System.exit(0);
		}
	    });

	label = new Label("Statuszeile...");
	label.setFont(new Font("Helvetica", Font.PLAIN, 12));
	getContentPane().add(label,"North" );
	
	panel = new GraphicsWindowPanel();
	panel.setBackground(Color.cyan);
	getContentPane().add(panel,"Center");
	
	mousePos = new Point();
	panel.addMouseListener(this);
	show();
    }
    /**
       Gibt eine Zeichenkette oben im Fenster aus.
       @param text diese Zeichenkette
    */
    public void setText(String text) {
	label.setText(text);
    }
    /**
       Liest den oben im Fenster angezeigten Text aus.
       @return den Text
    */ 
    public String getText() {
	return label.getText();
    }
    /**
       Wartet auf einen Mausklick.
       (Das Warten verbraucht im Gegensatz zur Version 1.0
       vom 30. Oktober 2002 keine CPU-Ressourcen.)
       @return die Koordinaten des angeklickten Punkts
    */
    synchronized public Point mouseClick() {
	try{
	    wait();
	}
	catch(InterruptedException e){
	    e.printStackTrace();
	}
	return mousePos;
    }
    /**
       Beendet das Warten auf den Mausklick und verwertet die Koordinaten.
       Diese Methode ist nicht für den Anwender bestimmt.
     */
    synchronized public void mouseClicked(MouseEvent e){
	mousePos = e.getPoint();
	notify();
    }

    /**
       leere Implementierung (nur aus formalen Gründen vorhanden)
    */
    public void mouseEntered(MouseEvent e){
    }
    /**
       leere Implementierung (nur aus formalen Gründen vorhanden)
    */
    public void mouseExited(MouseEvent e){
    }
    /**
       leere Implementierung (nur aus formalen Gründen vorhanden)
    */
    public void mousePressed(MouseEvent e){
    }
    /**
       leere Implementierung (nur aus formalen Gründen vorhanden)
    */
    public void mouseReleased(MouseEvent e){
    }


    /**
       Schaltet die Zeichenfarbe auf die Hintergrundfarbe um. Dies ist das
       Mittel, um gezeichnete Linien wieder zu löschen.
    */
    public void switchToBackgroundColour(){
	panel.kommandos[panel.kommandoZahl++] = -1;
	panel.repaint();
    }
    /**
       Schaltet die Zeichenfarbe (wieder) auf Schwarz um.
    */
    public void switchToForegroundColour(){
	panel.kommandos[panel.kommandoZahl++] = 1;
	panel.repaint();
    }
    /**
       Zeichnet eine Linie in der aktuellen Zeichenfarbe.
       Hinweis für Insider: Werden die Parameter (die Punkt-Objekte sind)
       nach dem Aufruf dieser Methode geändert, so ändert sich die bisherige
       Zeichnung im Grafikfenster NICHT.
       @param x Anfangspunkt
       @param y Endpunkt
    */
    public void drawLine(Point x, Point y){
	int i = panel.kommandoZahl;
	panel.kommandos[i] = 0;
	panel.ersterPunkt[i] = new Point(x);
	panel.zweiterPunkt[i] = new Point(y);
	panel.kommandoZahl++;
	panel.repaint();
    }
}

/**
   Eine Hilfsklasse, die das Zeichenfeld darstellt. Alle Farbwechselbefehle
   und die gezeichneten Linien werden hier gespeichert und erlauben so das
   Wiederzeichnen, wenn dies vom Window-Manager angefordert wird.
*/
class GraphicsWindowPanel extends JPanel{
    private final int MAX_LAENGE = 1000;  // maximale Zahl der Malbefehle
    int[] kommandos = new int[MAX_LAENGE];
    Point[] ersterPunkt = new Point[MAX_LAENGE];
    Point[] zweiterPunkt = new Point[MAX_LAENGE];
    int kommandoZahl =0; // Zahl der schon abgesetzten Malbefehle
    /**
       Die Methode zum (Wieder-)Zeichen des Grafikfeldes.
       @param der vom System bereitgestellte Grafikkontext
    */
    public void paintComponent(Graphics g){
	super.paintComponent(g);
	Graphics2D g2D = (Graphics2D)g;
	for(int i=0; i<kommandoZahl; i++){
	    if (kommandos[i]==0) g2D.drawLine(ersterPunkt[i].x,
					      ersterPunkt[i].y,
					      zweiterPunkt[i].x,
					      zweiterPunkt[i].y);
	    else if (kommandos[i]==1) g2D.setColor(Color.black);
	    else if (kommandos[i]==-1) g2D.setColor(getBackground());
	    else System.exit(-1); // waere ein Programmierfehler
	}
    }
}
