import processing.core.*;

public class Window extends PApplet {
	private static final long serialVersionUID = 1L;

	int phase = 0;
	// phase
	// 0 = title
	// 1 = introduce level
	// 2 = play level
	// 3 = game over

	Point[] checkPoints;
	float vitesse;
	float errorRadius;
	float totalLength;

	int level = 0;

	float currentPosition;
	float currentLight;

	float currentX, currentY;

	Point perduAt;

	int score = 0;

	PFont font;

	public void setup() {
		size(500, 500);
		frameRate(40);
		smooth();
		font = loadFont(dataPath("VisitorTT2BRK-12.vlw"));
		textFont(font);
	}

	public void draw() {
		if (phase == 0) {
			phaseTitle();
		} else if (phase == 1) {
			phaseIntrod();
		} else if (phase == 2) {
			phasePlay();
		} else if (phase == 3) {
			phaseEnd();
		}
	}

	private void phaseEnd() {
		// draw the level
		background(0);
		strokeWeight(2);
		stroke(0xFF);
		noFill();
		// draws the lines
		for (int i = 0; i < checkPoints.length - 1; i++) {
			line(checkPoints[i].getX(), checkPoints[i].getY(),
					checkPoints[i + 1].getX(), checkPoints[i + 1].getY());
		}
		stroke(0, 0xFF, 0);
		noFill();
		// draws the ellipse
		ellipse(currentX, currentY, errorRadius, errorRadius);
		// draws the cross
		stroke(0xFF, 0, 0);
		line(perduAt.getX() - width / 10, perduAt.getY() - height / 10, perduAt
				.getX()
				+ width / 10, perduAt.getY() + height / 10);
		line(perduAt.getX() + width / 10, perduAt.getY() - height / 10, perduAt
				.getX()
				- width / 10, perduAt.getY() + height / 10);
		fill(0x88);
		text(score + " pixels travelled successfully so far.", 10, 10);
	}

	private void phasePlay() {
		float currentLength = totalLength * currentPosition;
		int currentP = 0;// currentPoint
		// win ?
		if (currentPosition >= 1) {
			score += totalLength;
			nextLevel();
			level++;
			phase = 1;
		} else {
			boolean ok = false;
			for (int i = 0; i < checkPoints.length && !ok; i++) {
				float lF = lengthFrom(i);
				if (currentLength > lF) {
					currentLength -= lF;
				} else {
					ok = true;
					currentP = i;
				}
			}
			currentX = checkPoints[currentP].getX()
					+ cos(atan2(checkPoints[currentP + 1].getY()
							- checkPoints[currentP].getY(),
							checkPoints[currentP + 1].getX()
									- checkPoints[currentP].getX()))
					* currentLength;
			currentY = checkPoints[currentP].getY()
					+ sin(atan2(checkPoints[currentP + 1].getY()
							- checkPoints[currentP].getY(),
							checkPoints[currentP + 1].getX()
									- checkPoints[currentP].getX()))
					* currentLength;
			// game over if...
			if (dist(mouseX, mouseY, currentX, currentY) > errorRadius / 2) {
				phase = 3;
				perduAt = new Point(mouseX, mouseY);
			}
			// move
			currentPosition += vitesse;
			// draw the level
			background(0);
			strokeWeight(2);
			stroke(0xFF);
			noFill();
			// draws the lines
			for (int i = 0; i < checkPoints.length - 1; i++) {
				line(checkPoints[i].getX(), checkPoints[i].getY(),
						checkPoints[i + 1].getX(), checkPoints[i + 1].getY());
			}
			// fades
			if (level >= 2) {
				currentLight = max(currentLight - 0.5f, 0);
			}
			stroke(0, 0xFF, 0, currentLight);
			noFill();
			// draws the ellipse
			ellipse(currentX, currentY, errorRadius, errorRadius);
		}
	}

	private void nextLevel() {
		if (level % 3 == 0) {
			checkPoints = new Point[checkPoints.length + 1];
		}
		for (int i = 0; i < checkPoints.length; i++) {
			checkPoints[i] = new Point(random(width), random(height));
		}
		errorRadius *= 0.95f;
		currentPosition = 0;
		totalLength = 0;
		for (int i = 0; i < checkPoints.length - 1; i++) {
			totalLength += lengthFrom(i);
		}
		vitesse = 2 / totalLength;
		currentLight = 0xFF;
	}

	private float lengthFrom(int i) {
		return dist(checkPoints[i].getX(), checkPoints[i].getY(),
				checkPoints[i + 1].getX(), checkPoints[i + 1].getY());
	}

	private void phaseIntrod() {
		drawLevel();
	}

	private void drawLevel() {
		background(0);
		strokeWeight(2);
		stroke(0xFF);
		noFill();
		// draws the lines
		for (int i = 0; i < checkPoints.length - 1; i++) {
			line(checkPoints[i].getX(), checkPoints[i].getY(),
					checkPoints[i + 1].getX(), checkPoints[i + 1].getY());
		}
		stroke(0, 0xFF, 0);
		if (phase == 1)
			fill(0xFF, 0x88);
		ellipse(checkPoints[0].getX(), checkPoints[0].getY(), errorRadius,
				errorRadius);
	}

	private void phaseTitle() {
		background(0);
		fill(0xFF);
		stroke(0x88);
		rect(width / 3, height / 3, width / 3, height / 3);
	}

	public void mousePressed() {
		if (phase == 0) {
			loadFirstLevel();
			phase++;
		} else if (phase == 1) {
			if (dist(mouseX, mouseY, checkPoints[0].getX(), checkPoints[0]
					.getY()) < errorRadius / 2) {
				phase++;
			}
		} else if (phase == 2) {
		} else if (phase == 3) {
			resetLevel();
		}
	}

	private void resetLevel() {
		currentPosition = 0;
		currentLight = 0xFF;
		phase = 1;
	}

	private void loadFirstLevel() {
		checkPoints = new Point[2];
		checkPoints[0] = new Point(random(width / 3), random(height / 3));
		checkPoints[1] = new Point(random(width / 3) + (width * 2 / 3),
				random(height / 3) + (height * 2 / 3));
		errorRadius = width / 2;
		currentPosition = 0;
		totalLength = 0;
		for (int i = 0; i < checkPoints.length - 1; i++) {
			totalLength += lengthFrom(i);
		}
		vitesse = 2 / totalLength;
		currentLight = 0xFF;
	}

	public static void main(String[] args) {
		PApplet.main(new String[] { "Window" });
	}

}
