package pl.edu.pw.mini.sg.gamegen;

import java.util.function.Supplier;
import java.util.stream.Stream;

import com.google.common.base.Preconditions;

public final class BuildingCoordsHelpers {
    private BuildingCoordsHelpers() {
    }

    public static int convert3dCoordsToIndex(final int x, final int y, final int floor,
            final BuildingDimensions dimensions) {
        Preconditions.checkElementIndex(x, dimensions.getWidth());
        Preconditions.checkElementIndex(y, dimensions.getHeight());
        Preconditions.checkElementIndex(floor, dimensions.getFloorCount());
        return dimensions.getWidth() * dimensions.getHeight() * floor + dimensions.getHeight() * x + y;
    }

    public static int convert3dCoordsToIndex(final BuildingCoord coord, final BuildingDimensions dimensions) {
        return convert3dCoordsToIndex(coord.getX(), coord.getY(), coord.getFloor(), dimensions);
    }

    public static int getXConnectionIndex(final int x1, final int x2, final int y, final int floor,
            final BuildingDimensions dimensions) {
        Preconditions.checkElementIndex(x1, dimensions.getWidth());
        Preconditions.checkElementIndex(x2, dimensions.getWidth());
        Preconditions.checkElementIndex(y, dimensions.getHeight());
        Preconditions.checkElementIndex(floor, dimensions.getFloorCount());
        Preconditions.checkArgument(Math.abs(x1 - x2) == 1);
        final int x = Math.min(x1, x2);

        return floor * (dimensions.getWidth()-1) * dimensions.getHeight() + y * (dimensions.getWidth()-1) + x;
    }

    public static int getYConnectionIndex(final int x, final int y1, final int y2, final int floor,
            final BuildingDimensions dimensions) {
        Preconditions.checkElementIndex(y1, dimensions.getHeight());
        Preconditions.checkElementIndex(y2, dimensions.getHeight());
        Preconditions.checkElementIndex(x, dimensions.getWidth());
        Preconditions.checkElementIndex(floor, dimensions.getFloorCount());
        Preconditions.checkArgument(Math.abs(y1 - y2) == 1);
        final int y = Math.min(y1, y2);

        return floor * dimensions.getWidth() * (dimensions.getHeight() - 1) + x * (dimensions.getHeight()-1) + y;
    }

    public static Stream<BuildingCoord> nodesOnFloor(final int floor, final BuildingDimensions dimensions) {
        final Supplier<BuildingCoord> pred = new Supplier<BuildingCoord>() {
            private int x = -1;
            private int y = 0;

            @Override
            public BuildingCoord get() {
                if (x + 1 < dimensions.getWidth()) {
                    x++;
                } else if (y + 1 < dimensions.getHeight()) {
                    x = 0;
                    y++;
                } else {
                    throw new IllegalStateException();
                }
                return new BuildingCoord(x, y, floor);
            }
        };
        return Stream.generate(pred).limit(dimensions.getWidth() * dimensions.getHeight());
    }
}
