package relational;

import java.io.Serializable;
import java.util.*;

/**
 * Sorts results by a single column. (Versus a hypothetical sort that
 * sorts by multiple columns, in priority order.)
 */
public class OrderByOne
	implements OrderBy {

	class RowComparator implements Comparator, Serializable {
		Comparator fieldCompare;

		RowComparator(Comparator fieldCompare) {
			if (fieldCompare!=null) {
				this.fieldCompare = fieldCompare;
			} else {
				this.fieldCompare = new DefaultComparator();
			}
		}

		public int compare(Object o1, Object o2) {
			Row ro1 = (Row) o1;
			Row ro2 = (Row) o2;
			Object d1 = fd.get(ro1);
			Object d2 = fd.get(ro2);
			return fieldCompare.compare(d1, d2);
		}
	}

	static class DefaultComparator implements Comparator, Serializable {
		public int compare(Object o1, Object o2) {
			return o1.toString().compareTo(o2.toString());
		}
	}

	static class NaturalComparator implements Comparator, Serializable {
		public int compare(Object o1, Object o2) {
			Comparable c1 = (Comparable) o1;
			Comparable c2 = (Comparable) o2;
			return c1.compareTo(c2);
		}
	}

	FieldDescriptor fd;
	Comparator comp;

	public OrderByOne(FieldDescriptor fd) {
		this(fd, null);
	}

	// fieldComp is a Comparator that compares objects of type fd.getType().
	// fieldComp=null implies the default (tostring().compareTo()) Comparator
	public OrderByOne(FieldDescriptor fd, Comparator fieldComp) {
		this.fd = fd;
		this.comp = new RowComparator(fieldComp);
	}

	public ResultSet order(ResultSet rs) {
		Vector v = rs.getVector();	// going to smash this vector,
									// which will smash the rs, but
									// no-one will notice.
									// TODO make explicit in the interface.
		Collections.sort(v, comp);
		ResultSetImpl rsnew = new ResultSetImpl(rs.getFromClause(), v);
		return rsnew;
	}

	public static OrderBy natural(FieldDescriptor fd) {
		return new OrderByOne(fd, new NaturalComparator());
	}
}
