package tornadofx.control.skin;

import javafx.scene.Node;
import javafx.scene.control.SkinBase;
import tornadofx.control.MultiSelect;

public class MultiSelectSkin<E> extends SkinBase<MultiSelect<E>> {

	public MultiSelectSkin(MultiSelect<E> control) {
		super(control);
	}

	private double getPrefRowHeight() {
		double editorHeight = getSkinnable().getEditor().prefHeight(-1);
		if (getChildren().isEmpty())
			return editorHeight;
		else
			return Math.max(editorHeight, getChildren().get(0).prefHeight(-1));
	}

	/**
	 * Compute pref width by placing equal amount of childen on each line, with a line height equal to the editors preferred
	 * height plus the vgap. This will not be correct in every case, depending on the difference in the other childrens
	 * preferred width, but it seems to be adequate.
	 */
	protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
		MultiSelect<E> control = getSkinnable();

		double hgap = control.getHgap().doubleValue();
		double vgap = control.getVgap().doubleValue();
		double prefRowHeight = getPrefRowHeight();

		int childCount = getChildren().size();
		int rows = height <= 0 ? 1 : (int) Math.max(1, Math.floor((prefRowHeight + vgap) / height));
		int perRow = (int) Math.ceil(childCount / rows);

		double widestRow = 0;
		int childPos = 0;
		for (int rowCount = 0; rowCount < rows; rowCount++) {
			double rowWidth = 0;
			double childPosInRow = 0;

			while (childPosInRow < perRow && childPos < childCount) {
				Node child = getChildren().get(childPos);
				rowWidth += child.prefWidth(prefRowHeight) + hgap;
				childPos++;
				childPosInRow++;
			}

			if (rowWidth > widestRow)
				widestRow = rowWidth;
		}

		return widestRow + leftInset + rightInset - hgap;
	}

	protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
		return computePrefHeight(width, topInset, rightInset, bottomInset, leftInset);
	}

	protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
		MultiSelect<E> control = getSkinnable();

		double usedLineWidth = 0;
		double hgap = control.getHgap().doubleValue();
		double vgap = control.getVgap().doubleValue();
		double prefHeight = getPrefRowHeight();

		double y = prefHeight;
		if (width == -1 && control.getWidth() > 0)
			width = control.getWidth();

		for (Node node : getChildren()) {
			double prefWidth = node.prefWidth(prefHeight);
			if (width > 0 && usedLineWidth + prefWidth > width && usedLineWidth > 0) {
				usedLineWidth = 0;
				y += prefHeight + vgap;
			}
			usedLineWidth += prefWidth + hgap;
		}

		return y;
	}

	protected void layoutChildren(double contentX, double contentY, double contentWidth, double contentHeight) {
		double usedLineWidth = 0;
		double hgap = getSkinnable().getHgap().doubleValue();
		double vgap = getSkinnable().getVgap().doubleValue();
		double prefHeight = getPrefRowHeight();

		for (Node node : getChildren()) {
			double prefWidth = node.prefWidth(prefHeight);
			if (usedLineWidth + prefWidth > contentWidth && usedLineWidth > 0) {
				usedLineWidth = 0;
				contentY += prefHeight + vgap;
			}
			double x = usedLineWidth + contentX;
			node.resizeRelocate(x, contentY, prefWidth, prefHeight);
			usedLineWidth += prefWidth + hgap;
		}
	}

}