/*
 * jNPad v0.3 - jNPad's an Simple Text Editor written in Java
 *
 * Copyright (C) 2014-2017  rgs
 *
 * Require JDK 1.6 (or later)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 *
 * Info, Questions, Suggestions & Bugs Report to rgsevero@gmail.com
 */

package jnpad.ui.layout;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;

/**
 * The Class VerticalFlowLayout.
 *
 * @version 0.3
 * @since   jNPad v0.1
 */
public class VerticalFlowLayout extends FlowLayout {
  /** */
  public static final int   TOP              = 0;
  /** */
  public static final int   MIDDLE           = 1;
  /** */
  public static final int   BOTTOM           = 2;

  private int               hgap, vgap;
  private boolean           hfill, vfill;

  /** UID */
  private static final long serialVersionUID = -4437074057358594011L;

  /**
   * Instantiates a new vertical flow layout.
   */
  public VerticalFlowLayout() {
    this(TOP, 5, 5, true, false);
  }

  /**
   * Instantiates a new vertical flow layout.
   *
   * @param hfill boolean
   * @param vfill boolean
   */
  public VerticalFlowLayout(boolean hfill, boolean vfill) {
    this(TOP, 5, 5, hfill, vfill);
  }

  /**
   * Instantiates a new vertical flow layout.
   *
   * @param align int
   */
  public VerticalFlowLayout(int align) {
    this(align, 5, 5, true, false);
  }

  /**
   * Instantiates a new vertical flow layout.
   *
   * @param align int
   * @param hgap int
   * @param vgap int
   */
  public VerticalFlowLayout(int align, int hgap, int vgap) {
    this(align, hgap, vgap, true, false);
  }

  /**
   * Instantiates a new vertical flow layout.
   *
   * @param align int
   * @param hfill boolean
   * @param vfill boolean
   */
  public VerticalFlowLayout(int align, boolean hfill, boolean vfill) {
    this(align, 5, 5, hfill, vfill);
  }

  /**
   * Instantiates a new vertical flow layout.
   *
   * @param align int
   * @param hgap int
   * @param vgap int
   * @param hfill boolean
   * @param vfill boolean
   */
  public VerticalFlowLayout(int align, int hgap, int vgap, boolean hfill, boolean vfill) {
    setAlignment(align);
    this.hgap = hgap;
    this.vgap = vgap;
    this.hfill = hfill;
    this.vfill = vfill;
  }

  /**
   * Gets the hgap.
   *
   * @return the hgap
   * @see java.awt.FlowLayout#getHgap()
   */
  @Override
  public int getHgap() {
    return hgap;
  }

  /**
   * Sets the hgap.
   *
   * @param hgap the new hgap
   * @see java.awt.FlowLayout#setHgap(int)
   */
  @Override
  public void setHgap(int hgap) {
    super.setHgap(hgap);
    this.hgap = hgap;
  }

  /**
   * Gets the vgap.
   *
   * @return the vgap
   * @see java.awt.FlowLayout#getVgap()
   */
  @Override
  public int getVgap() {
    return vgap;
  }

  /**
   * Sets the vgap.
   *
   * @param vgap the new vgap
   * @see java.awt.FlowLayout#setVgap(int)
   */
  @Override
  public void setVgap(int vgap) {
    super.setVgap(vgap);
    this.vgap = vgap;
  }

  /**
   * Preferred layout size.
   *
   * @param target the Container
   * @return the dimension
   * @see java.awt.FlowLayout#preferredLayoutSize(java.awt.Container)
   */
  @Override
  public Dimension preferredLayoutSize(Container target) {
    Dimension tarsiz = new Dimension(0, 0);
    for (int i = 0; i < target.getComponentCount(); i++) {
      Component m = target.getComponent(i);
      if (!m.isVisible())
        continue;
      Dimension d = m.getPreferredSize();
      tarsiz.width = Math.max(tarsiz.width, d.width);
      if (i > 0)
        tarsiz.height += vgap;
      tarsiz.height += d.height;
    }

    Insets insets = target.getInsets();
    tarsiz.width += insets.left + insets.right + hgap * 2;
    tarsiz.height += insets.top + insets.bottom + vgap * 2;
    return tarsiz;
  }

