package sudoku.structure;

import java.util.ArrayList;
import java.util.List;

/**
 * Représente une case d'un, ou plusieurs, sudoku qui à comme valeur un index de symbole.
 * Celui ci pourra être remplacer par un symbole en temps voulu.
 */
public class Cell {

	/**
	 * Constante de valeur d'index de symbole quand il n'y en a pas,
	 * soit que la Cell est vide.
	 */
	public static int NOSYMBOL = -1;

	/**
	 * Block dans lequel est la Cell.
	 */
	private Block blockContainer;
	/**
	 * L'index du symbole que contient la Cell.
	 * Il est initialisé à Cell.NOSYMBOL.
	 */
	private int symbolIndex = Cell.NOSYMBOL;
	/**
	 * Si cette Cell peut être modififié ou non.
	 */
	private boolean isMutable = true;

	public Cell() {
		this(Cell.NOSYMBOL);
	}

	public Cell(int symbolIndex) {
		this.symbolIndex = symbolIndex;
	}

	public Cell(int symbolIndex, boolean isMutable) {
		this.symbolIndex = symbolIndex;
		this.isMutable = isMutable;
	}

	public int getSymbolIndex() {
		return this.symbolIndex;
	}

	public void setSymbolIndex(int symbolIndex) {
		this.symbolIndex = symbolIndex;
	}

	/**
	 * Rend la Cell immuable.
	 */
	public void setImmutable() {
		this.isMutable = false;
	}

	public Block getBlock() {
		return this.blockContainer;
	}

	public void setBlock(Block block) {
		this.blockContainer = block;
	}

	/**
	 * Remove the current symbolIndex and returns it
	 * @return integer symbolIndex cleared
	 */
	public int clearCurrentSymbol() {
		int i = this.symbolIndex;
		setSymbolIndex(NOSYMBOL);
		return i;
	}

	/**
	 * Renvoie si la Cell est vide ou non.
	 * @return boolean, true si la Cell est vide, false sinon.
	 */
	public boolean isEmpty() {
		return this.symbolIndex == Cell.NOSYMBOL;
	}

	/**
	 * Renvoie si la Cell est modifiable
	 * @return boolean, true si elle est modifiable ou false sinon.
	 */
	public boolean isMutable() {
		return this.isMutable;
	}

	/**
	 * Vide la Cell, en renvoie l'ancien index du symbole qui était dedans.
	 * @return int, index du symbole anciennement contenue dans la Cell.
	 */
    public int empty() {
		int oldSymbol = this.symbolIndex;
		this.symbolIndex = Cell.NOSYMBOL;
		return oldSymbol;
    }

	public boolean canHaveValue(int value) {
		for (Sudoku s :getBlock().getSudokus()) {
			int cellIndex = s.getCells().indexOf(this);
			// la cellule existe
			if (cellIndex != -1) {
				int cellX = cellIndex % s.getSize();
				int cellY = cellIndex / s.getSize();
				if (!s.canBePlaced(cellX, cellY, value)) {
					return false;
				}
			}
		}
		return true;
	}

	public List<Integer> getPossibleSymbols() {
		List<Integer> result = new ArrayList<>();
		for (int i = 0; i < getBlock().getSudokus().get(0).getSize(); i++) {
			if (canHaveValue(i))
				result.add(i);
		}
		return result;
	}

	public boolean trySetValue(int newValue) {
		if (!isMutable())
			return false;
		if (!canHaveValue(newValue))
			return false;
		setSymbolIndex(newValue);
		return true;
	}
}
