/*
 * Copyright 2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.shell.table;

/**
 * A SizeConstraints implementation that is tailored to rendering a series
 * of {@literal key = value} pairs. Computes extents so that equal signs (or any other
 * configurable delimiter) line up vertically.
 *
 * @author Eric Bottard
 */
public class KeyValueSizeConstraints implements SizeConstraints {

	private final String delimiter;

	public KeyValueSizeConstraints(String delimiter) {
		this.delimiter = delimiter;
	}

	private static String leftTrim(String raw) {
		int start = 0;
		int length = raw.length();
		while (start < length && raw.charAt(start) == ' ') {
			start++;
		}
		return raw.substring(start);
	}

	private static String rightTrim(String raw) {
		int end = raw.length();
		while (end > 0 && raw.charAt(end - 1) == ' ') {
			end--;
		}
		return raw.substring(0, end);
	}

	@Override
	public Extent width(String[] raw, int tableWidth, int nbColumns) {

		// We need to make sure we take care of the case where we have
		//        k = long-value
		// long-key = v
		// as the real maximal extent is size(long-key) + size( = ) + size(long-value)

		// The minimal extent in the example above is size(long-value)

		int maxLeft = 0;
		int maxRight = 0;
		int min = 0;
		for (String line : raw) {
			String lineToConsider = line.trim();
			int offset = lineToConsider.indexOf(delimiter);

			if (offset != -1) {
				// Compute minimal case (line can be split, decide where to put the delimiter)
				String minimalLeftPart = lineToConsider.substring(0, offset).trim();
				String minimalRightPart = lineToConsider.substring(offset + delimiter.length()).trim();
				int left = minimalLeftPart.length();
				int right = minimalRightPart.length();
				int case1 = Math.max(left, right + leftTrim(delimiter).length());
				int case2 = Math.max(left + rightTrim(delimiter).length(), right);
				int bestMin = Math.min(case1, case2);
				min = Math.max(min, bestMin);

				// Compute maximal case (sum of worst case on left and right)
				maxLeft = Math.max(maxLeft, offset);
				int after = lineToConsider.length() - offset - delimiter.length();
				maxRight = Math.max(maxRight, after);
			}
			else {
				min = Math.max(min, lineToConsider.length());
			}

		}

		return new Extent(min, maxLeft + delimiter.length() + maxRight);
	}
}
