/*******************************************************************************
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.swt.examples.launcher;

 
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;

/**
 * A Layout class that automatically switches from a horizontal split to a vertical
 * split layout to accomodate changing size conditions.
 * 
 * Later on we might improve this class to take into account the "preferred" size of
 * the widgets.
 */
public class SplitLayout extends Layout {
	private static final int
		splitHorizontally = 0,
		splitVertically = 1;
	private int splitDirection = splitHorizontally;

	public int spacing = 3;
	public int marginTop = 3;
	public int marginLeft = 3;
	public int marginRight = 3;
	public int marginBottom = 3;

	/**
	 * Creates a new layout
	 */
	public SplitLayout() {
	}

	/**
	 * @see Layout#computeSize(Composite, int, int, boolean)
	 */
	@Override
	protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
		if (wHint == SWT.DEFAULT) {
			if (hHint == SWT.DEFAULT) {
				Point hSplitSize = computeHSplitSize(composite, wHint, hHint, flushCache);
				Point vSplitSize = computeVSplitSize(composite, wHint, hHint, false);
				int hSplitArea = hSplitSize.x * hSplitSize.y;
				int vSplitArea = vSplitSize.x * vSplitSize.y;
				// Choose direction consuming least area
				if (hSplitArea < vSplitArea) {
					splitDirection = splitHorizontally;
					return hSplitSize;
				} else {
					splitDirection = splitVertically;
					return vSplitSize;
				}
			} else {
				// Constrained in height: split vertically
				splitDirection = splitVertically;
				return computeVSplitSize(composite, wHint, hHint, flushCache);
			}
		} else {
			if (hHint == SWT.DEFAULT) {
				// Constrained in width: split horizontally
				splitDirection = splitHorizontally;
				return computeHSplitSize(composite, wHint, hHint, flushCache);
			} else {
				if (hHint < wHint) {
					splitDirection = splitVertically;
					return computeVSplitSize(composite, wHint, hHint, flushCache);
				} else {
					splitDirection = splitHorizontally;
					return computeHSplitSize(composite, wHint, hHint, flushCache);
				}					
			}
		}
	}
	/**
	 * @see Layout#layout(Composite, boolean)
	 */
	@Override
	protected void layout(Composite composite, boolean flushCache) {
		Rectangle clientArea = composite.getClientArea();
		computeSize(composite, clientArea.width, clientArea.height, false);
		
		Control[] children = composite.getChildren();
		clientArea.x += marginLeft;
		clientArea.y += marginTop;
		clientArea.width -= marginRight + marginLeft;
		clientArea.height -= marginBottom + marginTop;
		Point position = new Point(clientArea.x, clientArea.y);

		for (Control child : children) {
			final Rectangle bounds;
			if (splitDirection == splitHorizontally) {
				int height = clientArea.height / children.length;
				bounds = new Rectangle(position.x, position.y, clientArea.width, height);
				position.y += height + spacing;
			} else {
				int width = clientArea.width / children.length;
				bounds = new Rectangle(position.x, position.y, width, clientArea.height);
				position.x += width + spacing;
			}
			bounds.width = Math.max(bounds.width, 0);
			bounds.height = Math.max(bounds.height, 0);
			child.setBounds(bounds);
		}
	}

	private Point computeHSplitSize(Composite composite, int wHint, int hHint, boolean flushCache) {
		Point size = new Point(marginLeft + marginRight, marginTop + marginBottom);
		Control[] children = composite.getChildren();
		for (Control child : children) {
			Point childSize = child.computeSize(wHint, hHint, flushCache);
			size.x = Math.max(size.x, childSize.x);
			size.y += childSize.y + spacing;
		}
		return size;
	}

	private Point computeVSplitSize(Composite composite, int wHint, int hHint, boolean flushCache) {
		Point size = new Point(marginLeft + marginRight, marginTop + marginBottom);
		Control[] children = composite.getChildren();
		for (Control child : children) {
			Point childSize = child.computeSize(wHint, hHint, flushCache);
			size.x += childSize.x + spacing;
			size.y = Math.max(size.y, childSize.y);
		}
		return size;
	}
}
