package com.foreverwin.mesnac.common.util;

import com.sap.tc.logging.Category;
import com.sap.tc.logging.Location;
import com.sap.tc.logging.Severity;
import com.sap.tc.logging.SimpleLogger;
import com.visiprise.globalization.DateGlobalizationServiceInterface;
import com.visiprise.globalization.GlobalizationService;
import com.visiprise.globalization.KnownGlobalizationServices;
import com.visiprise.globalization.util.DateTimeInterface;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

public class DateUtil
{


	public static final String[] YEARS = {"2017年", "2018年", "2019年", "2020年", "2021年", "2022年", "2023年", "2024年", "2025年", "2026年", "2027年"};
	public static final String[] YEARS_SHORT = {"2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025", "2026", "2027"};
	public static final String[] MONTHS = {"01月", "02月", "03月", "04月", "05月", "06月", "07月", "08月", "09月", "10月", "11月", "12月"};
	public static final String[] MONTHS_SHORT = {"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"};
	public static final String[] DAYS = {"0天", "1天", "2天", "3天", "4天", "5天", "6天", "7天", "8天", "9天", "10天", 
							   	         "11天", "12天", "13天", "14天", "15天", "16天", "17天", "18天", "19天", "20天", 
							   	         "21天", "22天", "23天", "24天", "25天", "26天", "27天", "28天", "29天", "30天", "31天"};
	
	public static final short DATE_TYPE_MILLISECOND = 0;
	public static final short DATE_TYPE_SECOND = 1;
	public static final short DATE_TYPE_MINUTE = 2;
	public static final short DATE_TYPE_HOUR = 3;
	public static final short DATE_TYPE_DAY = 4;
			
	private static final String[] WEEK_DAYS = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"}; 
	
	private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	private static final SimpleDateFormat FORMATTER_SERIAL = new SimpleDateFormat("yyyyMMddHHmmss");
	private static final SimpleDateFormat FORMATTER_SHORT = new SimpleDateFormat("yyyy-MM-dd");
	private static final SimpleDateFormat FORMATTER_SHORT_GMT = new SimpleDateFormat("yyyy-MM-dd");
	private static final SimpleDateFormat FORMATTER_SHORT_SLASH = new SimpleDateFormat("yyyy/MM/dd");
	private static final SimpleDateFormat FORMATTER_SHORT_SERIAL = new SimpleDateFormat("yyyyMMdd");
	private static final SimpleDateFormat FORMATTER_MIDDLE = new SimpleDateFormat("yyyy-MM-dd HH:mm");
	private static final SimpleDateFormat FORMATTER_LONG = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
	private static final SimpleDateFormat FORMATTER_LONG_SERIAL = new SimpleDateFormat("yyyyMMddHHmmssSSS");
	private static final SimpleDateFormat FORMATTER_NUMBER = new SimpleDateFormat("yyMMddHHmmss");
	private static final SimpleDateFormat FORMATTER_YEAR = new SimpleDateFormat("yyyy");
	private static final SimpleDateFormat FORMATTER_MONTH = new SimpleDateFormat("MM");
	private static final SimpleDateFormat FORMATTER_DAY = new SimpleDateFormat("dd");
	private static final SimpleDateFormat FORMATTER_YEAR_MONTH = new SimpleDateFormat("yyyy-MM");
	private static final SimpleDateFormat FORMATTER_YEAR_MONTH_SERIAL = new SimpleDateFormat("yyyyMM");

	public static Date toDate(LocalDate localDate) {
		if (localDate == null) return null;

		return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
	}

	public static Date toDate(LocalDateTime localDateTime)
	{
		if (localDateTime == null) return null;

		return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
	}

	//Date -> LocalDate
	public static LocalDate toLocalDate(Date date)
	{
		if (date == null) return null;

		return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
	}

	//Date -> LocalDateTime
	public static LocalDateTime toLocalDateTime(Date date)
	{
		if (date == null) return null;

		return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
	}

	public static Date parseDate(String str)
	{
		str = StringUtil.toString(str);
		if (!str.equals(""))
		{
			try 
			{
				return FORMATTER.parse(str);
			}
			catch (Exception ex) 
			{
				ex.printStackTrace();
				return parseDateShort(str);
			}
		}
		return null;
	}
	
	public static Date parseDateShort(String str)
	{
		str = StringUtil.toString(str);
		if (!str.equals(""))
		{
			try 
			{
				return FORMATTER_SHORT.parse(str);
			}
			catch (Exception ex)
			{
				ex.printStackTrace();
			}
		}
		return null;
	}
	
	public static Date parseDateLong(String str) 
	{
		str = StringUtil.toString(str);
		if (!str.equals(""))
		{
			try 
			{
				return FORMATTER_LONG.parse(str);
			}
			catch (Exception ex)
			{
				ex.printStackTrace();
			}
		}
		return null;
	}
	
