// Tiedosto Viiva.java

import java.awt.Color;

public class Viiva {
    private double ax;
    private double ay;
    private double bx;
    private double by;
    private Color väri;

    public Viiva(double ax, double ay, double bx, double by, Color väri) {
        this.ax = ax;
        this.ay = ay;
        this.bx = bx;
        this.by = by;
        this.väri = väri;
    }

    public String toString() {
        return "(" + ax + ", " + ay + ") -> (" + bx + ", " + by + ")";
    }

    public void piirrä(Piirto p) {
        p.vaihdaVäri(väri);
        p.piirräViiva(ax, ay, bx, by);
    }

    public void siirrä(double dx, double dy) {
        ax += dx;
        ay += dy;
        bx += dx;
        by += dy;
    }
}


// Tiedosto Nelio.java

import java.awt.Color;

public class Nelio {
    private Viiva v1;
    private Viiva v2;
    private Viiva v3;
    private Viiva v4;

    public Nelio(double ax, double ay, double sivu, Color väri) {
        v1 = new Viiva(ax, ay, ax + sivu, ay, väri);
        v2 = new Viiva(ax + sivu, ay, ax + sivu, ay + sivu, väri);
        v3 = new Viiva(ax + sivu, ay + sivu, ax, ay + sivu, väri);
        v4 = new Viiva(ax, ay + sivu, ax, ay, väri);
    }

    public String toString() {
        return "Nelio " + v1 + ", " + v2 + ", " + v3 + ", " + v4;
    }

    public void piirrä(Piirto p) {
        v1.piirrä(p);
        v2.piirrä(p);
        v3.piirrä(p);
        v4.piirrä(p);
    }

    public void siirrä(double dx, double dy) {
        v1.siirrä(dx, dy);
        v2.siirrä(dx, dy);
        v3.siirrä(dx, dy);
        v4.siirrä(dx, dy);
    }

}

// Tiedosto Kolmio.java

import java.awt.Color;

public class Kolmio {
    private Viiva v1;
    private Viiva v2;
    private Viiva v3;
    
    public Kolmio(double x1, double y1, double x2, double y2, double x3, double y3,
                  Color väri){
        v1 = new Viiva(x1, y1, x2, y2, väri);
        v2 = new Viiva(x2, y2, x3, y3, väri);
        v3 = new Viiva(x3, y3, x1, y1, väri);
    }

    public String toString() {
        return "Kolmio " + v1 + ", " + v2 + ", " + v3;
    }

    public void piirrä(Piirto p) {
        v1.piirrä(p);
        v2.piirrä(p);
        v3.piirrä(p);
    }

    public void siirrä(double dx, double dy) {
        v1.siirrä(dx, dy);
        v2.siirrä(dx, dy);
        v3.siirrä(dx, dy);
    }
}

// Tiedosto TikkuUkko.java

import java.awt.Color;

public class TikkuUkko {
    private Nelio pää;
    private Viiva kaula;
    private Kolmio vartalo;
    private Viiva vasenKäsi;
    private Viiva oikeaKäsi;
    private Viiva vasenJalka;
    private Viiva oikeaJalka;

    public TikkuUkko(double x, double y, double pituus, double leveys, Color väri) {
        pää = new Nelio(x + 0.25*leveys, y + 0.8*pituus, 0.5*leveys, väri);
        kaula = new Viiva(x + 0.5*leveys, y + 0.7*pituus,
                          x + 0.5*leveys, y + 0.8*pituus,
                          väri);
        vartalo = new Kolmio(x + 0.5*leveys, y + 0.45*pituus,
                             x + leveys, y + 0.7*pituus,
                             x, y + 0.7*pituus,
                             väri);
        vasenKäsi = new Viiva(x, y + 0.4*pituus,
                              x, y + 0.7*pituus,
                              väri);
        oikeaKäsi = new Viiva(x + leveys, y + 0.4*pituus,
                              x + leveys, y + 0.7*pituus,
                              väri);
        vasenJalka = new Viiva(x, y, 
                               x + 0.5*leveys, y + 0.45*pituus,
                               väri);
        oikeaJalka = new Viiva(x + leveys, y, 
                               x + 0.5*leveys, y + 0.45*pituus,
                               väri);
    }

