import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Snakes extends JPanel {
	public final static int WIDTH = 640;
	public final static int HEIGHT = 480;
	public final static int NUMBER_OF_SNAKES = 1000;
	public final static int TIME_INTERVAL = 200;
	public final static double TURN_PROB = .1;
	public final static double RIGHT_PROB = .5;
	public final static int DISTANCE_MULTIPLIER = 5;
	
	private Random random;
	private ArrayList<Snake> snakes;
	private Snake currentSnake;

	public static void main(String[] args) {
		JFrame frame = new JFrame("Trippy Snake Screensaver");
		frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		frame.setSize(WIDTH, HEIGHT);
		frame.setLocationRelativeTo(null);

		Snakes panel = new Snakes();

		panel.setBackground(Color.black);

		frame.setContentPane(panel);

		frame.setVisible(true);

		panel.initSnakes();
	}

	public void initSnakes() {
		snakes = new ArrayList<Snake>();
		random = new Random();

		for (int i = 0; i < NUMBER_OF_SNAKES; i++) {
			int x = Math.abs(random.nextInt() % WIDTH);
			int y = Math.abs(random.nextInt() % HEIGHT);
			Color color = new Color(Math.abs(random.nextInt() % 16000000));
			Point direction;
			if (random.nextFloat() > .5) {
				if (random.nextFloat() > .5) {
					direction = new Point(0, 1);
				} else {
					direction = new Point(1, 0);
				}
			} else {
				if (random.nextFloat() > .5) {
					direction = new Point(0, -1);
				} else {
					direction = new Point(-1, 0);
				}
			}
			Snake nextSnake = new Snake(x, y, color, direction, this);
			Thread nextThread = new Thread(nextSnake);
			nextThread.setDaemon(true);
			nextThread.start();

			snakes.add(nextSnake);
		}
	}

	public void paintSnake(Snake snake) {
		this.currentSnake = snake;
		repaint();
	}
	
	public void paint(Graphics g) {
		if (currentSnake == null) {
			super.paint(g);
		} else {

			g.setColor(currentSnake.color);
			g.drawLine(currentSnake.x, currentSnake.y, 
					currentSnake.x, currentSnake.y);
		}
	}	
}

class Snake implements Runnable {
	int x;
	int y;
	Point direction;
	Color color;
	
	private static Random random = new Random();
	private Snakes app;

	public Snake(int x, int y, Color color, Point direction, Snakes app) {
		this.x = x;
		this.y = y;
		this.color = color;
		this.direction = direction;
		this.app = app;
	}

	public void run() {
		while (true) {
			try {
				Thread.sleep(Snakes.TIME_INTERVAL);
				x += direction.x * Snakes.DISTANCE_MULTIPLIER;
				y += direction.y * Snakes.DISTANCE_MULTIPLIER;

				if (random.nextFloat() < Snakes.TURN_PROB) {
					if (direction.x == 0) {
						if (random.nextFloat() > Snakes.RIGHT_PROB) {
							direction.x = 1;
						} else {
							direction.x = -1;
						}
						direction.y = 0;
					} else {
						if (random.nextFloat() > Snakes.RIGHT_PROB) {
							direction.y = 1;
						} else {
							direction.y = -1;
						}
						direction.x = 0;
					}
				}
				app.paintSnake(this);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

