package es.sandbox.spike.connectn;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static es.sandbox.spike.connectn.Position.position;

/**
 * Created by jeslopalo on 27/2/16.
 */
final class Dimensions {

    private final int columns;
    private final int rows;

    private Dimensions(int columns, int rows) {
        validateDimensions(columns, rows);

        this.columns = columns;
        this.rows = rows;
    }

    public static Dimensions dimensions(int columns, int rows) {
        return new Dimensions(columns, rows);
    }

    Chip[][] createBoard() {
        return new Chip[this.columns][this.rows];
    }

    private List<Position> positions() {
        final List<Position> positions = new ArrayList<>();
        IntStream.range(0, this.columns)
                .mapToObj(column -> positionsAtColumn(column))
                .forEach(columnPositions -> positions.addAll(columnPositions));
        return positions;
    }

    void forEachPosition(PositionClosure positionClosure) {
        positions().forEach(position -> positionClosure.execute(position));
    }

    void forEachPositionInRows(PositionsClosure positionsClosure) {
        IntStream.range(0, this.rows)
                .mapToObj(row -> positionsAtRow(row))
                .forEach(positions -> positionsClosure.execute(positions));
    }

    List<Position> positionsAtColumn(int column) {
        validateColumn(column);

        return IntStream.range(0, this.rows)
                .mapToObj(row -> position(column, row))
                .collect(Collectors.toList());
    }

    List<Position> positionsAtRow(int row) {
        validateRow(row);

        return IntStream.range(0, this.columns)
                .mapToObj(column -> position(column, row))
                .collect(Collectors.toList());
    }

    boolean contains(Position position) {
        return columnIsInRange(position.column()) && rowIsInRange(position.row());
    }

    boolean fitsOn(int magnitude) {

        if (magnitude < 1) {
            throw new IllegalArgumentException("Magnitude must be greater than zero");
        }

        return (Math.max(this.columns, magnitude) == this.columns) &&
                (Math.max(this.rows, magnitude) == this.rows);
    }

    void validateColumn(int column) {
        if (!columnIsInRange(column)) {
            throw new ColumnOutOfRangeException(column, this);
        }
    }

    void validateRow(int row) {
        if (!rowIsInRange(row)) {
            throw new RowOutOfRangeException(row, this);
        }
    }

    private boolean rowIsInRange(int row) {
        return 0 <= row && row < this.rows;
    }

    private boolean columnIsInRange(int column) {
        return 0 <= column && column < this.columns;
    }

    static void validateDimensions(int columns, int rows) {
        assertThatNumberOfColumnsIsGreaterOrEqualThanTwo(columns);
        assertThatNumberOfRowsIsGreaterOrEqualThanTwo(rows);
    }

    private static void assertThatNumberOfColumnsIsGreaterOrEqualThanTwo(int columns) {
        if (columns < 2) {
            throw new IllegalArgumentException("The number of columns must be greater or equal than 2");
        }
    }

    private static void assertThatNumberOfRowsIsGreaterOrEqualThanTwo(int rows) {
        if (rows < 2) {
            throw new IllegalArgumentException("The number of rows must be greater or equal than 2");
        }
    }

    @Override
    public String toString() {
        return String.format("%dx%d", this.columns, this.rows);
    }
}

@@ -867,34 +867,30 @@
   .mapToObj(
-column -%3E 
+this::
 positionsAtC
@@ -894,24 +894,16 @@
 AtColumn
-(column)
 )%0A      
@@ -925,27 +925,8 @@
 ach(
-columnPositions -%3E 
 posi
@@ -934,32 +934,16 @@
 ions
-.
+::
 addAll
-(columnPositions)
 );%0A 
@@ -1066,20 +1066,8 @@
 ach(
-position -%3E 
 posi
@@ -1081,26 +1081,17 @@
 sure
-.
+::
 execute
-(position)
 );%0A 
@@ -1220,39 +1220,38 @@
       .mapToObj(
-row -%3E 
+this::
 positionsAtRow(r
@@ -1248,21 +1248,16 @@
 onsAtRow
-(row)
 )%0A      
@@ -1279,21 +1279,8 @@
 ach(
-positions -%3E 
 posi
@@ -1295,27 +1295,17 @@
 sure
-.
+::
 execute
-(positions)
 );%0A 
@@ -2214,32 +2214,40 @@
 ws);%0A    %7D%0A%0A    
+private 
 void validateCol
@@ -2384,24 +2384,32 @@
 %0A    %7D%0A%0A    
+private 
 void validat
@@ -2737,20 +2737,28 @@
 %0A    %7D%0A%0A
-
     
+private 
 static v

Simplify lambdas usage