package com.lofibucket.yotris.logic;
import com.lofibucket.yotris.ui.UserInterface;
import com.lofibucket.yotris.util.Settings;
import com.lofibucket.yotris.util.TileColor;
import java.util.Observable;
import java.util.Random;

public class GameLogic extends Observable {
	private UserInterface ui;
	private Grid grid;
	private Settings settings;
	private Piece fallingPiece;
	private int score;
	private int frames = 0;
	private ZeroBasedCounter pieceFallCounter;
	private boolean running;
	
	public GameLogic(UserInterface ui, Settings settings)	 {
		this.ui = ui;
		this.settings = settings;
		this.reset(settings);

		addObserver(ui);
	}

	private void reset(Settings settings) {
		this.grid = new Grid(settings.getGridWidth(), settings.getGridHeight());	
		running = true;
		fallingPiece = null;
		pieceFallCounter = new ZeroBasedCounter(0, 10);
		score = 0;
		frames = 0;

		GameState state = getGameState();
		notifyObservers(state);
	}

	public GameState update() {
		frames++;
		updateFallingPiece();
		
		GameState state = getGameState();
		notifyObservers(state);

		return state;
	}

	private void updateFallingPiece() {
		pieceFallCounter.decrease();

		if (pieceFallCounter.isZero()) {
			if (fallingPiece == null) {
				spawnPiece();
			} else {
				fallingPiece.moveDown();
			}
		}
	}

	private void spawnPiece() {
		Position center = new Position(grid.getWidth()/2, 0);
		fallingPiece = new Piece(getRandomTetrimino(), getRandomColor(), center);

		if (grid.checkIntersection(fallingPiece)) {
			running = false;
			// TODO broadcast a gameover message?
		}
	}

	private TileColor getRandomColor() {
		TileColor[] colors;
		int choice;

		colors = TileColor.class.getEnumConstants();

		Random r = new Random();
		choice = r.nextInt(colors.length);

		return colors[choice];
	}

	private boolean[][] getRandomTetrimino() {
		return Tetrimino.O;	// TODO add proper random here
	}

	public GameState getGameState() {
		GameState state = new GameState(true);	
		state.running = this.running;

		Grid renderGrid = getRenderGrid();
		state.renderGrid = renderGrid;

		return state;
	}

	public Grid getRenderGrid() {
		Grid renderGrid = new Grid(this.grid.getWidth(), this.grid.getHeight());
		if (fallingPiece != null) {
			renderGrid.plotPiece(fallingPiece);
		}
		return renderGrid;
	}

	public int getSimulatedFrames() {
		return frames;
	}

	public Settings getSettings() {
		return settings;
	}
}

@@ -221,16 +221,104 @@
 andom;%0A%0A
+/**%0A *%09The main logic class. Takes care of the falling piece movement & collisions.%0A */%0A
 public c
@@ -574,16 +574,137 @@
 ning;%0A%09%0A
+%09/**%0A%09 *%0A%09 * @param ui%09The user interface to update changes to%0A%09 * @param settings%09settings for the current session%0A%09 */%0A
 %09public 
@@ -1143,24 +1143,113 @@
 state);%0A%09%7D%0A%0A
+%09/**%0A%09 *%09Runs one cycle of the game.%0A%09 * @return%09state of the game after this step.%0A%09 */%0A
 %09public Game
@@ -2185,24 +2185,128 @@
 om here%0A%09%7D%0A%0A
+%09/**%0A%09 *%09Builds a GameState object of the current GameLogic state.%09%0A%09 * @return current game state%0A%09 */%0A
 %09public Game
@@ -2490,24 +2490,50 @@
  state;%0A%09%7D%0A%0A
+%09/**%0A%09 *%0A%09 * @return%0A%09 */%0A
 %09public Grid
@@ -2720,24 +2720,100 @@
 erGrid;%0A%09%7D%0A%0A
+%09/**%0A%09 *%0A%09 * @return%09the amount of frames (update cycles) we have done%0A%09 */%0A
 %09public int 
@@ -2856,16 +2856,60 @@
 es;%0A%09%7D%0A%0A
+%09/**%0A%09 *%0A%09 * @return%09current settings.%0A%09 */%0A
 %09public 
@@ -2952,13 +2952,218 @@
 ttings;%0A
-
 %09%7D
+%0A%0A%09/**%0A%09 * Sets the current settings. Use this to change themes etc. on the fly.%0A%09 * @param settings %09new settings to use%0A%09 */%0A%09public void setSettings(Settings settings) %7B%0A%09%09this.settings = settings;%0A%09%7D%0A%0A
 %0A%7D%0A

add GameLogic documentation