package ij.util;

/** A simple QuickSort for String arrays. */
public class StringSorter {
	
	/** Sorts the array. */
	public static void sort(String[] a) {
		if (!alreadySorted(a))
			sort(a, 0, a.length - 1);
	}
	
	static void sort(String[] a, int from, int to) {
		int i = from, j = to;
		String center = a[ (from + to) / 2 ];
		do {
			while ( i < to && center.compareTo(a[i]) > 0 ) i++;
			while ( j > from && center.compareTo(a[j]) < 0 ) j--;
			if (i < j) {String temp = a[i]; a[i] = a[j]; a[j] = temp; }
			if (i <= j) { i++; j--; }
		} while(i <= j);
		if (from < j) sort(a, from, j);
		if (i < to) sort(a,  i, to);
	}
		
	static boolean alreadySorted(String[] a) {
		for ( int i=1; i<a.length; i++ ) {
			if (a[i].compareTo(a[i-1]) < 0 )
			return false;
		}
		return true;
	}
	
	/** Sorts file names containing numerical components.
	* Author: Norbert Vischer
	*/
	public static String[] sortNumerically(String[] list) {
		int n = list.length;
		String[] paddedList = getPaddedNames(list);
		String[] sortedList = new String[n];
		int[] indexes = Tools.rank(paddedList);
		for (int i = 0; i < n; i++)
			sortedList[i] = list[indexes[i]];
		return sortedList;
	}

	// Pads individual numeric string components with zeroes for correct sorting
	private static String[] getPaddedNames(String[] names) {
		int nNames = names.length;
		String[] paddedNames = new String[nNames];
		int maxLen = 0;
		for (int jj = 0; jj < nNames; jj++) {
			if (names[jj].length() > maxLen) {
				maxLen = names[jj].length();
			}
		}
		int maxNums = maxLen / 2 + 1;//calc array sizes
		int[][] numberStarts = new int[names.length][maxNums];
		int[][] numberLengths = new int[names.length][maxNums];
		int[] maxDigits = new int[maxNums];

		//a) record position and digit count of 1st, 2nd, .. n-th number in string
		for (int jj = 0; jj < names.length; jj++) {
			String name = names[jj];
			boolean inNumber = false;
			int nNumbers = 0;
			int nDigits = 0;
			for (int pos = 0; pos < name.length(); pos++) {
				boolean isDigit = name.charAt(pos) >= '0' && name.charAt(pos) <= '9';
				if (isDigit) {
					nDigits++;
					if (!inNumber) {
						numberStarts[jj][nNumbers] = pos;
						inNumber = true;
					}
				}
				if (inNumber && (!isDigit || (pos == name.length() - 1))) {
					inNumber = false;
					if (maxDigits[nNumbers] < nDigits) {
						maxDigits[nNumbers] = nDigits;
					}
					numberLengths[jj][nNumbers] = nDigits;
					nNumbers++;
					nDigits = 0;
				}
			}
		}
		
		//b) perform padding
		for (int jj = 0; jj < names.length; jj++) {
			String name = names[jj];
			int numIndex = 0;
			StringBuilder destName = new StringBuilder();
			for (int srcPtr = 0; srcPtr < name.length(); srcPtr++) {
				if (srcPtr == numberStarts[jj][numIndex]) {
					int numLen = numberLengths[jj][numIndex];
					if (numLen > 0) {
						for (int pad = 0; pad < (maxDigits[numIndex] - numLen); pad++) {
							destName.append('0');
						}
					}
					numIndex++;
				}
				destName.append(name.charAt(srcPtr));
			}
			paddedNames[jj] = destName.toString();
		}
		return paddedNames;
	}

}