	public static Date parseDateYearMonth(String str)
	{
		str = StringUtil.toString(str);
		if (!str.equals(""))
		{
			try 
			{
				return FORMATTER_YEAR_MONTH.parse(str);
			}
			catch (Exception ex)
			{
				ex.printStackTrace();
			}
		}
		return null;
	}
	
	public static String formatDate(Date date)
	{
		if (date != null)
		{
			return FORMATTER.format(date);
		}
		return "";
	}
	
	public static String formatDateSerial(Date date)
	{
		if (date != null)
		{
			return FORMATTER_SERIAL.format(date);
		}
		return "";
	}
	//FORMATTER_LONG_SERIAL
	public static String formatDateLongSerial(Date date)
	{
		if (date != null)
		{
			return FORMATTER_LONG_SERIAL.format(date);
		}
		return "";
	}

	public static String formatDateShort(Date date)
	{
		if (date != null)
		{
			return FORMATTER_SHORT.format(date);
		}
		return "";
	}
	
	public static String formatDateShortSlash(Date date)
	{
		if (date != null)
		{
			return FORMATTER_SHORT_SLASH.format(date);
		}
		return "";
	}
	
	public static String formatDateShortSerial(Date date)
	{
		if (date != null)
		{
			return FORMATTER_SHORT_SERIAL.format(date);
		}
		return "";
	}
	
	public static String formatDateMiddle(Date date)
	{
		if (date != null)
		{
			return FORMATTER_MIDDLE.format(date);
		}
		return "";
	}

	public static String formatDateLong(Date date)
	{
		if (date != null)
		{
			return FORMATTER_LONG.format(date);
		}
		return "";
	}
	
	public static String formatDateNumber(Date date)
	{
		if (date != null)
		{
			return FORMATTER_NUMBER.format(date);
		}
		return "";
	}

	public static String formatDateYear(Date date)
	{
		if (date != null)
		{
			return FORMATTER_YEAR.format(date);
		}
		return "";
	}
	
	public static String formatDateMonth(Date date)
	{
		if (date != null)
		{
			return FORMATTER_MONTH.format(date);
		}
		return "";
	}
	
	public static String formatDateDay(Date date)
	{
		if (date != null)
		{
			return FORMATTER_DAY.format(date);
		}
		return "";
	}
	
	public static String formatDateYearMonth(Date date)
	{
		if (date != null)
		{
			return FORMATTER_YEAR_MONTH.format(date);
		}
		return "";
	}
	
	public static String formatDateYearMonthSerial(Date date)
	{
		if (date != null)
		{
			return FORMATTER_YEAR_MONTH_SERIAL.format(date);
		}
		return "";
	}
	
	public static String formatGMTShort()
	{
	    Calendar calendar = Calendar.getInstance(new SimpleTimeZone(0, "GMT"));
	    FORMATTER_SHORT_GMT.setCalendar(calendar);
		return FORMATTER_SHORT_GMT.format(new Date());
	}
	
	public static String formatGMTShort(Date date)
	{
	    Calendar calendar = Calendar.getInstance(new SimpleTimeZone(0, "GMT"));
	    FORMATTER_SHORT_GMT.setCalendar(calendar);
		return FORMATTER_SHORT_GMT.format(date);
	}
	
	public static String formatTime(long seconds)
	{
	    String result = "00:00";  
	    if (seconds > 0)  
	    {
	    	long minute = seconds / 60;  
	        if (minute < 60)
	        {  
	        	long second = seconds % 60;  
	            result = formatterTime(minute) + ":" + formatterTime(second);  
	        }
	        else
	        {  
	        	long hour = minute / 60;  
	            if (hour <= 99)
	            {  
		            minute = minute % 60;  
		            long second = seconds - hour * 3600 - minute * 60;  
		            result = formatterTime(hour) + ":" + formatterTime(minute) + ":" + formatterTime(second);  
	            }
	            else
	            {
	            	result = "99:59:59";
	            }
	        }  
	    }  
	    return result;  
	}
	
	private static String formatterTime(long time)
	{  
		String result = null;  
	    if ((time >= 0) && (time < 10))
	    {
	    	result = "0" + Long.toString(time);
	    }
	    else
	    {
	    	result = time + "";
	    }
	    return result;
	}
	
	public static boolean largeThan(Date date)
	{
		return date.compareTo(new Date()) > 0;
	}

	public static boolean largeThan(Date date1, Date date2)
	{
		return date1.compareTo(date2) > 0;
	}
	
	public static boolean largeEqual(Date date)
	{
		return date.compareTo(new Date()) >= 0;
	}

	public static boolean largeEqual(Date date1, Date date2)
	{
		return date1.compareTo(date2) >= 0;
	}
	
