package sudoku;

import sudoku.constraint.IConstraint;

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

/**
 * @class Sudoku
 * @brief Représente une grille de sudoku avec N symboles
 */
public class Sudoku {

	private final List<Block> blocks;
	private final List<Cell> cells;
	private final List<IConstraint> constraints;

	public Sudoku(List<Cell> cells, List<Block> blocks, List<IConstraint> constraints) {
		this.cells = cells;
		this.blocks = blocks;
		this.constraints = constraints;
	}

	public Cell getCell(int x, int y) {
		int index = y * getSize() + x;
		assert(index < getSize() * getSize());
		return this.cells.get(index);
	}

	public Cell getCell(int i) {
		return this.cells.get(i);
	}

	public List<IConstraint> getConstraints() {
		return constraints;
	}

	public int getSize() {
		return this.blocks.size();
	}

	public Boolean isValid(List<IConstraint> constraints) {
		//not implemented
		//for eachcase check contraintes
		throw new Error("Function isValid() not implemented");
	}

	public List<Cell> getCells() {
		return this.cells;
	}

	public List<Block> getBlocks() {
		return this.blocks;
	}

	public List<MutableCell> getMutableCells() {
		List<MutableCell> mutableCells = new ArrayList<>();
		for (Cell cell : this.cells) {
			if (cell instanceof MutableCell){
				mutableCells.add((MutableCell) cell);
			}
		}
		return mutableCells;
	}

	public boolean contains(Cell cell) {
		return this.cells.contains(cell);
	}

	private Coordinate getCoordinateCell(Cell c) throws Exception {
		int x=0, y=0;
		int size = this.getSize();

		if (!this.contains(c)) {
			throw new Exception("The given cell is not in this sudoku.");
		}

		for (Cell cell : this.cells) {
			if (cell == c){
				return new Coordinate(x, y);
			}
			if (x == size - 1){
				y+=1;
				x=0;
			}
			else {
				x+=1;
			}
		}
		return new Coordinate(x, y);
	}

    public void updateSymbolsPossibilities() throws Exception {
		for (IConstraint constraint : constraints) {
			List<MutableCell> mutableCells = this.getMutableCells();
			for (MutableCell cell : mutableCells) {
                Coordinate coord = null;
                try {
                    coord = this.getCoordinateCell(cell);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                constraint.getPossibleSymbols(this, coord.getX(), coord.getY());
				if (cell.getPossibleSymbols().isEmpty()){
					throw new Exception("Rollback bitch");
				}
			}
		}
	}

	public String toString () {
		StringBuilder sb = new StringBuilder();
		sb.append("Sudoku {");
		for (int i = 0; i < getSize(); i++) {
			sb.append("\n\t");
			for (int j = 0; j < getSize(); j++) {
				Cell cell = getCell(i, j);
				sb.append(cell.toString()).append(" ");
			}
		}
		sb.append("\n}");
		return sb.toString();
	}
}
