/*
* Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
*
* 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
*
* http://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 net.sf.antcontrib.property;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.Locale;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.types.Reference;
/****************************************************************************
* Place class description here.
*
* @author <a href='mailto:mattinger@yahoo.com'>Matthew Inger</a>
* @author <additional author>
*
* @since
*
****************************************************************************/
public class SortList
extends AbstractPropertySetterTask
{
private String value;
private Reference ref;
private boolean casesensitive = true;
private boolean numeric = false;
private String delimiter = ",";
private File orderPropertyFile;
private String orderPropertyFilePrefix;
public SortList()
{
super();
}
public void setNumeric(boolean numeric)
{
this.numeric = numeric;
}
public void setValue(String value)
{
this.value = value;
}
public void setRefid(Reference ref)
{
this.ref = ref;
}
public void setCasesensitive(boolean casesenstive)
{
this.casesensitive = casesenstive;
}
public void setDelimiter(String delimiter)
{
this.delimiter = delimiter;
}
public void setOrderPropertyFile(File orderPropertyFile)
{
this.orderPropertyFile = orderPropertyFile;
}
public void setOrderPropertyFilePrefix(String orderPropertyFilePrefix)
{
this.orderPropertyFilePrefix = orderPropertyFilePrefix;
}
private static void mergeSort(String src[],
String dest[],
int low,
int high,
boolean caseSensitive,
boolean numeric) {
int length = high - low;
// Insertion sort on smallest arrays
if (length < 7) {
for (int i=low; i<high; i++)
for (int j=i; j>low &&
compare(dest[j-1],dest[j], caseSensitive, numeric)>0; j--)
swap(dest, j, j-1);
return;
}
// Recursively sort halves of dest into src
int mid = (low + high)/2;
mergeSort(dest, src, low, mid, caseSensitive, numeric);
mergeSort(dest, src, mid, high, caseSensitive, numeric);
// If list is already sorted, just copy from src to dest. This is an
// optimization that results in faster sorts for nearly ordered lists.
if (compare(src[mid-1], src[mid], caseSensitive, numeric) <= 0) {
System.arraycopy(src, low, dest, low, length);
return;
}
// Merge sorted halves (now in src) into dest
for(int i = low, p = low, q = mid; i < high; i++) {
if (q>=high || p<mid && compare(src[p], src[q], caseSensitive, numeric)<=0)
dest[i] = src[p++];
else
dest[i] = src[q++];
}
}
private static int compare(String s1,
String s2,
boolean casesensitive,
boolean numeric)
{
int res = 0;
if (numeric)
{
double d1 = new Double(s1).doubleValue();
double d2 = new Double(s2).doubleValue();
if (d1 < d2)
res = -1;
else if (d1 == d2)
res = 0;
else
res = 1;
}
else if (casesensitive)
{
res = s1.compareTo(s2);
}
else
{
Locale l = Locale.getDefault();
res = s1.toLowerCase(l).compareTo(s2.toLowerCase(l));
}
return res;
}
/**
* Swaps x[a] with x[b].
*/
private static void swap(Object x[], int a, int b) {
Object t = x[a];
x[a] = x[b];
x[b] = t;
}
private Vector sortByOrderPropertyFile(Vector props)
throws IOException
{
FileReader fr = null;
Vector orderedProps = new Vector();
try
{
fr = new FileReader(orderPropertyFile);
BufferedReader br = new BufferedReader(fr);
String line = "";
String pname = "";
int pos = 0;
while ((line = br.readLine()) != null)
{
pos = line.indexOf('#');
if (pos != -1)
line = line.substring(0, pos).trim();
if (line.length() > 0)
{
pos = line.indexOf('=');
if (pos != -1)
pname = line.substring(0,pos).trim();
else
pname = line.trim();
String prefPname = pname;
if (orderPropertyFilePrefix != null)
prefPname = orderPropertyFilePrefix + "." + prefPname;
if (props.contains(prefPname) &&
! orderedProps.contains(prefPname))
{
orderedProps.addElement(prefPname);
}
}
}
Enumeration e = props.elements();
while (e.hasMoreElements())
{
String prop = (String)(e.nextElement());
if (! orderedProps.contains(prop))
orderedProps.addElement(prop);
}
return orderedProps;
}
finally
{
try
{
if (fr != null)
fr.close();
}
catch (IOException e)
{
; // gulp
}
}
}
protected void validate()
{
super.validate();
}
public void execute()
{
validate();
String val = value;
if (val == null && ref != null)
val = ref.getReferencedObject(project).toString();
if (val == null)
throw new BuildException("Either the 'Value' or 'Refid' attribute must be set.");
StringTokenizer st = new StringTokenizer(val, delimiter);
Vector vec = new Vector(st.countTokens());
while (st.hasMoreTokens())
vec.addElement(st.nextToken());
String propList[] = null;
if (orderPropertyFile != null)
{
try
{
Vector sorted = sortByOrderPropertyFile(vec);
propList = new String[sorted.size()];
sorted.copyInto(propList);
}
catch (IOException e)
{
throw new BuildException(e);
}
}
else
{
String s[] = (String[])(vec.toArray(new String[vec.size()]));
propList = new String[s.length];
System.arraycopy(s, 0, propList, 0, s.length);
mergeSort(s, propList, 0, s.length, casesensitive, numeric);
}
StringBuffer sb = new StringBuffer();
for (int i=0;i<propList.length;i++)
{
if (i != 0) sb.append(delimiter);
sb.append(propList[i]);
}
setPropertyValue(sb.toString());
}
}