/**
 * 
 */
package org.forkalsrud.album.exif;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author knut
 *
 */
public class ComparatorFactory {

	public static final String ASC = "asc";
	public static final String DESC = "desc";
	public static final String DIR = "dir";
	public static final String DATE = "date";
	public static final String NAME = "name";

	static Pattern SORT_SPEC_SYNTAX = Pattern.compile("(\\w+)(\\s+(" + ASC + "|" + DESC + "))?,? *");

	static ComparatorFactory singleton = new ComparatorFactory();

	Comparator<Entry> directoryFirst = new Comparator<Entry>() {

		@Override
        public int compare(Entry e1, Entry e2) {

		    boolean d1 = "dir".equals(e1.getType());
            boolean d2 = "dir".equals(e2.getType());
        	if (d1 && !d2) {
        		return -1;
        	} else if (!d1 && d2) {
        		return +1;
        	}
        	return 0;
		}
	 };


	 Comparator<Entry> dates = new Comparator<Entry>() {

		 @Override
        public int compare(Entry e1, Entry e2) {

			 Date d1 = e1.getEarliest();
			 Date d2 = e2.getEarliest();
			 if (d1 != null && d2 != null) {
				 return d1.compareTo(d2);
			 } else if (d1 != null) {
				 return -1;
			 } else if (d2 != null) {
				 return +1;
			 } else {
				 return 0;
			 }
		 }
	 };

	 Comparator<Entry> names = new Comparator<Entry>() {

		 @Override
        public int compare(Entry e1, Entry e2) {

			 String n1 = e1.getName();
			 String n2 = e2.getName();
			 if (n1 != null && n2 != null) {
				 return n1.compareTo(n2);
			 } else if (n1 != null) {
				 return -1;
			 } else if (n2 != null) {
				 return +1;
			 } else {
				 return 0;
			 }
		 }
	 };

	 HashMap<String, Comparator<Entry>> map = new HashMap<String, Comparator<Entry>>(); 

	 public ComparatorFactory() {

		 map.put(DIR, directoryFirst);
		 map.put(DATE, dates);
		 map.put(NAME, names);
	 }

	 public static <T> Comparator<T> reverse(final Comparator<T> c) {

		 return new Comparator<T>() {

			@Override
            public int compare(T o1, T o2) {
				return c.compare(o2, o1);
			}
		 };
	 }



	 public Comparator<Entry> getComparator(String sortSpec) {

		 Matcher m = SORT_SPEC_SYNTAX.matcher(sortSpec);
		 int start = 0;
		 ArrayList<Comparator<Entry>> list = new ArrayList<Comparator<Entry>>(); 
		 while (m.find(start)) {

			 String param = m.group(1);
			 String direction = m.group(3);
			 Comparator<Entry> c = map.get(param);
			 if (c == null) {
				 throw new IllegalArgumentException(param);
			 }
			 if (DESC.equals(direction)) {
				 c = reverse(c);
			 }
			 list.add(c);
			 start = m.end();
		 }
		 return new ComposingComparator<Entry>(list);
	 }

	 public static Comparator<Entry> getSort(String sortSpec) {

		 return singleton.getComparator(sortSpec != null ? sortSpec : "dir, date");
	 }
}