import java.util.* ;
import java.awt.* ;
import java.awt.event.* ;
import java.awt.image.* ;

interface Fenetre
{
    /* Peint un rectangle de coin sup'erieur gauche (xa, ya) inclus
     * et de coin inf'erieur droit (xb, yb) exclus
     * avec la couleur coul.
     */
    void rectangle (int xa, int ya, int xb, int yb, int coul) ;

    /* Couleurs :
     * 0 pour blanc, 1 pour noir,
     * 2-255 pour une teinte pure :
     *   2-85 rouge au vert, 86-170 du vert au bleu, 
     *   171-255 du bleu au rouge.
     */
}


// --------- partie dessin de fenetre `a l''ecran -----------

class FenEcran extends Frame implements Fenetre
{

    public static void main (String[] args) {
	FenEcran f = new FenEcran (300) ;
        test (f) ;
    }

    static void test (FenEcran f) {
        // rectangle (50,70) (200, 100) de couleur noire :
        f.rectangle (50, 70, 200, 100, 1) ; 
        // rectangle (70,30) (150, 200) de couleur bleue :
        f.rectangle (70, 30, 150, 200, 170) ; 
    }

    int largeur ; // taille du dessin
    int marge ; // Un peu de blanc autour de [0,1]x[0,1]
    //Image bufimg ; // Buffer de dessin
    BufferedImage bufimg ; // Buffer de dessin
    ImgCanvas imgDisplayer ; // Composant awt affichant bufimg
    Color couleur ; // Couleur du prochain dessin.

    FenEcran (int larg) {
	super ("FenEcran") ;  // Titre de la fenetre

	largeur = larg ;
	marge = 3 ;
        couleur = Color.black ;

	// Pour quitter si on ferme la fen^etre :
        addWindowListener (new ExitWindowAdapter()) ;

        // Pour afficher l'image qui sera stock'ee dans bufimg :
        imgDisplayer = new ImgCanvas (largeur + 2*marge) ;
        add (imgDisplayer);

        // Calculer les dimensions et rendre visible :
        pack () ;
        setLocation (50, 0) ;
        setVisible (true) ;

	// Pour dessiner dans la fen^etre et ^etre capable de la redessiner,
	//   on dessine dans un buffer qui est copi'e 
	//   dans la fenetre.
	//bufimg = createImage (largeur+2*marge, largeur+2*marge) ;
	bufimg = new BufferedImage (largeur+2*marge, largeur+2*marge, BufferedImage.TYPE_3BYTE_BGR) ;
        // createImage () renvoie null tant qu'on a pas fait :
        //   setVisible (true) ; On peut maintenant donner `a imgDisplayer
        //   le buffer qu'il doit afficher :
        imgDisplayer.bufimg = bufimg ;

        // Effacer tout avant de commencer :
        clear () ;
    }

    // ----------- dessin de polygones ---------------


    public void rectangle (int ax, int ay, int bx, int by, int coul) {
        couleur (coul) ;
        int w = bx - ax, h = by - ay ;
        // Vers l'image buffer :
        Graphics graph = bufimg.getGraphics () ;
        graph.setColor (couleur) ;
        graph.fillRect (ax, ay, w, h) ;
	// Vers l''ecran :
	imgDisplayer.repaint (10, ax, ay, w, h) ;
    }

    static int[] xTrig = new int [3] ;
    static int[] yTrig = new int [3] ;

    public void triangle (int ax, int ay, int bx, int by, 
                          int cx, int cy, int coul) {
        couleur (coul) ;
	xTrig [0] = ax ;
	xTrig [1] = bx ;
	xTrig [2] = cx ;
	yTrig [0] = ay ;
	yTrig [1] = by ;
	yTrig [2] = cy ;
	polygone (xTrig, yTrig, 3, true ,false) ;
    }

    public void ligne (int ax, int ay, int bx, int by, int coul) {
        couleur (coul) ;
	xTrig [0] = ax ;
	xTrig [1] = bx ;
	yTrig [0] = ay ;
	yTrig [1] = by ;
	polygone (xTrig, yTrig, 2, false, true) ;
    }

    void polygone (int[] x, int[] y, int nbPts,
		   boolean fill, boolean outline) {
	// Partie de la fen^etre qu'il faudra redessiner :
	int  xmin=largeur+2*marge, xmax=0, ymin=largeur+2*marge, ymax=0 ;
	for (int i=0 ; i<x.length ; i++) {
	    if (x[i] < xmin) xmin = x[i] ;
	    if (x[i] > xmax) xmax = x[i] ;
	    if (y[i] < ymin) ymin = y[i] ;
	    if (y[i] > ymax) ymax = y[i] ;
	}
        // Vers l'image buffer :
        Graphics graph = bufimg.getGraphics () ;
        graph.setColor (couleur) ;
	if (fill) {
	    graph.fillPolygon (x, y, nbPts) ;
	}
	if (outline) {
	    graph.drawPolygon (x, y, nbPts) ;
	}

	// Vers l''ecran :
	imgDisplayer.repaint (10, xmin, ymin, 
			      xmax - xmin + 1, ymax - ymin + 1) ;
    }

    /* 0 pour blanc, 1 pour noir, 
     * 2-255 pour une teinte pure (hue) :
     *   2-85 rouge au vert,
     *   86-170 du vert au bleu,
     *   171-255 du bleu au rouge.
     */
    public void couleur (int h) {
        if (h == 0)
            couleur (0.f, 0.f, 1.f, 1.0f) ;
        else if (h == 1)
            couleur (0.f, 0.f, 0.f, 1.0f) ;
        else
            couleur ((float) ((h-2) / 253.), 1.0f, 1.0f, 1.0f) ;
    }

    // hue, saturation, brightness, alpha
    void couleur (float h, float s, float b, float a) {
	Color coul = new Color (Color.HSBtoRGB 
				((float)h, (float)s, (float)b)) ;
	if (a == 1.0)
	    couleur = coul ;
	else // a < 1.0
	    couleur = new Color (coul.getRed(), coul.getGreen(), 
                                 coul.getBlue(), (int)(256 * a)) ;
    }

    void clear () {
        Graphics graph = bufimg.getGraphics () ;
	graph.setColor (Color.white) ;
	graph.fillRect (0, 0, largeur+2*marge, largeur+2*marge) ;
	imgDisplayer.repaint () ;
    }


    // ----------- ecriture de l'image dans un fichier ----

    void save (String file) {
        try {
            javax.imageio.ImageIO.write (bufimg, "png", 
                                         new java.io.File (file)) ;
        } catch (java.io.IOException e) {
            throw new Error (e) ;
        }
    }
}

// Classe pour afficher le buffer bufimg dans la fen^etre
class ImgCanvas extends Canvas
{
    Image bufimg ;

    ImgCanvas (int largeur) {
        bufimg = null ;
        setSize (largeur, largeur) ;
    }

    public void paint (Graphics g) {
        if (bufimg != null) {
            g.drawImage(bufimg, 0, 0, this) ;
        }
    }

    // Pour ne pas que sa clignotte en gris quand ,ca rame :
    public void update (Graphics g) {
        paint (g) ;
    }
}

// Classe pour quitter quand on ferme la fen^etre :
class ExitWindowAdapter extends WindowAdapter 
{
    public void windowClosing(WindowEvent e) {
        System.exit(0);
    }
}
