package it.mice.voila.runtime.util;
/**
 * Licensed under the MICE s.r.l.
 * End User License Agreement
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.micegroup.it/voila/license.html
 */

import java.sql.Timestamp;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.tools.generic.DateTool;
import org.apache.velocity.tools.generic.MathTool;
import org.apache.velocity.tools.generic.NumberTool;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

/**
 * This class provides some methods for dynamically
 * invoking methods in objects, and some string
 * manipulation methods used by torque. The string
 * methods will soon be moved into the turbine
 * string utilities class.
 *
 * @author zzy9v4
 * @version $Id: VelocityContextUtils.java,v 1.1 2007/02/16 11:34:01 zzy9v4 Exp $
 */
public class VelocityContextUtils {
    private static Log logger = LogFactory.getLog(VelocityContextUtils.class);
    
    private static Map<String, Object> velocityContextToolsMap = new HashMap<String, Object>();
    
    static {
    	velocityContextToolsMap.put("math", new MathTool());
    	velocityContextToolsMap.put("number", new NumberTool());
    	velocityContextToolsMap.put("date", new DateTool());
    	velocityContextToolsMap.put("numberUtils", new NumberUtil());
    	velocityContextToolsMap.put("formatterUtil", new FormatterUtil());
    }

    /**
     * singletone instance.
     */
    private static VelocityContextUtils instance = null;
    private DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("yyyy/MM/dd");
    private DateTimeFormatter timeFormatter = DateTimeFormat.forPattern("HH:mm:ss");
    private DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyy/MM/dd HH:mm:ss");

    public static VelocityContextUtils getInstance() {
        if (instance == null) {
            if (logger.isDebugEnabled()) {
                logger.debug("Creating new instance velocity context utility object");
            }
            instance = new VelocityContextUtils();
        }
        return instance;
    }

    public String getCurrentDate() {
        return dateFormatter.print(System.currentTimeMillis());
    }

    public String getCurrentTime() {
        return timeFormatter.print(System.currentTimeMillis());
    }

    public String getCurrentDateTime() {
        return dateTimeFormatter.print(System.currentTimeMillis());
    }

    public int getCurrentDayOfWeek() {
        return new DateTime().getDayOfWeek();
    }

    public int getCurrentDayOfMonth() {
        return new DateTime().getDayOfMonth();
    }

    public int getCurrentDayOfYear() {
        return new DateTime().getDayOfYear();
    }

    public int getCurrentMonthOfYear() {
        return new DateTime().getMonthOfYear();
    }

    /**
     * Check current date time (yyyy/MM/dd hh:mm:ss) string between two given date time start/end period.
     *
     * @param dateTimeFrom start date/time
     * @param dateTimeTo   end date/time
     * @return true if current date is between the given range.
     */
    public boolean isCurrentDateTimeBetween(String dateTimeFrom, String dateTimeTo) {
        return (isDateBetween(getCurrentDateTime(), dateTimeFrom, dateTimeTo));
    }

    /**
     * Check current date (yyyy/MM/dd) string between two given date start/end period.
     *
     * @param dateFrom start date
     * @param dateTo   end date
     * @return true if current date is between the given range.
     */
    public boolean isCurrentDateBetween(String dateFrom, String dateTo) {
        return (isDateBetween(getCurrentDate(), dateFrom, dateTo));
    }

    public boolean isCurrentDateBetween(Timestamp dateFrom, Timestamp dateTo) {
        return (isDateBetween(getCurrentDate(), dateFormatter.print(dateFrom.getTime()), dateFormatter.print(dateTo.getTime())));
    }

    /**
     * Check current time (hh:mm:ss) string between two given time start/end period.
     *
     * @param timeFrom start time
     * @param timeTo   end time
     * @return true if current time is between the given range.
     */
    public boolean isCurrentTimeBetween(String timeFrom, String timeTo) {
        return (isTimeBetween(getCurrentTime(), timeFrom, timeTo));
    }

    /**
     * Check if the current date time (yyyy/MM/dd hh:mm:ss) string is before the given date/time string.
     *
     * @param dateTimeReference reference date/time
     * @return true if current date/time is before the given date/time.
     */
    public boolean isCurrentDateTimeBefore(String dateTimeReference) {
        return (isDateBefore(getCurrentDateTime(), dateTimeReference));
    }

