package amphis;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JPanel;

// note : utilise la classe UnionFind qui se trouve dans Amphi3Connectivity 

enum Direction { Vertical, Horizontal };

class Wall {
  final int x;
  final int y;
  final Direction direction;
  boolean closed;
  
  public Wall(int x, int y, Direction direction) {
    this.x = x;
    this.y = y;
    this.direction = direction;
    this.closed = true;
  }
}

public class Amphi3Maze extends JFrame {
  private static final long serialVersionUID = 2465232426222345837L;

  private static final int step = 20;
  
  Amphi3Maze(int width, int height) {
    Vector<Wall> walls = new Vector<Wall>();
    for (int x = 0; x < width; x++)
      for (int y = 0; y < height; y++) {
        if (x < width - 1) walls.add(new Wall(x, y, Direction.Vertical));
        if (y < height - 1) walls.add(new Wall(x, y, Direction.Horizontal));
      }
    System.out.println(walls.size() + " walls");
    shuffle(walls);

    int n = width * height;
    UnionFind uf = new UnionFind(n); // codage : x * height + y
     
    for (Wall w: walls) {
      int cell = w.x * height + w.y;
      int next = cell + (w.direction == Direction.Horizontal ? 1 : height); 
      if (uf.find(cell) == uf.find(next)) continue;
      uf.union(cell, next);
      w.closed = false;
    }
    
    MazeWindow window = new MazeWindow(walls, width, height, step);
    this.setTitle("labyrinthe");
    window.setPreferredSize(new Dimension(width * step + 1, height * step + 1));
    this.add(window, BorderLayout.CENTER);
    this.pack();
    this.add(window);
    this.addKeyListener(window);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setResizable(false);
    this.setLocationRelativeTo(null);
    this.setVisible(true);
  }
  
  // mélange de Knuth
  void shuffle(Vector<Wall> a) {
    for (int i = 1; i < a.size(); i++) {
      int j = (int)(Math.random() * (i + 1));
      Wall tmp = a.get(i);
      a.set(i,  a.get(j));
      a.set(j, tmp);
    }
  }

  public static void main(String[] args) {
    new Amphi3Maze(40, 30);
  }
}
  
class MazeWindow extends JPanel implements KeyListener {

  private static final long serialVersionUID = 1L;

  private final int width, height, step;
  private final Vector<Wall> walls;
  
  MazeWindow(Vector<Wall> walls, int width, int height, int step) {
    this.walls = walls;
    this.width = width;
    this.height = height;
    this.step = step;
  }
  
  @Override
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;
    g2d.setStroke(new BasicStroke(3));
    int w = this.width * this.step;
    int h = this.height * this.step;
    g.drawLine(0, 0, w, 0);
    g.drawLine(0, 0, 0, h);
    g.drawLine(w, 0, w, h);
    g.drawLine(0, h, w, h);
    for (Wall wall: this.walls) {
      if (!wall.closed) continue;
      int x = wall.x * this.step;
      int y = wall.y * this.step;
      switch (wall.direction){
      case Horizontal:
        g2d.drawLine(x, y + step, x + step, y + step);
        break;
      case Vertical:
        g2d.drawLine(x + step, y, x + step, y + step);
        break;
      }
    }
  }

  @Override
  public void keyTyped(KeyEvent ev) {    
    char key = ev.getKeyChar();
    if (key == 'q')
      System.exit(0);
  }

  @Override
  public void keyPressed(KeyEvent ev) {
  }

  @Override
  public void keyReleased(KeyEvent ev) {    
  }
  
}