package it.mice.voila.runtime.hibernate.interceptor;

import java.util.ArrayList;
import java.util.Collection;

import org.apache.commons.lang.StringUtils;

/**
 * Created by IntelliJ IDEA.
 * User: zzy9v4
 * Date: 23-feb-2007
 * Time: 10.39.27
 * To change this template use File | Settings | File Templates.
 */
public class CustomNullsFirstInterceptor extends CustomInterceptor {
	
	private static final long serialVersionUID = -3156853534261313031L;
	
	private static final String ORDER_BY_TOKEN = "order by";

	public String onPrepareStatement(String sql) {
		if (sql.indexOf("ignoreNullsFirst") > -1) {
			return super.onPrepareStatement(sql);
		}
		//TODO ricontrollare in quanto non funziona con order by contenenti espressioni complesse tipo NVL, ecc...
		int orderByStart = sql.toLowerCase().indexOf(ORDER_BY_TOKEN);
		if (orderByStart == -1) {
			return super.onPrepareStatement(sql);
		}
		sql = prepareSqlStatement(sql, orderByStart); 
		return super.onPrepareStatement(sql);
	}

	private String prepareSqlStatement(String sql, int orderByStart) {
		int counter = orderByStart + ORDER_BY_TOKEN.length() + 1;
		Collection orderByNames = new ArrayList();
		int maxLength = sql.length();
		String currentOrderByElement = "";
		int parDepth = 0;
		while (counter < maxLength) {
			char char1 = sql.charAt(counter);
			if (char1 == ',' && parDepth == 0) {
				orderByNames.add(currentOrderByElement.trim());
				currentOrderByElement = "";
				counter++;
			} else {
				if (char1 == '(') {
					parDepth++;
				}
				if (char1 == ')') {
					parDepth--;
				}
				currentOrderByElement += char1;
				counter++;
			}
		}
		sql = finalizeSqlStatement(sql, orderByStart, counter, orderByNames,
				currentOrderByElement);
		return sql;
	}

	private String finalizeSqlStatement(String sql, int orderByStart,
			int counter, Collection orderByNames, String currentOrderByElement) {
		if (currentOrderByElement.trim().length() > 0) {
			orderByNames.add(currentOrderByElement);
		}
		int orderByEnd = counter;

		String[] orderByNamesArray = (String[])orderByNames.toArray(new String[0]);
		//String orderByContent = sql.substring(orderByStart, orderByEnd);
		//String[] orderByNames = orderByContent.split("\\,");
		for (int i=0; i<orderByNamesArray.length; i++) {
			if (orderByNamesArray[i].trim().length() > 0) {
				if (orderByNamesArray[i].trim().toLowerCase().endsWith("desc")) {
					orderByNamesArray[i] += " NULLS LAST";
				} else {
					orderByNamesArray[i] += " NULLS FIRST";
				}
			}
		}
		String orderByContent = StringUtils.join(orderByNamesArray, ",");
		sql = sql.substring(0, orderByStart) + ORDER_BY_TOKEN + " " + orderByContent + sql.substring(orderByEnd);
		return sql;
	}
	
}
