package CH.ifa.draw.gui;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Insets;
import java.awt.LayoutManager;


/**
 * I am a LayoutManager that lays out a tool panel.
 * <p>
 * All components will be the same size.
 * The height equals the height of the first component, regardless if it is visible or not.
 * The width depends on the width of the container.
 * Depending on the minimum width, I try to fit as many components in a row as possible, then stretch them up to the max width to fill the container.
 * @deprecated This class is not to be used externally and will later be hidden.
 */
@Deprecated
public class ToolPanelLayout implements LayoutManager {

    private int _maxWidth;
    private int _minWidth;
    private int _columns;

    /**
     * Constructor that takes in a maximum and minimum width.
     * @param minWidth minimal width for Panels that are of this layout, may not be smaller than 0
     * @param maxWidth maximum width for Panels that are of this layout
     */
    public ToolPanelLayout(int minWidth, int maxWidth) {

        assert minWidth > 0 : "Minimum width may not be smaller 0.";

        _maxWidth = maxWidth;
        _minWidth = minWidth;
    }

    @Override
    public void addLayoutComponent(String name, Component comp) {

    }

    @Override
    public void removeLayoutComponent(Component comp) {

    }

    @Override
    public Dimension preferredLayoutSize(Container parent) {

        int width;
        int height;

        synchronized (parent.getTreeLock()) {
            Dimension d = calculatePreferredWidth(parent);
            width = (d != null) ? d.width : _minWidth * 5;
            height = calculatePreferredHeight(width, parent);

        }
        return new Dimension(width, height);
    }

    private int calculatePreferredHeight(int containerWidth, Container parent) {

        int result = 0;

        Insets insets = parent.getInsets();
        int componentsPerRow = (containerWidth - (insets.left + insets.right)) / _minWidth;
        int count = parent.getComponentCount();
        if (count > 0 && componentsPerRow > 0) {

            int rows = (int) Math.ceil(((double) count) / componentsPerRow);
            int heightPerComponent = parent.getComponent(0).getPreferredSize().height;
            result = rows * heightPerComponent + parent.getInsets().top;
        }
        return result;

    }

    @Override
    public Dimension minimumLayoutSize(Container parent) {
        return new Dimension(_minWidth * 3, 50);
    }

    private Dimension calculatePreferredWidth(Container parent) {

        Dimension result;
        Container container = parent;

        do {
            result = container.getSize();
            container = container.getParent();
        } while (((result == null) || (result.width <= 0)) && (container != null));

        return result;
    }

    @Override
    public void layoutContainer(final Container parent) {
        synchronized (parent.getTreeLock()) {

            Insets insets = parent.getInsets();
            int parentWidth = calculatePreferredWidth(parent).width - (insets.left + insets.right);

            // What is the maximum number of components we can fit in?
            int componentsPerRow = parentWidth / _minWidth;
            if (componentsPerRow == 0) {
                componentsPerRow = 1;
            }
            // How wide do the components need to be to fill the container?
            int width = Math.min(parentWidth / componentsPerRow, _maxWidth);

            // The last component in each row is slightly larger to account for extra space that can't be
            // divided among the components (i.e. there are fewer pixels than components per row).
            int lastWidth = width + parentWidth % width;

            int count = parent.getComponentCount();
            int x = 0, y = insets.top;
            int column = 0;
            Component c;

            if (count > 0) {
                c = parent.getComponent(0);
                int height = c.getPreferredSize().height;

                for (int i = 0; i < count; i++) {
                    c = parent.getComponent(i);
                    if (c.isVisible()) {
                        c.setSize(width, height);
                        c.setLocation(x, y);
                        column++;
                        x += width;

                        if (column >= componentsPerRow) {
                            // Last component in this row, so adjust the width again
                            c.setSize(lastWidth, height);
                            column = 0;
                            y += height;
                            x = 0;
                        }
                    }
                }
            }

            if (_columns != componentsPerRow) {
                // The number of columns has changed.
                // This means the current preferred height was probably wrongly calculated.
                // Revalidate the component to set the correct height.
                _columns = componentsPerRow;

                EventQueue.invokeLater(parent::revalidate);
            }
        }


    }

    /**
     * Sets the maximum width a component can have in the container with a layout.
     * Components are stretched up to the max width in order to fill the container.
     *
     * @param width maximum component width is set with this parameter
     */
    public void setMaximumComponentWidth(int width) {
        _maxWidth = width;

    }

    /**
     * Sets the minimum width a component can have in the container with a layout.
     * Components are resized down up to their minimum width in order to fit as many as possible per row.
     *
     * @param width minimum component width is set with this parameter
     */
    public void setMinimumComponentWidth(int width) {
        _minWidth = width;
    }
}
