// Copyright 1996, David Neto
class SortInput extends Clickable {
	int len=0;	// Number of elements.
	String rep="";	// Representation
	String repValues[];
	int values[];
	double relValues[];
	int pos[][];	// array of indices into repValues (and a working copy too)

	public SortInput() {
		setLabel("No label");
		setLength(0);
		setRepresentation("");
	}

	public SortInput( String label, int len, String rep ) {
		setLabel(label);
		setLength(len);
		setRepresentation(rep);
	}

/*
    // This code tests the SortInput Constructor.
    { SortInput junk;
        junk = new SortInput("Empty",5,"");
        junk = new SortInput("Space",5," ");
        junk = new SortInput("Too few",5,"96");
        junk = new SortInput("Too many ",5,"1 2 3 4 5 6");
        junk = new SortInput("Space before",5," 1 2 3 4 5");
        junk = new SortInput("Space after",5,"1 2 3 4 5  ");
        junk = new SortInput("Space between",5,"1 2    3        4 5  ");
        junk = new SortInput("Zero len",0,"1 2 3 4 5  ");
    }
*/

	public int getLength() {
		return len;
	}

	public void setLength(int newLen) {
		// In case of negative length, it just throws a runtime exception(?)
		len = newLen;
		repValues = new String[len];
		values = new int[len];
		relValues = new double[len];
		pos = new int[2][];
		pos[0] = new int[len];
		pos[1] = new int[len];
		setRepresentation(rep);
	}

	public String getRepresentation() {
		return rep;
	}
	
	public void setRepresentation(String newRep) {
		// Requires that setLength has been called at least once so
		// that the object's arrays have been initialized (even with arrays
		// of length zero).
		// Empty string is fine for newRep.  
		// len==0 is also fine.
		int i, j, start, end;
		String newRepValues[] = new String[len];

		// Build the new array of rep values.
		// Each rep value is a string value with no leading, trailing, or
		// embedded blanks.  They are stored the array in the order they 
		// appear in newRep from left to right.
		for ( i=0, start = 0 ; i<len && start != -1 ; i++, start = end ) {
			// Find first non-space
			while ( start < newRep.length() && newRep.charAt(start) == ' ' )
				start++;
			if ( start == newRep.length() ) break; // Hit the end of the string.
			// Find first space after start
			end = newRep.indexOf(' ',start+1);
			if ( end == -1 ) end = newRep.length(); // No space found.
			newRepValues[i] = newRep.substring(start,end); // intervals are closed on left end, open on right: [)
		}

		// Replicate the last item to fill up len.
		if ( i==0 && i<len ) newRepValues[i++] = "1";
		for ( j=i ; j<len ; j++ ) {
			newRepValues[j] = newRepValues[i-1];
		}
		setRepArray(newRepValues);
	}
	
	public String [] getRepArray() {
		return repValues;
	}

	void setRepArray(String newRepValues[]) {
		// Handles the case when newRepValues has more or fewer values than len.
		int inLen = newRepValues.length;
		String fillValue;
		int i;

		for ( i=0; i<inLen && i<len ; i++ ) {
			repValues[i] = newRepValues[i];
		}
		if ( inLen == 0 ) fillValue = "1";
		else fillValue = newRepValues[inLen-1];
		for ( i=inLen ; i<len ; i++ ) {
			repValues[i] = fillValue;
		}

		// Build up the new representation string.
		StringBuffer newRep = new StringBuffer();
		for ( i=0; i< len ; i++ ) {
			newRep.append(repValues[i]);
			if ( i+1 < len ) newRep.append(" "); 
		}
		rep = newRep.toString();
		
		for ( i=0; i<len ; i++ ) {
			relValues[i] = Double.valueOf(repValues[i]).doubleValue();
		}
		setValues();
	}

	public int [] getValues() {
		return values;
	}

	// Build an index array into repValues.  Sort that index array, and then
	// extract the relative values.
	void setValues() {
		int i, v;
		for (i=0;i<len;i++) {
			pos[0][i] = i;
		}

		localMergeSort(0,0,len);

		for (i=0,v=0;i<len;i++) {
			if ( i>0 && relValues[pos[0][i]] > relValues[pos[0][i-1]] ) v++;
			values[pos[0][i]] = v+1;	// Add 1 so that we can see the bar.
		}
	}
	
	// dst is the destination array.
	void localMergeSort(int dst, int Low, int Hi) {

		if ( Hi - Low > 1 ) {
			int mid = (Hi+Low)/2;
			int L, R, w;
			localMergeSort(1-dst,Low,mid);
			localMergeSort(1-dst,mid,Hi);
			// Now merge them
			L = Low; R = mid; w=Low;
			while ( L < mid || R < Hi ) {
				if ( L == mid ) {
					pos[dst][w++] = pos[1-dst][R++];
				} else if ( R == Hi ) {
					pos[dst][w++] = pos[1-dst][L++];
				} else {
					if ( relValues[pos[1-dst][L]] <= relValues[pos[1-dst][R]] ) {
						pos[dst][w++] = pos[1-dst][L++];
					} else {
						pos[dst][w++] = pos[1-dst][R++];
					}
				}
			}
		} else if ( Hi - Low == 1 ) {
			if ( dst != 0 ) pos[dst][Low] = pos[0][Low];
		}
	}
}
