/*******************************************************************************
 * Copyright (c) 2007 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:
 *     Stefan Xenos, IBM Corporation - initial API and implementation
 *     Chris Torrence, ITT Visual Information Solutions - initial API and implementation (bug 51580)
 *******************************************************************************/
package org.eclipse.ui.tests.layout.constraints;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.layout.LayoutConstants;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.ISizeProvider;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPartConstants;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.ViewPart;

public class LayoutConstraintsView extends ViewPart implements ISizeProvider {

	private Control control;

	private int minWidth = ISizeProvider.INFINITE;
	private int maxWidth = ISizeProvider.INFINITE;
	private int minHeight = ISizeProvider.INFINITE;
	private int maxHeight = ISizeProvider.INFINITE;
	private int quantizedWidth = ISizeProvider.INFINITE;
	private int quantizedHeight = ISizeProvider.INFINITE;
	private int fixedArea = ISizeProvider.INFINITE;
	private Text minWidthText;
	private Text maxWidthText;
	private Text quantizedWidthText;
	private Text minHeightText;
	private Text maxHeightText;
	private Text quantizedHeightText;
	private Text fixedAreaText;
	private Text sampleImplementation;

	@Override
	public void createPartControl(Composite parent) {
		control = parent;

		Composite buttonBar = new Composite(parent, SWT.NONE);
		GridDataFactory buttonData = GridDataFactory.fillDefaults().grab(true, false);

		Button applyButton = new Button(buttonBar, SWT.PUSH);
		applyButton.setText("Apply");
		applyButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				applyPressed();
			}
		});
		buttonData.applyTo(applyButton);

		Button clearButton = new Button(buttonBar, SWT.PUSH);
		clearButton.setText("Reset");
		clearButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				minWidthText.setText("");
				maxWidthText.setText("");
				quantizedWidthText.setText("");
				minHeightText.setText("");
				maxHeightText.setText("");
				quantizedHeightText.setText("");
				fixedAreaText.setText("");
				applyPressed();
			}
		});
		buttonData.applyTo(clearButton);

		Button newViewButton = new Button(buttonBar, SWT.PUSH);
		newViewButton.setText("New View");
		newViewButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				try {
					getSite().getPage().showView("org.eclipse.ui.tests.layout.constraints.LayoutConstraintsView",
							"" + System.currentTimeMillis(), IWorkbenchPage.VIEW_ACTIVATE);
				} catch (PartInitException e1) {
					MessageDialog.openError(getSite().getShell(), "Error opening view", "Unable to open view.");
				}
			}
		});
		buttonData.applyTo(newViewButton);

		GridLayoutFactory.fillDefaults().equalWidth(true).numColumns(3).applyTo(buttonBar);
		GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(buttonBar);

		new Label(parent, SWT.NONE).setText("Min Width");
		minWidthText = createText(parent);

		new Label(parent, SWT.NONE).setText("Max Width (blank = unbounded)");
		maxWidthText = createText(parent);

		new Label(parent, SWT.NONE).setText("Quantized Width (blank = none)");
		quantizedWidthText = createText(parent);

		new Label(parent, SWT.NONE).setText("Min Height");
		minHeightText = createText(parent);

		new Label(parent, SWT.NONE).setText("Max Height (blank = unbounded)");
		maxHeightText = createText(parent);

		new Label(parent, SWT.NONE).setText("Quantized Height (blank = none)");
		quantizedHeightText = createText(parent);

		new Label(parent, SWT.NONE).setText("Fixed Area (blank = none");
		fixedAreaText = createText(parent);

		sampleImplementation = new Text(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
		sampleImplementation.setFont(JFaceResources.getFont(JFaceResources.TEXT_FONT));
		sampleImplementation.setTabs(4);
		GridDataFactory.fillDefaults().grab(true, true).span(2, 1).applyTo(sampleImplementation);

		GridLayoutFactory.fillDefaults().numColumns(2).margins(LayoutConstants.getMargins()).generateLayout(parent);

		applyPressed();

	}

	/**
	 *
	 */
	protected void applyPressed() {
		// Copy the values from the text boxes
		minWidth = getInt(minWidthText);
		maxWidth = getInt(maxWidthText);
		quantizedWidth = getInt(quantizedWidthText);
		minHeight = getInt(minHeightText);
		maxHeight = getInt(maxHeightText);
		quantizedHeight = getInt(quantizedHeightText);
		fixedArea = getInt(fixedAreaText);

		StringBuilder result = new StringBuilder();
		result.append("// Sample implementation: Make sure your ViewPart adapts to ISizeProvider.\n");
		result.append("// Then implement the following two methods.\n\n");
		sampleImplementation.setText(result + getSizeFlagsString() + computePreferredSizeString());

		// Trigger a workbench layout
		updateLayout();
	}

	@Override
	public int getSizeFlags(boolean width) {
		int flags = 0;
		if (width) {
			if (minWidth != ISizeProvider.INFINITE) {
				flags |= SWT.MIN;
			}
			if (maxWidth != ISizeProvider.INFINITE) {
				flags |= SWT.MAX;
			}
			if (quantizedWidth != ISizeProvider.INFINITE || fixedArea != ISizeProvider.INFINITE) {
				flags |= SWT.FILL;
			}
			if (fixedArea != ISizeProvider.INFINITE) {
				flags |= SWT.WRAP;
			}
		} else {
			if (minHeight != ISizeProvider.INFINITE) {
				flags |= SWT.MIN;
			}
			if (maxHeight != ISizeProvider.INFINITE) {
				flags |= SWT.MAX;
			}
			if (quantizedHeight != ISizeProvider.INFINITE || fixedArea != ISizeProvider.INFINITE) {
				flags |= SWT.FILL;
			}
			if (fixedArea != ISizeProvider.INFINITE) {
				flags |= SWT.WRAP;
			}
		}

		return flags;
	}

	public String getSizeFlagsString() {
		StringBuilder result = new StringBuilder();
		result.append("/* (non-Javadoc)\n");
		result.append(" * @see org.eclipse.ui.ISizeProvider#getSizeFlags(boolean)\n");
		result.append(" */\n");
		result.append("public int getSizeFlags(boolean width) {\n");
		result.append("\tint flags = 0;\n");
		result.append("\tif (width) {\n");
		if (minWidth != ISizeProvider.INFINITE) {
			result.append("\t\tflags |= SWT.MIN;\n");
		}
		if (maxWidth != ISizeProvider.INFINITE) {
			result.append("\t\tflags |= SWT.MAX;\n");
		}
		if (quantizedWidth != ISizeProvider.INFINITE || fixedArea != ISizeProvider.INFINITE) {
			result.append("\t\tflags |= SWT.FILL;\n");
		}
		if (fixedArea != ISizeProvider.INFINITE) {
			result.append("\t\tflags |= SWT.WRAP;\n");
		}
		result.append("\t} else {\n");
		if (minHeight != ISizeProvider.INFINITE) {
			result.append("\t\tflags |= SWT.MIN;\n");
		}
		if (maxHeight != ISizeProvider.INFINITE) {
			result.append("\t\tflags |= SWT.MAX;\n");
		}
		if (quantizedHeight != ISizeProvider.INFINITE || fixedArea != ISizeProvider.INFINITE) {
			result.append("\t\tflags |= SWT.FILL;\n");
		}
		if (fixedArea != ISizeProvider.INFINITE) {
			result.append("\t\tflags |= SWT.WRAP;\n");
		}
		result.append("\t}\n");
		result.append("\treturn flags;\n");
		result.append("}\n\n");
		return result.toString();
	}

	/**
	 * @param minWidth2
	 * @return
	 */
	private int getInt(Text text) {
		if (text.getText().isEmpty()) {
			return ISizeProvider.INFINITE;
		}

		try {
			return Integer.parseInt(text.getText());
		} catch (NumberFormatException e) {
			return ISizeProvider.INFINITE;
		}
	}

	/**
	 *
	 */
	protected void updateLayout() {
		firePropertyChange(IWorkbenchPartConstants.PROP_PREFERRED_SIZE);
	}

	/**
	 * @param parent
	 */
	private Text createText(Composite parent) {
		return new Text(parent, SWT.BORDER);
	}

	@Override
	public void setFocus() {
		control.setFocus();
	}

	@Override
	public int computePreferredSize(boolean width, int availableParallel, int availablePerpendicular,
			int preferredResult) {

		int result = preferredResult;

		if (fixedArea != ISizeProvider.INFINITE) {
			// Try to maintain a fixed area
			result = (availablePerpendicular != 0) ? fixedArea / availablePerpendicular : 0;
			if (result < 30) {
				result = 30;
			}
		}

		if (width) {
			if (quantizedWidth != ISizeProvider.INFINITE && quantizedWidth != 0) {
				// Jump to the nearest multiple of the quantized size
				result = Math.min(result + quantizedWidth / 2, availableParallel);
				result = result - (result % quantizedWidth);
			}
			if (minWidth != ISizeProvider.INFINITE) {
				// Ensure we go no smaller than the minimum size
				if (result < minWidth) {
					result = minWidth;
				}
			}
			if (maxWidth != ISizeProvider.INFINITE) {
				// Ensure we go no larger than the maximum size
				if (result > maxWidth) {
					result = maxWidth;
				}
			}
		} else {
			// Jump to the nearest multiple of the quantized size
			if (quantizedHeight != ISizeProvider.INFINITE && quantizedHeight != 0) {
				result = Math.min(result + quantizedHeight / 2, availableParallel);
				result = result - (result % quantizedHeight);
			}
			if (minHeight != ISizeProvider.INFINITE) {
				// Ensure we go no smaller than the minimum size
				if (result < minHeight) {
					result = minHeight;
				}
			}
			if (maxHeight != ISizeProvider.INFINITE) {
				// Ensure we go no larger than the maximum size
				if (result > maxHeight) {
					result = maxHeight;
				}
			}
		}

		// Ensure that we do not use more than the available space
		if (result > availableParallel) {
			result = availableParallel;
		}
		if (result < 0) {
			result = 0;
		}
		return result;
	}

	private String computePreferredSizeString() {
		StringBuilder result = new StringBuilder();
		result.append("/* (non-Javadoc)\n");
		result.append(" * @see org.eclipse.ui.ISizeProvider#computePreferredSize(boolean, int, int, int)\n");
		result.append(" */\n");
		result.append("public int computePreferredSize(boolean width, int availableParallel,\n");
		result.append("\tint availablePerpendicular, int preferredResult) {\n");
		result.append("\tint result = preferredResult;\n");
		if (fixedArea != ISizeProvider.INFINITE) {
			result.append("\t// Try to maintain a fixed area\n");
			result.append("\tresult = (availablePerpendicular != 0) ? " + fixedArea + "/availablePerpendicular : 0;\n");
			result.append("\tif (result < 30) result = 30;\n");
		}
		result.append("\tif (width) {\n");
		if (quantizedWidth != ISizeProvider.INFINITE && quantizedWidth != 0) {
			result.append("\t\t// Jump to the nearest multiple of the quantized size\n");
			result.append("\t\tresult = Math.min(result + " + quantizedWidth + "/2, availableParallel);\n");
			result.append("\t\tresult = result - (result % " + quantizedWidth + ");\n");
		}
		if (minWidth != ISizeProvider.INFINITE) {
			result.append("\t\t// Ensure we go no smaller than the minimum size\n");
			result.append("\t\tif (result < " + minWidth + ") result = " + minWidth + ";\n");
		}
		if (maxWidth != ISizeProvider.INFINITE) {
			result.append("\t\t// Ensure we go no larger than the maximum size\n");
			result.append("\t\tif (result > " + maxWidth + ") result = " + maxWidth + ";\n");
		}
		result.append("\t} else {\n");
		if (quantizedHeight != ISizeProvider.INFINITE && quantizedHeight != 0) {
			result.append("\t\t// Jump to the nearest multiple of the quantized size\n");
			result.append("\t\tresult = Math.min(result + " + quantizedHeight + "/2, availableParallel);\n");
			result.append("\t\tresult = result - (result % " + quantizedHeight + ");\n");
		}
		if (minHeight != ISizeProvider.INFINITE) {
			result.append("\t\t// Ensure we go no smaller than the minimum size\n");
			result.append("\t\tif (result < " + minHeight + ") result = " + minHeight + ";\n");
		}
		if (maxHeight != ISizeProvider.INFINITE) {
			result.append("\t\t// Ensure we go no larger than the maximum size\n");
			result.append("\t\tif (result > " + maxHeight + ") result = " + maxHeight + ";\n");
		}
		result.append("\t}\n");
		result.append("\t// Ensure that we do not use more than the available space\n");
		result.append("\tif (result > availableParallel) result = availableParallel;\n");
		result.append("\tif (result < 0) result = 0;\n");
		result.append("\treturn result;\n");
		result.append("}\n");
		return result.toString();
	}

}
