package org.artisanlogiciel.games.maze.model;

import org.artisanlogiciel.games.maze.Brick;
import org.artisanlogiciel.games.maze.MovesProvider;
import org.artisanlogiciel.games.maze.Position;
import org.artisanlogiciel.games.maze.WallsProvider;

public class LineColumnModel
    implements WallsProvider,
        MovesProvider
{

    final BooleanLongSet lines[];
    final BooleanLongSet columns[];

    public LineColumnModel(int width, int height)
    {
        lines = new BooleanLongSet[height];
        columns = new BooleanLongSet[width];
    }

    BooleanLongSet getLine(int column)
    {
        BooleanLongSet l = lines[column];
        if ( l == null )
        {
            l= new BooleanLongSet(getWidth(),63);
            lines[column] = l;
        }
        return l;
    }

    BooleanLongSet getColumn(int line)
    {
        BooleanLongSet c = columns[line];
        if ( c == null )
        {
            c = new BooleanLongSet(getHeight(),63);
            columns[line] = c;
        }
        return c;
    }

    public short getWalls(Position cell) {
        return getWalls(cell.getX(),cell.getY());
    }

    @Override
    public short getWalls(int x, int y) {
        return (short) (
                (getLine(y).isSet(x) ? Brick.UP : 0)
                + (getColumn(x).isSet(y) ? Brick.LEFT : 0)
                + (getLine(y+1).isSet(x) ? Brick.DOWN : 0)
                + (getColumn(x+1).isSet(y) ? Brick.RIGHT : 0)
        );
    }

    @Override
    public short getMoves(int x, int y)
    {
        // moves are where there is no walls ...
        return (short) ((~ getWalls(x,y)) & 0x0f);
    }

    @Override
    public int getWidth() {
        return columns.length;
    }

    @Override
    public int getHeight() {
        return lines.length;
    }

    public void setWalls(int x, int y, short walls)
    {
        getLine(y).set(x, (walls & Brick.UP) != 0);
        getColumn(x).set(y, (walls & Brick.LEFT) != 0);
        getLine(y+1).set(x, (walls & Brick.DOWN) != 0);
        getColumn(x+1).set(y, (walls & Brick.RIGHT) != 0);
    }

    public void setMoves(int x, int y, short moves)
    {
        short walls = (short) ~ moves;
        setWalls(x,y,walls);
    }

}