package fr.upd.jby;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

/**
 * Using this layout in a real application is a sin.
 * It has been designed to demonstrate how to implement a LayoutManager.
 * It lays components one below
 * the other, starting from the top of the container space,
 * and such that, left and right margins
 * draw a sinusoid.
 *
 * Source code <a href="SinLayout.java.html">here</a> and a sample
 * <a href="../../../SinExample.java.html">here</a>.
 *
 * @author J.-B. Yunès
 * @version 1.0
 * @since 1.6
 */
public class SinLayout implements LayoutManager {
    private java.util.List<Component> components;
    private Dimension preferredSize;
    private int componentPerCycle, maxValue;
    /**
     * Constructs a default SinLayout which glues component's borders
     * to the respective left and right borders of their container.
     */
    public SinLayout() {
	componentPerCycle = 1;
	maxValue = 0;
	components = new Vector<Component>();
    }
    /**
     * Constructs a SinLayout which glues component's borders to
     * the respective left and right sinusoidal border of their container,
     * with strict respect to their minimum size.
     * @param cpc the number of component per period of the sinusoid.
     * @param zenith the zenith of the sinusoid, in pixels.
     */
    public SinLayout(int cpc,int zenith) {
	this();
	if (cpc>0)
	    componentPerCycle = cpc;
	if (maxValue>=0 && maxValue<200)
	    maxValue = zenith;
    }
    /**
     * Adds the specified component to the layout. Not used by this class.
     */
    public void addLayoutComponent(String n,Component c) {
	// Never used...
    }
    private int leftGap(int i) {
	return (int)Math.abs(Math.sin(i*Math.PI/componentPerCycle)*maxValue);
    }
    /**
     * Lays out the container.
     * @param c the container to be laid out
     */
    public void layoutContainer(Container c) {
	synchronized (c.getTreeLock()) {
	    int width = c.getSize().width;
	    int i=0, h=0;
	    for (Component co : c.getComponents()) {
		if (!co.isVisible()) continue;
		Dimension d = co.getPreferredSize();
		int cw = Math.max(width-2*leftGap(i),co.getMinimumSize().width);
		System.out.println(""+width+" "+d+" "+co.getMinimumSize());
		if (!co.getSize().equals(new Dimension(cw,d.height))) {
		    co.setSize(cw,d.height);
		}
		Point l = new Point((c.getSize().width-co.getSize().width)/2,h);
		if (!co.getLocation().equals(l)) {
		    co.setLocation(l);
		}
		i++;
		h += co.getSize().height;
	    }
	}
    }
    /**
     * Returns the minimum dimensions needed to layout the
     * <em>visible</em> components contained in the specified target container.
     * @param c the container to bo laid out.
     */
    public Dimension minimumLayoutSize(Container c) {
	synchronized (c.getTreeLock()) {
	    int w=1000, h=0, i=0;
	    if (c.getComponentCount()==0) return new Dimension(10,10);
	    for (Component co : c.getComponents()) {
		if (!co.isVisible()) continue;
		h += co.getMinimumSize().height;
		w = Math.min(w,co.getMinimumSize().width+2*leftGap(i));
		i++;
	    }
	    return new Dimension(w,h);
	}
    }
    /**
     * Returns the preferred dimensions for this layout given the
     * <em>visible</em>  components in the specified target container.
     * @param c the container to bo laid out.
     */
    public Dimension preferredLayoutSize(Container c) {
	synchronized (c.getTreeLock()) {
	    int w=0, h=0, i=0;
	    if (c.getComponentCount()==0) return new Dimension(10,10);
	    for (Component co : c.getComponents()) {
		if (!co.isVisible()) continue;
		h += co.getPreferredSize().height;
		w = Math.max(w,co.getPreferredSize().width+2*leftGap(i));
		i++;
	    }
	    preferredSize = new Dimension(w,h);
	    return preferredSize;
	}
    }
    /**
     * Removes the specified component from the layout. Forces a repaint to
     * clean the space previously used by the component in the container.
     * @param c the component to be removed.
     */
    public void removeLayoutComponent(Component c) {
	synchronized (c.getTreeLock()) {

	    // Force a repaint to clean the space used by the component
	    // At this point the component has not been removed from the
	    // container then we are able to procastinate a repaint...
	    c.getParent().repaint(c.getLocation().x,c.getLocation().y,
				  c.getSize().width,c.getSize().height);
	}
    }
}