    /**
     * Check if the current date (yyyy/MM/dd) string is before the given date string.
     *
     * @param dateReference reference date
     * @return true if current date is before the given date.
     */
    public boolean isCurrentDateBefore(String dateReference) {
        return (isDateBefore(getCurrentDate(), dateReference));
    }

    public boolean isCurrentDateBefore(Timestamp dateReference) {
        return (isDateBefore(getCurrentDate(), dateFormatter.print(dateReference.getTime())));
    }

    /**
     * Check if the current time (hh:mm:ss) string is before the given time string.
     *
     * @param timeReference reference time
     * @return true if current time is before the given time.
     */
    public boolean isCurrentTimeBefore(String timeReference) {
        return (isTimeBefore(getCurrentTime(), timeReference));
    }

    /**
     * Check if the current date time (yyyy/MM/dd hh:mm:ss) string is after the given date/time string.
     *
     * @param dateTimeReference reference date/time
     * @return true if current date/time is after the given date/time.
     */
    public boolean isCurrentDateTimeAfter(String dateTimeReference) {
        return (isDateAfter(getCurrentDateTime(), dateTimeReference));
    }

    /**
     * Check if the current date (yyyy/MM/dd) string is after the given date string.
     *
     * @param dateReference reference date
     * @return true if current date is after the given date.
     */
    public boolean isCurrentDateAfter(String dateReference) {
        return (isDateAfter(getCurrentDate(), dateReference));
    }

    public boolean isCurrentDateAfter(Timestamp dateReference) {
        return (isDateAfter(getCurrentDate(), dateFormatter.print(dateReference.getTime())));
    }

    /**
     * Check if the current time (hh:mm:ss) string is after the given time string.
     *
     * @param timeReference reference time
     * @return true if current time is after the given time.
     */
    public boolean isCurrentTimeAfter(String timeReference) {
        return (isTimeAfter(getCurrentTime(), timeReference));
    }

    public boolean isCurrentDayOfWeek(int dayOfWeek) {
        return (isDayOfWeek(getCurrentDate(), dayOfWeek));
    }

    public boolean isCurrentDayOfMonth(int dayOfMonth) {
        return (isDayOfMonth(getCurrentDate(), dayOfMonth));
    }

    public boolean isCurrentDayOfYear(int dayOfYear) {
        return (isDayOfYear(getCurrentDate(), dayOfYear));
    }

    public boolean isCurrentMonthOfYear(int monthOfYear) {
        return (isMonthOfYear(getCurrentDate(), monthOfYear));
    }

    public boolean isDateTimeBetween(String dateTime, String dateTimeFrom, String dateTimeTo) {
        DateTime aDateTime = dateTimeFormatter.parseDateTime(dateTime);
        DateTime aDateTimeFrom = dateTimeFormatter.parseDateTime(dateTimeFrom);
        DateTime aDateTimeTo = dateTimeFormatter.parseDateTime(dateTimeTo);

        return (isDateTimeBetween(aDateTime, aDateTimeFrom, aDateTimeTo));
    }

    public boolean isDateBetween(String date, String dateFrom, String dateTo) {
        DateTime aDateTime = dateFormatter.parseDateTime(date);
        DateTime aDateTimeFrom = dateFormatter.parseDateTime(dateFrom);
        DateTime aDateTimeTo = dateFormatter.parseDateTime(dateTo);

        return (isDateTimeBetween(aDateTime, aDateTimeFrom, aDateTimeTo));
    }

    public boolean isTimeBetween(String time, String timeFrom, String timeTo) {
        DateTime aTime = timeFormatter.parseDateTime(time);
        DateTime aTimeFrom = timeFormatter.parseDateTime(timeFrom);
        DateTime aTimeTo = timeFormatter.parseDateTime(timeTo);

        return (isDateTimeBetween(aTime, aTimeFrom, aTimeTo));
    }

    public boolean isDateTimeBefore(String dateTime, String dateTimeReference) {
        DateTime aDateTime = dateTimeFormatter.parseDateTime(dateTime);
        DateTime aDateTimeReference = dateTimeFormatter.parseDateTime(dateTimeReference);

        return (isDateTimeBefore(aDateTime, aDateTimeReference));
    }