	public static boolean lessThan(Date date)
	{
		return date.compareTo(new Date()) < 0;
	}
	
	public static boolean lessThan(Date date1, Date date2)
	{
		return date1.compareTo(date2) < 0;
	}

	public static boolean lessEqual(Date date)
	{
		return date.compareTo(new Date()) <= 0;
	}
	
	public static boolean lessEqual(Date date1, Date date2)
	{
		return date1.compareTo(date2) <= 0;
	}
	
	public static Date getCurrentDate()
	{
		return new Date();
	}
	
	public static Date getBeginDateByDay() 
	{
	    return getBeginDateByDay(new Date());
	}
	
	public static Date getBeginDateByDay(Date date) 
	{
		if (date != null)
		{
			String _date = formatDateShort(date);
			String beginDate = _date.substring(0, 10) + " 00:00:00";
			return parseDate(beginDate);
		}
		return null;
	}
	
	public static Date getBeginDateByWeek() 
	{
		Calendar calendar = Calendar.getInstance();    
		int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 2;
		calendar.add(Calendar.DATE, - dayOfWeek);
		
		return getBeginDateByDay(calendar.getTime());
	}
	
	public static Date getBeginDateByMonth() 
	{
		return getBeginDateByMonth(null, 0);
	}
	
	public static Date getBeginDateByMonth(Date date)
	{
		return getBeginDateByMonth(date, 0);
	}
	
	public static Date getBeginDateByMonth(int count)
	{
		return getBeginDateByMonth(null, count);
	}
	
	public static Date getBeginDateByMonth(Date date, int count) 
	{
		Calendar calendar = Calendar.getInstance();
		if (date != null)
		{
			calendar.setTime(date);
		}
		calendar.add(Calendar.MONTH, count);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		
		return getBeginDateByDay(calendar.getTime());
	}
	
	public static Date getEndDateByDay() 
	{
		return getEndDateByDay(new Date());
	}
	
	public static Date getEndDateByDay(Date date) 
	{
		if (date != null)
		{
			String _date = formatDateShort(date);
			String endDate = _date.substring(0, 10) + " 23:59:59";
			return parseDate(endDate);
		}
		return null;
	}
	
	public static Date getEndDateByWeek() 
	{
		Calendar calendar = Calendar.getInstance();    
		int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 2;
		calendar.add(Calendar.DATE, -dayOfWeek);
		calendar.add(Calendar.DATE, 6);
		
		return getEndDateByDay(calendar.getTime());
	}
	
	public static Date getEndDateByMonth() 
	{
		return getEndDateByMonth(null, 0);
	}
	
	public static Date getEndDateByMonth(Date date) 
	{
		return getEndDateByMonth(date, 0);
	}
	
	public static Date getEndDateByMonth(int count) 
	{
		return getEndDateByMonth(null, count);
	}
	
	public static Date getEndDateByMonth(Date date, int count) 
	{
		Calendar calendar = Calendar.getInstance();
		if (date != null)
		{
			calendar.setTime(date);
		}
		calendar.add(Calendar.MONTH, count);
		calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
		
		return getEndDateByDay(calendar.getTime());
	}
	