  /**
   * Minimum layout size.
   *
   * @param target the Container
   * @return the dimension
   * @see java.awt.FlowLayout#minimumLayoutSize(java.awt.Container)
   */
  @Override
  public Dimension minimumLayoutSize(Container target) {
    Dimension tarsiz = new Dimension(0, 0);
    for (int i = 0; i < target.getComponentCount(); i++) {
      Component m = target.getComponent(i);
      if (!m.isVisible())
        continue;
      Dimension d = m.getMinimumSize();
      tarsiz.width = Math.max(tarsiz.width, d.width);
      if (i > 0)
        tarsiz.height += vgap;
      tarsiz.height += d.height;
    }

    Insets insets = target.getInsets();
    tarsiz.width += insets.left + insets.right + hgap * 2;
    tarsiz.height += insets.top + insets.bottom + vgap * 2;
    return tarsiz;
  }

  /**
   * Sets the vertical fill.
   *
   * @param vfill the new vertical fill
   */
  public void setVerticalFill(boolean vfill) {
    this.vfill = vfill;
  }

  /**
   * Gets the vertical fill.
   *
   * @return the vertical fill
   */
  public boolean getVerticalFill() {
    return vfill;
  }

  /**
   * Sets the horizontal fill.
   *
   * @param hfill the new horizontal fill
   */
  public void setHorizontalFill(boolean hfill) {
    this.hfill = hfill;
  }

  /**
   * Gets the horizontal fill.
   *
   * @return the horizontal fill
   */
  public boolean getHorizontalFill() {
    return hfill;
  }

  /**
   * Placethem.
   *
   * @param target Container
   * @param x int
   * @param y int
   * @param width int
   * @param height int
   * @param first int
   * @param last int
   */
  private void placethem(Container target, int x, int y, int width, int height, int first, int last) {
    int align = getAlignment();
    if (align == MIDDLE)
      y += height / 2;
    if (align == BOTTOM)
      y += height;
    for (int i = first; i < last; i++) {
      Component m = target.getComponent(i);
      Dimension md = m.getSize();
      if (m.isVisible()) {
        int px = x + (width - md.width) / 2;
        m.setLocation(px, y);
        y += vgap + md.height;
      }
    }

  }

  /**
   * Layout container.
   *
   * @param target the Container
   * @see java.awt.FlowLayout#layoutContainer(java.awt.Container)
   */
  @Override
  public void layoutContainer(Container target) {
    Insets insets = target.getInsets();
    int maxheight = target.getSize().height - (insets.top + insets.bottom + vgap * 2);
    int maxwidth = target.getSize().width - (insets.left + insets.right + hgap * 2);
    int numcomp = target.getComponentCount();
    int x = insets.left + hgap;
    int y = 0;
    int colw = 0;
    int start = 0;
    for (int i = 0; i < numcomp; i++) {
      Component m = target.getComponent(i);
      if (!m.isVisible())
        continue;
      Dimension d = m.getPreferredSize();
      if (vfill && i == numcomp - 1)
        d.height = Math.max(maxheight - y, m.getPreferredSize().height);
      if (hfill) {
        m.setSize(maxwidth, d.height);
        d.width = maxwidth;
      }
      else {
        m.setSize(d.width, d.height);
      }
      if (y + d.height > maxheight) {
        placethem(target, x, insets.top + vgap, colw, maxheight - y, start, i);
        y = d.height;
        x += hgap + colw;
        colw = d.width;
        start = i;
        continue;
      }
      if (y > 0)
        y += vgap;
      y += d.height;
      colw = Math.max(colw, d.width);
    }

    placethem(target, x, insets.top + vgap, colw, maxheight - y, start, numcomp);
  }
}