    public boolean isDateBefore(String date, String dateReference) {
        DateTime aDateTime = dateFormatter.parseDateTime(date);
        DateTime aDateTimeReference = dateFormatter.parseDateTime(dateReference);

        return (isDateTimeBefore(aDateTime, aDateTimeReference));
    }

    public boolean isTimeBefore(String time, String timeReference) {
        DateTime aTime = timeFormatter.parseDateTime(time);
        DateTime aTimeReference = timeFormatter.parseDateTime(timeReference);

        return (isDateTimeBefore(aTime, aTimeReference));
    }

    public boolean isDateTimeAfter(String dateTime, String dateTimeReference) {
        DateTime aDateTime = dateTimeFormatter.parseDateTime(dateTime);
        DateTime aDateTimeReference = dateTimeFormatter.parseDateTime(dateTimeReference);

        return (isDateTimeAfter(aDateTime, aDateTimeReference));
    }

    public boolean isDateAfter(String date, String dateReference) {
        DateTime aDateTime = dateFormatter.parseDateTime(date);
        DateTime aDateTimeReference = dateFormatter.parseDateTime(dateReference);

        return (isDateTimeAfter(aDateTime, aDateTimeReference));
    }

    public boolean isTimeAfter(String time, String timeReference) {
        DateTime aTime = timeFormatter.parseDateTime(time);
        DateTime aTimeReference = timeFormatter.parseDateTime(timeReference);

        return (isDateTimeAfter(aTime, aTimeReference));
    }

    public boolean isDayOfWeek(String date, int dayOfWeek) {
        DateTime aDateTime = dateFormatter.parseDateTime(date);

        return (isDayOfWeek(aDateTime, dayOfWeek));
    }

    public boolean isDayOfMonth(String date, int dayOfMonth) {
        DateTime aDateTime = dateFormatter.parseDateTime(date);

        return (isDayOfMonth(aDateTime, dayOfMonth));
    }

    public boolean isDayOfYear(String date, int dayOfYear) {
        DateTime aDateTime = dateFormatter.parseDateTime(date);

        return (isDayOfYear(aDateTime, dayOfYear));
    }

    public boolean isMonthOfYear(String date, int monthOfYear) {
        DateTime aDateTime = dateFormatter.parseDateTime(date);

        return (isMonthOfYear(aDateTime, monthOfYear));
    }

    public boolean isIncludedInList(Object refValue, Object[] listValue, boolean defaultForEmptyList, boolean defaultForRefValueNull) {
    	return true;
    }

    public boolean isIncludedInList(Comparable<Object> refValue, Collection<Comparable<Object>> listValue, boolean defaultForEmptyList, boolean defaultForRefValueNull) {
    	boolean result = false;
    	if (listValue == null || listValue.size() == 0) {
    		result = defaultForEmptyList;
    	} else if (refValue == null) {
    		result = defaultForRefValueNull;
    	} else {
        	Iterator<Comparable<Object>> iter = listValue.iterator();
        	while (iter.hasNext()) {
    			Comparable<Object> element = iter.next();
        		if (element.compareTo(refValue) == 0) {
        			result = true;
        		}
    		}
    	}
    	return result;
    }

    private boolean isDateTimeBetween(DateTime date, DateTime dateFrom, DateTime dateTo) {
        return (!date.isBefore(dateFrom) && !date.isAfter(dateTo));
    }

    private boolean isDateTimeBefore(DateTime date, DateTime dateReference) {
        return (date.isBefore(dateReference));
    }

    private boolean isDateTimeAfter(DateTime date, DateTime dateReference) {
        return (date.isAfter(dateReference));
    }

    private boolean isDayOfWeek(DateTime dateTimeRef, int dayOfWeek) {
        return (dateTimeRef.getDayOfWeek() == dayOfWeek);
    }

    private boolean isDayOfMonth(DateTime dateTimeRef, int dayOfMonth) {
        return (dateTimeRef.getDayOfMonth() == dayOfMonth);
    }

    private boolean isDayOfYear(DateTime dateTimeRef, int dayOfYear) {
        return (dateTimeRef.getDayOfYear() == dayOfYear);
    }

    private boolean isMonthOfYear(DateTime dateTimeRef, int monthOfYear) {
        return (dateTimeRef.getMonthOfYear() == monthOfYear);
    }
    
    public static Map<String, Object> getVelocityContextToolsMap() {
    	return velocityContextToolsMap;
    }
}