	public static Date getDateByDay(Date date, int count)
	{
	    Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.DAY_OF_MONTH, count);
		return calendar.getTime();
	}
	
	public static Date getDateByWeek(Date date, int count)
	{
	    Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.WEEK_OF_YEAR, count);
		return calendar.getTime();
	}
	
	public static Date getDateByMonth(Date date, int count)
	{
	    Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.MONTH, count);
		return calendar.getTime();
	}
	
	public static Date getDateByYear(Date date, int count)
	{
	    Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.YEAR, count);
		return calendar.getTime();
	}
	
	public static long getTimeInMillis(String str) 
	{
		return getTimeInMillis(parseDate(str));
	}
	
	public static long getTimeInMillis(Date date)
	{
		if (date != null)
		{
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			return calendar.getTimeInMillis();
		}
		return 0;
	}
	
	public static long getTimestamp()
	{
		return System.currentTimeMillis() / 1000;
	}

	public static long getIntervalTime(Date beginDate, Date endDate)
	{
		return getIntervalTime(beginDate, endDate, DATE_TYPE_MILLISECOND);
	}
	
	public static long getIntervalTime(Date beginDate, short dateType)
	{
		return getIntervalTime(beginDate, new Date(), dateType);
	}

	public static long getIntervalTime(Date beginDate, Date endDate, short dateType)
	{
		long times = endDate.getTime() - beginDate.getTime();
		if (dateType == DATE_TYPE_SECOND)
		{
			return times / 1000;
		} 
		if (dateType == DATE_TYPE_MINUTE)
		{
			return times / 1000 / 60;
		} 
		else if (dateType == DATE_TYPE_HOUR)
		{
			return times / 1000 / 60 / 60;
		} 
		else if (dateType == DATE_TYPE_DAY) 
		{
			return times / 1000 / 60 / 60 / 24;
		}
		else 
		{
			return times;
		}
	}
	
	public static List<Date> getIntervalDates(Date beginDate, Date endDate) 
	{
		List<Date> dates = new ArrayList<Date>();
		Calendar startCalendar = Calendar.getInstance();
		startCalendar.setTime(beginDate);
		
		Calendar endCalendar = Calendar.getInstance();
		endCalendar.setTime(endDate);
		
        while (startCalendar.before(endCalendar) || startCalendar.equals(endCalendar)) 
        {
        	dates.add(startCalendar.getTime());
        	startCalendar.add(Calendar.DAY_OF_YEAR, 1);
        }
        return dates;
    }
	
	public static String getWeekDay(Date date) 
	{      
	    Calendar calendar = Calendar.getInstance();
	    calendar.setTime(date);      
	    int index = calendar.get(Calendar.DAY_OF_WEEK) - 1;      
	    if (index < 0)
	    {        
	    	index = 0;      
	    }      
	    return WEEK_DAYS[index];    
	}
	
	public static long getMonthDayCount(Date date) 
	{
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);  
	
		return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
	}

	public static String parseDiff(Date begin, Date end)
	{
		long diff = end.getTime() - begin.getTime();//这样得到的差值是毫秒级别
		long days = diff / (1000 * 60 * 60 * 24);

		long hours = (diff-days*(1000 * 60 * 60 * 24))/(1000* 60 * 60);
		long minutes = (diff-days*(1000 * 60 * 60 * 24)-hours*(1000* 60 * 60))/(1000* 60);
		long seconds = (diff-days*(1000 * 60 * 60 * 24)-hours*(1000* 60 * 60)-minutes*(1000*60))/1000;

		return days+"天"+hours+"小时"+minutes+"分"+seconds+"秒";
	}

	/**
	 * 将格式为 yyyy-MM-dd HH:mm:ss的字符串转换成DateTimeInterface类型
	 *
	 * @param dateStr
	 * @return
	 */
	public static DateTimeInterface coverDateTimeFromString(String dateStr) {
		DateGlobalizationServiceInterface dateService = GlobalizationService.getUserService(KnownGlobalizationServices.DATE);
		DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		try {
			Date date = sdf.parse(dateStr);
			Calendar ca = Calendar.getInstance();
			ca.setTime(date);
			return dateService.createDateTime(ca.get(Calendar.YEAR), ca.get(Calendar.MONTH), ca.get(Calendar.DATE), ca.get(Calendar.HOUR_OF_DAY), ca.get(Calendar.MINUTE), ca.get(Calendar.SECOND));
		} catch (ParseException e) {
			SimpleLogger.log(Severity.ERROR, Category.SYS_SERVER, Location.getLocation("SystemOper"), "coverDateTimeFromString", e.toString());
			return null;
		}
	}

	/**
	 *
	 * @return 时间的秒数 HH：mm
	 */
	public static long getTimeToSecond(){
		Date now=new Date();
		int min=now.getMinutes();
		int h=now.getHours();
		return (h*60+min)*60;
	}
	/**
	 * @return Date
	 */
	public static Date convertDateTimeToDate(DateTimeInterface dateTimeInterface, String format) {
		if (format == null || "".equals(format)) {
			format = "yyyy-MM-dd HH:mm:ss";
		}
		long timeMillis = dateTimeInterface.getTimeInMillis();
		Date date = new Date(timeMillis);
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
		String dateStr = simpleDateFormat.format(date);
		try {
			return simpleDateFormat.parse(dateStr);
		} catch (ParseException e) {
			SimpleLogger.log(Severity.ERROR, Category.SYS_SERVER, Location.getLocation("SystemOper"), "convertDateTimeToDate", e.toString());
			return null;
		}
	}

	/**
	 * 获得当前时间的字符串序列
	 *
	 * @return 201812511183786
	 */
	public final static String getTimeString() {
		Calendar calendar = new GregorianCalendar();
		int year = calendar.get(Calendar.YEAR);
		int month = calendar.get(Calendar.MONTH) + 1;
		int day = calendar.get(Calendar.DAY_OF_MONTH);
		int hour = calendar.get(Calendar.HOUR_OF_DAY);
		int minute = calendar.get(Calendar.MINUTE);
		int second = calendar.get(Calendar.SECOND);
		int msec = calendar.get(Calendar.MILLISECOND);

		return String.valueOf(year) + String.valueOf(month) + String.valueOf(day) + String.valueOf(hour) + String.valueOf(minute) + String.valueOf(second) + String.valueOf(msec);
	}
}