/*******************************************************************************
 * Copyright (c) 2004, 2017 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.ui.internal.layout;

import org.eclipse.swt.widgets.Control;

/**
 * Computes and the positions of controls in a CellLayout, based on their span.
 */
class GridInfo {
	private int cols = 0;

	private int rows = 0;

	private int[] gridInfo;

	int[] controlRow;

	int[] controlCol;

	private CellData[] cellData;

	Control[] controls;

	/**
	 * Initialize the grid
	 *
	 * @param newControls
	 * @param cols
	 */
	public void initGrid(Control[] newControls, CellLayout layout) {
		cols = layout.getColumns();
		controls = newControls;

		int area = 0;
		int totalWidth = 0;

		controlRow = new int[controls.length];
		controlCol = new int[controls.length];

		// Get the CellData objects for each control, and compute
		// the total number of cells spanned by controls in this layout.
		cellData = new CellData[controls.length];
		for (int idx = 0; idx < controls.length; idx++) {
			if (controls[idx] == null) {
				continue;
			}

			CellData next = CellLayoutUtil.getData(controls[idx]);
			cellData[idx] = next;
			area += next.horizontalSpan * next.verticalSpan;
			totalWidth += next.horizontalSpan;
		}

		// Compute the number of columns
		if (cols == 0) {
			cols = totalWidth;
		}

		// Compute the number of rows
		rows = area / cols;
		if (area % cols > 0) {
			// Ensure we count any partial rows
			rows++;
		}

		area = rows * cols;

		// Allocate the gridInfo array
		gridInfo = new int[area];
		for (int idx = 0; idx < area; idx++) {
			gridInfo[idx] = -1;
		}

		int infoIdx = 0;
		// Compute the positions of each control
		for (int idx = 0; idx < controls.length; idx++) {
			CellData data = cellData[idx];

			// Find an empty position to insert the control
			while (gridInfo[infoIdx] >= 0) {
				infoIdx++;
			}

			controlRow[idx] = infoIdx / cols;
			controlCol[idx] = infoIdx % cols;

			// Insert the new control here
			for (int rowIdx = 0; rowIdx < data.verticalSpan; rowIdx++) {
				for (int colIdx = 0; colIdx < data.horizontalSpan; colIdx++) {
					gridInfo[infoIdx + rowIdx * cols + colIdx] = idx;
				}
			}

			infoIdx += data.horizontalSpan;
		}
	}

	public int getRows() {
		return rows;
	}

	public int getStartPos(int control, boolean row) {
		if (row) {
			return controlRow[control];
		}
		return controlCol[control];
	}

	/**
	 * Returns the number of rows or columns
	 *
	 * @param isRow if true, returns the number of rows. If false, returns the
	 *              number of columns
	 * @return
	 */
	public int getNumRows(boolean isRow) {
		if (isRow) {
			return rows;
		}
		return cols;
	}

	public void getRow(int[] result, int rowId, boolean horizontal) {
		if (horizontal) {
			int prev = -1;
			for (int colIdx = 0; colIdx < cols; colIdx++) {
				int next = gridInfo[cols * rowId + colIdx];

				if (prev == next) {
					result[colIdx] = -1;
				} else {
					result[colIdx] = next;
				}

				prev = next;
			}
		} else {
			int prev = -1;
			for (int rowIdx = 0; rowIdx < rows; rowIdx++) {
				int next = gridInfo[cols * rowIdx + rowId];

				if (prev == next) {
					result[rowIdx] = -1;
				} else {
					result[rowIdx] = next;
				}

				prev = next;
			}
		}
	}

	public CellData getCellData(int controlId) {
		return cellData[controlId];
	}

	public int getCols() {
		return cols;
	}
}
