package info.bukova.isspst.sort;

import info.bukova.isspst.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.Collator;
import java.text.ParseException;
import java.text.RuleBasedCollator;
import java.util.Comparator;
import java.util.List;

import org.zkoss.zk.ui.util.Clients;

public class CzechStringComparator implements Comparator<Object> {
	private String m_rule;
	private final List<String> m_propertyPath;
	private final boolean m_ascending;
	private Comparator<Object> m_comparator;

	public CzechStringComparator(String property, boolean ascending) {
		m_rule = "";
		m_rule += "< 0 < 1 < 2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 ";
		m_rule += "< A,a < Á,á < Ä,ä ";
		m_rule += "< B,b ";
		m_rule += "< C,c < Ć,ć < Č,č ";
		m_rule += "< D,d < Ď,ď ";
		m_rule += "< E,e < É,é < Ë,ë ";
		m_rule += "< F,f ";
		m_rule += "< G,g ";
		m_rule += "< H,h ";
		m_rule += "< CH,Ch,ch ";
		m_rule += "< I,i < Í,í ";
		m_rule += "< J,j ";
		m_rule += "< K,k ";
		m_rule += "< L,l < Ľ,ľ < Ĺ,ĺ ";
		m_rule += "< M,m ";
		m_rule += "< N,n < Ń,ń < Ň,ň ";
		m_rule += "< O,o < Ó,ó < Ö,ö ";
		m_rule += "< P,p ";
		m_rule += "< Q,q ";
		m_rule += "< R,r < Ŕ,ŕ < Ř,ř ";
		m_rule += "< S,s < ß < Ś,ś < Š,š ";
		m_rule += "< T,t < Ť,ť ";
		m_rule += "< U,u < Ú,ú < Ů,ů < Ü,ü ";
		m_rule += "< V,v ";
		m_rule += "< W,w ";
		m_rule += "< X,x ";
		m_rule += "< Y,y < Ý,ý ";
		m_rule += "< Z,z < Ź,ź < Ž,ž ";

		m_propertyPath = StringUtils.split(property, ".");
		m_ascending = ascending;
	}

	@Override
	public int compare(Object argL, Object argR) {
		try {
			return this.internalCompare(argL, argR);

		} catch (ParseException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return 0;
	}

	private Object getValue(Object caller)
	{
		Object obj = caller;

		for (String property : m_propertyPath)
		{
			if (obj == null)
			{
				return null;
			}

			Method method = ReflectionTools.getGetterMethod(obj, property);

			try
			{
				obj = method.invoke(obj);
			}
			catch (IllegalAccessException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			catch (IllegalArgumentException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			catch (InvocationTargetException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return obj;
	}

	private int internalCompare(Object argL, Object argR)
			throws ParseException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException {

		if (m_comparator == null)
		{
			Collator c = new RuleBasedCollator(m_rule);
			c.setStrength(Collator.TERTIARY);
			m_comparator = c;
		}

		Object valL = this.getValue(argL);
		Object valR = this.getValue(argR);
		boolean isNullValL = (valL == null);
		boolean isNullValR = (valR == null);

		int result = 0;

		if (isNullValL || isNullValR) {
			if (isNullValL && isNullValR) {
				result = 0;
			} else if (isNullValL) {
				result = -1;
			} else {
				result = 1;
			}
		} else {

			if (valL instanceof String) {
				result = m_comparator.compare(valL, valR);
			} else {
				String className = valL.getClass().getName();
				Clients.alert(
						"Nepodporovaný datový typ '"
								+ className
								+ "' pro třídění 'sort=czech(...)'. Použít 'sort=auto(...)'",
						"Franta", Clients.NOTIFICATION_TYPE_WARNING);
			}
		}

		return (m_ascending ? result : -result);
	}
}