    public String toString() {
        return "TikkuUkko";
    }

    public void piirrä(Piirto piirto) {
        pää.piirrä(piirto);
        kaula.piirrä(piirto);
        vartalo.piirrä(piirto);
        vasenKäsi.piirrä(piirto);
        oikeaKäsi.piirrä(piirto);
        vasenJalka.piirrä(piirto);
        oikeaJalka.piirrä(piirto);
    }

    public void siirrä(double dx, double dy) {
        pää.siirrä(dx, dy);
        kaula.siirrä(dx, dy);
        vartalo.siirrä(dx, dy);
        vasenKäsi.siirrä(dx, dy);
        oikeaKäsi.siirrä(dx, dy);
        vasenJalka.siirrä(dx, dy);
        oikeaJalka.siirrä(dx, dy);
    }
}

// Tiedosto Paperi.java

import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Iterator;
import java.util.List;
import java.util.LinkedList;

public class Paperi extends JPanel {

    protected class ViivaKomento {
	protected double x1;
	protected double y1;
	protected double x2;
	protected double y2;
	protected Color väri;

	ViivaKomento(double x1, double y1, double x2, double y2, Color väri) {
	    this.x1 = x1;
	    this.y1 = y1;
	    this.x2 = x2;
	    this.y2 = y2;
	    this.väri = väri;
	}

	void tee(Graphics g) {
	    g.setColor(väri);
	    g.drawLine((int)x1, (int)y1, (int)x2, (int)y2);
	}
    }

    private double leveys;
    private double korkeus;
    private Color väri;
    private List komennot;

    public Paperi(double leveys, double korkeus) {
	super();
	this.leveys = leveys;
	this.korkeus = korkeus;
	setPreferredSize(new Dimension((int)(leveys+8), (int)(korkeus+8)));
	setBorder(new EmptyBorder(4, 4, 4, 4));
	setBackground(Color.white);
	väri = Color.black;
	komennot = new LinkedList();
    }

    protected double leveys() { return leveys; }

    protected double korkeus() { return korkeus; }

    protected Color väri() { return väri; }

    protected void asetaVäri(Color väri) {
	this.väri = väri;
    }

    public void pyyhiKaikki() {
	komennot = new LinkedList();
    }

    public void lisääViiva(double x1, double y1, double x2, double y2) {
	komennot.add(new ViivaKomento(x1, korkeus - y1, x2, korkeus - y2, väri));
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);
	Iterator it = komennot.iterator();
	while (it.hasNext()) {
	    ViivaKomento komento = (ViivaKomento)it.next();
	    komento.tee(g);
	}
    }
}

