import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Color;
import java.util.Iterator;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import java.io.File;

/** A JPanel visually representing the sizes in certain Trees of MeasuredData:
  * trees where the size of each internal node's data is the sum of the sizes
  * of its children's (e.g. a tree returned by FileWalker.measure(Tree<File>).
  * 
  * Nodes are represented by boxes, with each child box inside its parent's.
  * The size of each box is proportional to the size of the data in the node.
  * Children of the root correspond to columns in the panel.
  * Grandchildren are rows inside those columns. This continues recursively,
  * alternating between columns and rows.
  * 
  * @param <T> the type of data in the MeasuredData in the represented Tree. */
class MapPanel<T> extends JPanel {

  private Tree<MeasuredData<T>> t;

  /** A MapPanel representing t.
    * Precondition: t != null, the sizes in t are non-negative, and the size
    * of each internal node's data is the sum of the sizes of its children's.
    * @param t  the tree to represent.
    * @throws IllegalArgumentException  if t is null. */
  public MapPanel(Tree<MeasuredData<T>> t) {
    if (t == null) throw new IllegalArgumentException();
    this.t = t;
  }

  /** Overridden to do the specific drawing.
    * @param g  a Graphics object for drawing on this JPanel. */
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    draw(t, true, g, 0, 0, getSize().width - 1, getSize().height - 1);
  }

  private static <T> void draw(Tree<MeasuredData<T>> t, boolean columns,
                               Graphics g, int x1, int y1, int x2, int y2) {
    long parentSize = t.getRootData().getSize();
    if (parentSize != 0) {
      Iterator<Tree<MeasuredData<T>>> children = t.childTreeIterator();
      long oldSum = 0;
      int oldXorY = columns ? x1 : y1;
      while (children.hasNext()) {
        Tree<MeasuredData<T>> child = children.next();
        long newSum = oldSum + child.getRootData().getSize();
        int newXorY = (int) (columns ?
                               x1 + (x2 - x1) * newSum / parentSize :
                               y1 + (y2 - y1) * newSum / parentSize);
        if (columns) {
          draw(child, !columns, g, oldXorY, y1, newXorY, y2);
          if (children.hasNext()) {
            g.setColor(Color.RED);
            g.drawLine(newXorY, y1, newXorY, y2);
          }
        } else {
          draw(child, !columns, g, x1, oldXorY, x2, newXorY);
          if (children.hasNext()) {
            g.setColor(Color.BLUE);
            g.drawLine(x1, newXorY, x2, newXorY);
          }
        }
        oldSum = newSum;
        oldXorY = newXorY;
      }
    }
  }
  
  /** Ask the user for a file and bring up a window visually representing
    * the filesystem under the user's file.
    * @param args  ignored. */
  public static void main(String[] args) {
    JFrame f = new JFrame();
    f.getContentPane().add(new MapPanel<File>
                           (FileWalker.measure
                              (FileWalker.fileTree
                                 (new File
                                    (JOptionPane.showInputDialog
                                       ("Please input a file/directory name"
                                          ))))));
    f.setSize(320, 240);
    f.setVisible(true);
  }

}

