import java.util.*;

public class Sweep {
  // The size of the world is set permanently to a 16x16 grid 
  public static final int WORLDSIZE = 16;
  
  public static void main(String[] args) {
    System.out.println("Hello Sweeps");
    Sweep s = new Sweep();

    s.sweepMatrix();
    s.sweepList();
    s.sweepMapClassic();
    s.sweepMapStream();
  }

  // Demonstration of the sweep template on a matrix
  public void sweepMatrix() {
    System.out.println("-- Sweeping a matrix --");
    City[][] matrix = new City[WORLDSIZE][WORLDSIZE];
    matrix[1][1] = new City(); // The red city
    matrix[4][1] = new City(); // The blue city
    
    // Sweeping a matrix
    for (int row = 0; row < WORLDSIZE; row++) {
      for (int column = 0; column < WORLDSIZE; column++) {
        City element = matrix[row][column];
        if (element != null) {
          // process element
          System.out.println("Processing "+element);
        }
      }
    }
  }

  // Demonstration of the sweep template on a List 
  public void sweepList() {
    System.out.println("-- Sweeping a List --");
    // We create a List<City> of size 16x16,
    // and then position (3,4) is index (3*16+4)
    List<City> list = new ArrayList<City>(WORLDSIZE * WORLDSIZE);
    // Though the capacity is 64, the size is still 0 so I need to
    for (int i = 0; i < WORLDSIZE * WORLDSIZE; i++) list.add(null);
    int index;
    index = computeIndex(1,1); list.set(index, new City()); // The red city
    index = computeIndex(4,1); list.set(index, new City()); // The blue city
    
    // Sweeping the List
    for (City element: list) {
      if (element != null) {
        // process element
        System.out.println("Processing "+element);
      }
    }
  }

  // Demonstration of the sweep template on a Map
  // using the Java 7 / classic for iteration
  public void sweepMapClassic() {
    System.out.println("-- Sweeping a map / Classic --");
    Map<Position, City> map = new HashMap<>();
    map.put(new Position(1,1), new City()); // The red city
    map.put(new Position(4,1), new City()); // The blue city
    
    // Sweeping a map, by iteration on the set of keys
    for (Position p: map.keySet()) {
      City element = map.get(p);
      if (element != null) {
        // process element
        System.out.println("Processing "+element);
      }
    }
    // Note: the 'if' is not necessary as the map only
    // contains the two cities.
  }
  
  // Demonstration of the sweep template on a Map
  // using the Java 8 / stream api
  public void sweepMapStream() {
    System.out.println("-- Sweeping a map / Stream --");
    Map<Position, City> map = new HashMap<>();
    map.put(new Position(1,1), new City()); // The red city
    map.put(new Position(4,1), new City()); // The blue city
    
    // Sweeping a map, by streaming the set of keys
    map.keySet()
      .stream()
      .filter(p -> map.get(p) != null) 
      .forEach(p -> {
          City element = map.get(p);
          System.out.println("Processing "+element);
            });
    // Note: the 'filter' is actually not necessary here,
    // as the map only contains the two cities
  }

  private int computeIndex(int row, int column) {
    return row * WORLDSIZE + column;
  }
}

// ========= Support classes
class City {
  // Empty, as we use no fields nor methods of it
}

class Position {

  /** create a position. 
   * @param r the row
   * @param c the column
  */
  public Position(int r, int c) { 
    this.r = r; this.c = c; 
  }

  protected int r;
  protected int c;

  /** get the row represented by this position.
   * @return the row.
   */
  public int getRow() { return r; }

  /** get the column represented by this position.
   * @return the column.
   */
  public int getColumn() { return c; }

  public String toString() {
    return "["+r+","+c+"]";
  }
}