// Tiedosto Piirto.java

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Piirto extends JFrame implements ActionListener {
    private JPanel napit;
    private JButton lopeta;
    private JButton pysäytä;
    private Paperi paperi;
    private Timer ajastin;
    private boolean pysäytetty = false;

    public void käynnistä() {
        if (!pysäytetty && !ajastin.isRunning()) {
	    ajastin.start();
	}
    }

    public void pysäytä() {
        if (ajastin.isRunning()) {
            ajastin.stop();
        }
    }

    public void actionPerformed(ActionEvent e) {
	piirräKaikki();
 	paperi.repaint(0L);
    }

    public void piirräKaikki() {
    }

    public void piirräViiva(double x1, double y1, double x2, double y2) {
	paperi.lisääViiva(x1, y1, x2, y2);
    }

    public void vaihdaVäri(Color väri) {
	paperi.asetaVäri(väri);
    }

    public void pyyhiKaikki() {
	paperi.pyyhiKaikki();
    }

    public void odota(double sec) {
    }

    public Piirto(double leveys, double korkeus) {
	this("Piirto", leveys, korkeus, 50, false);
    }


    public Piirto(String nimi, double leveys, double korkeus, int fps,
		  boolean pysäytettävissä) {
	super(nimi);
        int viive = (fps > 0) ? (1000 / fps) : 100;

        ajastin = new Timer(viive, this);
        ajastin.setInitialDelay(0);
        ajastin.setCoalesce(true);

        addWindowListener(new WindowAdapter() {
            public void windowIconified(WindowEvent e) {
                pysäytä();
            }
            public void windowDeiconified(WindowEvent e) {
                käynnistä();
            }
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }  
        });

	napit = new JPanel();
	
	lopeta = new JButton("Lopeta");

        lopeta.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
		System.exit(0);
            }
        });

	napit.add(lopeta);

	if (pysäytettävissä) {
	    pysäytä = new JButton("Pysäytä");

	    pysäytä.addMouseListener(new MouseAdapter() {
		    public void mousePressed(MouseEvent e) {
			if (pysäytetty) {
			    pysäytetty = false;
			    pysäytä.setText("Pysäytä");
			    käynnistä();
			} else {
			    pysäytetty = true;
			    pysäytä.setText("Jatka");
			    pysäytä();
			}
		    }
		});

	    napit.add(pysäytä);
	}

	paperi = new Paperi(leveys, korkeus);

	Container paneeli = this.getContentPane();
	paneeli.add(paperi, BorderLayout.CENTER);
	paneeli.add(napit, BorderLayout.SOUTH);

	this.pack();
	this.setVisible(true);
    }
}

// Tiedosto Kokeilu4.java

import java.awt.Color;
import java.util.Random;

public class Kokeilu4 extends Piirto {
    private static final int leveys = 400;
    private static final int korkeus = 400;
    private static final int fps = 50;
    private static final int n = 8;
    private static final int maksimiNopeus = 4;
    private static final int ukonTila = korkeus/n;
    private static final long seed = 1234L;
    private static final Random random = new Random(seed);

    TikkuUkko[] ukot;
    int[] sijainnit;
    int[] nopeudet;

    public Kokeilu4() {
        super("Kokeilu4", leveys, korkeus, fps, true);
	luoKuviot();
    }

    private void luoKuviot() {
	ukot = new TikkuUkko[n];
	sijainnit = new int[n];
	nopeudet = new int[n];
	for (int i = 0; i < n; i++) {
	    sijainnit[i] = random.nextInt(2*leveys) - leveys/2;
	    if (random.nextDouble() < 0.5) {
		nopeudet[i] = -(1 + random.nextInt(maksimiNopeus));
	    } else {
		nopeudet[i] = (1 + random.nextInt(maksimiNopeus));
	    }
	    int ukonKorkeus = random.nextInt(ukonTila - n) + 8;
	    int ukonLeveys = ukonKorkeus/3;
	    ukot[i] = new TikkuUkko(sijainnit[i],
				    i*ukonTila + (ukonTila - ukonKorkeus)/2,
				    ukonKorkeus,
				    ukonLeveys,
				    new Color((float)(i%3*0.5*random.nextDouble()),
					      (float)(i%3*0.5*random.nextDouble()),
					      (float)(i%3*0.5*random.nextDouble())));
	}
    }

    public void piirräKaikki() {
	pyyhiKaikki();
	for (int i = 0; i < n; i++) {
	    ukot[i].piirrä(this);
	    if (sijainnit[i] < -leveys/2 || sijainnit[i] > 3*leveys/2) {
		nopeudet[i] = -nopeudet[i];
	    }
	    ukot[i].siirrä(nopeudet[i], 0);
	    sijainnit[i] += nopeudet[i];
	}
    }

    public static void main(String[] args) {
	Kokeilu4 k = new Kokeilu4();
	k.käynnistä();
    }
}
