package school_project;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * Represent the map with its pieces.
 * Every piece has a position element that represent its position on the map
 */
public class Map extends Shape{
    private final ArrayList<Piece> pieces = new ArrayList<>();

    public Map(boolean[][] matrix) {
        super(matrix);
    }

    public Map() {
        super();
    }

    public void addPiece(Piece piece){
        piece.setLinked_map(this);
        pieces.add(piece);
    }

    public void addPiece(Piece[] pieces) {
        for (Piece p : pieces)
            this.addPiece(p);
    }

    /**
     * try to place a piece on the map, return true if succeed and false if it failed
     * @param piece the piece to place
     * @param pos the position to place the piece in matrix position
     * @return true if the piece can and is placed and false if it can't and won't not be palced
     */
    public boolean placePiece(Piece piece, Vec2 pos){

        if(!pieces.contains(piece))
            return false;

        piece.setPosition(null);
        // In the map limits
        if (    pos.x + piece.height > height
                || pos.y+piece.width > width
                || pos.x < 0
                || pos.y < 0)
            return false;

        ArrayList<Vec2> occupation = new ArrayList<>();
        for(Piece p: pieces){
            if(p.getPosition() == null || p == piece)
                continue;
            for (Vec2 o : p.getOccupation()) {
                occupation.add(o);
            }
        }

        for (int x = pos.x; x < pos.x + piece.height; x++) {
            for (int y = pos.y; y < pos.y + piece.width; y++) {
                if ((!getShape()[x][y] || occupation.contains(new Vec2(x, y))) && piece.getShape()[x - pos.x][y - pos.y]) {
                    return false;
                }
            }
        }

        piece.setPosition(pos);
        return true;
    }

    /**
     * Check if every pieces has a space on the board to know if the game is finished
     * @return true if the game is finished, false if not
     */
    public boolean gameDone(){
        ArrayList<Vec2> posList = getPosList();
        for(Piece p: pieces){
            posList.removeAll(p.getOccupation());
        }
        return posList.isEmpty();
    }

    /**
     * Return a matrix with all used space on the map to see if a piece can fit in a space
     *
     * @return matrix of boolean with false being the not used space
     */
    public boolean[][] getUsedSpace(){

        // Copy of the map to avoid side effect
        boolean[][] used = new boolean[height][width];
        for (int i = 0; i < height; i++) {
            used[i] = Arrays.copyOf(matrix[i], width);
        }

        for (Piece p : pieces) {
            if(p.getPosition() == null)
                continue;
            for(int x = 0; x < p.height; x++){
                for(int y = 0; y < p.width; y++){
                    if (p.getShape()[x][y]){
                        used[p.getPosition().x + x][p.getPosition().y + y] = false;
                    }
                }
            }
        }
        return used;
    }

    public ArrayList<Piece> getPieces() {
        return pieces;
    }

    /**
     * return a new Clean Map without any pieces on it for saving purpose
     * @return a New Map Object without any pieces or saved data
     */
    public Map getCleanedMap() {
        try {
            Map ret = (Map) this.clone();
            ret.getPieces().clear();
            return ret;
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
}
