/*******************************************************************************
 * Copyright 2019 2Fi Business Solutions Ltd.
 *
 * This code is part of the Core project.
 *
 * This code is copyrighted. Under no circumstances should any party, people,
 * or organization should redistribute any portions of this code in any form,
 * either verbatim or through electronic media, to any third parties, unless
 * under explicit written permission by 2Fi Business Solutions Ltd.
 ******************************************************************************/
package com.ffii.core.utils;

import java.sql.Date;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.bind.ServletRequestBindingException;

import com.ffii.core.utils.web.ServletRequestUtils;

/**
 * Utils for getting parameter values from HTTP Request and put them into a criteria map if found
 *
 * @author Patrick
 */
public abstract class CriteriaUtils {

	/**
	 * Alias for {@link #addString(HttpServletRequest, Map, String)}
	 */
	public static void addStringExact(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		addString(request, args, paramName);
	}

	/**
	 * Alias for {@link #addStringContains(HttpServletRequest, Map, String)}
	 */
	public static void addStringLike(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		addStringContains(request, args, paramName);
	}

	/**
	 * Add a String (an exact value for using equal sign in SQL) parameter to criteria. Usually used for exact string search.
	 */
	public static void addString(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		String value = ServletRequestUtils.getTrimmedStringParameter(request, paramName);
		if (value != null) args.put(paramName, value);
	}

	/**
	 * Add a String (a substring value for using <code>LIKE</code> in SQL) parameter to criteria. Usually used for substring search for values that contains the
	 * input value.
	 */
	public static void addStringContains(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		String value = ServletRequestUtils.getTrimmedStringParameter(request, paramName);
		if (value != null) args.put(paramName, StringUtils.PERCENT + value + StringUtils.PERCENT);
	}

	/**
	 * Add a String (a substring value for using <code>LIKE</code> in SQL) parameter to criteria. Usually used for substring search for values that starts with
	 * the input value.
	 */
	public static void addStringStartsWith(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		String value = ServletRequestUtils.getTrimmedStringParameter(request, paramName);
		if (value != null) args.put(paramName, value + StringUtils.PERCENT);
	}

	/**
	 * Add a String (a substring value for using <code>LIKE</code> in SQL) parameter to criteria. Usually used for substring search for values that ends with
	 * the input value.
	 */
	public static void addStringEndsWith(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		String value = ServletRequestUtils.getTrimmedStringParameter(request, paramName);
		if (value != null) args.put(paramName, StringUtils.PERCENT + value);
	}

	/**
	 * Add String List parameter to criteria.
	 */
	public static void addStringList(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		String[] params = ServletRequestUtils.getStringParameters(request, paramName);
		if (params.length > 0) {
			List<String> value = new ArrayList<String>();
			for (int i = 0; i < params.length; i++)
				if (StringUtils.isNotBlank(params[i])) value.add(params[i]);
			if (value.size() > 0) args.put(paramName, value);
		}
	}

	/**
	 * Add String CSV parameter to criteria.
	 */
	public static void addStringCsv(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		String text = ServletRequestUtils.getStringParameter(request, paramName);
		if (StringUtils.isNotEmpty(text)) {
			String[] params = text.split(",");
			List<String> values = new ArrayList<String>();
			for (int i = 0; i < params.length; i++)
				values.add(params[i]);
			args.put(paramName, values);
		}
	}

	/**
	 * Add an Integer parameter to criteria.
	 */
	public static void addInteger(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		Integer value = ServletRequestUtils.getIntParameter(request, paramName, null);
		if (value != null) args.put(paramName, value);
	}

	/**
	 * Add a non-zero Integer parameter to criteria.
	 */
	public static void addNonZeroInteger(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		Integer value = ServletRequestUtils.getIntParameter(request, paramName, null);
		if (value != null && value.intValue() != 0) args.put(paramName, value);
	}

	/**
	 * Add Integer List parameter to criteria.
	 */
	public static void addIntegerList(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		int[] params = ServletRequestUtils.getIntParameters(request, paramName);
		if (params.length > 0) {
			List<Integer> values = new ArrayList<Integer>();
			for (int i = 0; i < params.length; i++)
				values.add(params[i]);
			args.put(paramName, values);
		}
	}

	/**
	 * Add non-zero Integer List parameter to criteria.
	 */
	public static void addNonZeroIntegerList(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		int[] params = ServletRequestUtils.getIntParameters(request, paramName);
		if (params.length > 0) {
			List<Integer> values = new ArrayList<Integer>();
			for (int i = 0; i < params.length; i++)
				if (params[i] != 0) values.add(params[i]);
			args.put(paramName, values);
		}
	}

	/**
	 * Add a Long parameter to criteria.
	 */
	public static void addLong(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		Long value = ServletRequestUtils.getLongParameter(request, paramName, null);
		if (value != null) args.put(paramName, value);
	}

	/**
	 * Add a non-zero Long parameter to criteria.
	 */
	public static void addNonZeroLong(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		Long value = ServletRequestUtils.getLongParameter(request, paramName, null);
		if (value != null && value.longValue() != 0L) args.put(paramName, value);
	}

	/**
	 * Add a SQL Date parameter to criteria. Usually used for <code>FROM</code> date range search, or exact date search.
	 */
	public static void addDate(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		Date value = ServletRequestUtils.getSqlDateParameter(request, paramName);
		if (value != null) args.put(paramName, value);
	}

	/**
	 * Add a SQL Date (plus 1 day) parameter to criteria. Usually used for {@code TO} date range search.
	 */
	public static void addDateTo(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		Date value = ServletRequestUtils.getSqlDateParameter(request, paramName);
		if (value != null) args.put(paramName, DateUtils.add(value.getClass(), value, Calendar.DAY_OF_MONTH, 1));
	}

	/**
	 * Add a Boolean parameter to criteria if it's not {@code null}. Accepts "true", "on", "yes" (any case) and "1" as values for true; treats every other
	 * non-empty value as false (i.e. parses leniently).
	 */
	public static void addBoolean(HttpServletRequest request, Map<String, Object> args, String paramName) throws ServletRequestBindingException {
		Boolean value = ServletRequestUtils.getBooleanParameter(request, paramName);
		if (value != null) args.put(paramName, value);
	}

}
