package com.emr.util;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.UUID;

/*
* 该类，只能用于随机数，可以实现时间与long类型的转化
* 如果当前系统的时区与服务器同步，则时间与long可以完全与服务器同步，也可相互转化
*
* */
public final class IDHelper {

    public static final long BASE = 2;
    public static final long MIN_YEAR = 2000;
    public static final long MAX_YEAR = 2127;
    public static final long MIN_RANDOM = 0;
    public static final long MAX_RANDOM = 1048575;

    private static final long UP_YEAR = 62;            // bits: 7    max: 127
    private static final long DN_YEAR = 56;
    private static final long UP_MONTH = 55;           // bits: 4    max: 15
    private static final long DN_MONTH = 52;
    private static final long UP_DAY = 51;             // bits: 5    max: 31
    private static final long DN_DAY = 47;
    private static final long UP_HOUR = 46;            // bits: 5    max: 31
    private static final long DN_HOUR = 42;
    private static final long UP_MINUTE = 41;          // bits: 6    max: 63
    private static final long DN_MINUTE = 36;
    private static final long UP_SECOND = 35;          // bits: 6    max: 63
    private static final long DN_SECOND = 30;
    private static final long UP_MILLI_SECOND = 29;    // bits: 10   max: 1023
    private static final long DN_MILLI_SECOND = 20;
    private static final long UP_RANDOM = 19;          // bits: 20   max: 1048575 FFFFF
    private static final long DN_RANDOM = 0;

    private static long DN_YEAR_POW = (long)Math.pow(BASE, DN_YEAR);
    private static long DN_MONTH_POW = (long)Math.pow(BASE, DN_MONTH);
    private static long DN_DAY_POW = (long)Math.pow(BASE, DN_DAY);
    private static long DN_HOUR_POW = (long)Math.pow(BASE, DN_HOUR);
    private static long DN_MINUTE_POW = (long)Math.pow(BASE, DN_MINUTE);
    private static long DN_SECOND_POW = (long)Math.pow(BASE, DN_SECOND);
    private static long DN_MILLI_SECOND_POW = (long)Math.pow(BASE, DN_MILLI_SECOND);
    private static long DN_RANDOM_POW = (long)Math.pow(BASE, DN_RANDOM);


    public static long GetRandom(long id)
    {
        return id % DN_MILLI_SECOND_POW + MIN_RANDOM;
    }
    public static long MIN_ID() throws Exception
    {
        Calendar c = Calendar.getInstance();
        c.set((int)MIN_YEAR,0,1,0,0,0);

        return NewID(c, MIN_RANDOM);
    }
    public static long MAX_ID() throws Exception
    {
        Calendar c = Calendar.getInstance();
        c.set((int)MAX_YEAR,11,31,23,59,59);

        return NewID(c, MIN_RANDOM);
    }


    public static long NewID(Calendar datetime, long random) throws Exception
    {
        int yy = datetime.get(Calendar.YEAR);
        int mm = datetime.get(Calendar.MONTH)+1;
        int dd = datetime.get(Calendar.DATE);
        int hh =  datetime.get(Calendar.HOUR_OF_DAY);
        int MM =  datetime.get(Calendar.MINUTE);
        int ss =  datetime.get(Calendar.SECOND);
        int mi =  datetime.get(Calendar.MILLISECOND);
        if (yy > MAX_YEAR)
        {
            throw new ExSys("Year(%d) can not be more than %d !", yy, MAX_YEAR);
        }
        if (yy < MIN_YEAR)
        {
            throw new ExSys("Year(%d) can not be less than %d!", yy, MIN_YEAR);
        }
        if (random > MAX_RANDOM)
        {
            throw new ExSys("Random(%d) can not be more than %d!", random, MAX_RANDOM);
        }
        if (random < MIN_RANDOM)
        {
            throw new ExSys("Random(%d) can not be less than %d!", random, MIN_RANDOM);
        }
        long id = 0;

        id += ((long)yy - MIN_YEAR) * DN_YEAR_POW;
        id += ((long)mm) * DN_MONTH_POW;
        id += ((long)dd) * DN_DAY_POW;
        id += ((long)hh) * DN_HOUR_POW;
        id += ((long)MM) * DN_MINUTE_POW;
        id += ((long)ss) * DN_SECOND_POW;
        id += ((long)mi) * DN_MILLI_SECOND_POW;
        id += (random - MIN_RANDOM) * DN_RANDOM_POW;
        return id;
    }



    public static long NewID(Calendar datetime) throws Exception
    {
        UUID id= UUID.randomUUID();
        String strID = id.toString().substring(0,5);
        long random = Long.parseLong(strID, 16);
        return NewID(datetime, random);
    }

    public static long NewID() throws Exception
    {
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        return NewID(c);
    }

    public static Calendar GetDateTimeWithoutMilliseconds(long id) throws Exception
    {
        if (id < MIN_ID() || id > MAX_ID())
        {
            throw new ExSys("Invalid id! \"%d\"", id);
        }
        long YEAR = id / DN_YEAR_POW + MIN_YEAR;
        long MONTH = (id % DN_YEAR_POW) / DN_MONTH_POW;
        long DAY = (id % DN_MONTH_POW) / DN_DAY_POW;
        long HOUR = (id % DN_DAY_POW) / DN_HOUR_POW;
        long MINUTE = (id % DN_HOUR_POW) / DN_MINUTE_POW;
        long SECOND = (id % DN_MINUTE_POW) / DN_SECOND_POW;


        Calendar c = Calendar.getInstance();
        c.set((int)YEAR,(int)MONTH-1,(int)DAY,(int)HOUR,(int)MINUTE,(int)SECOND);
        return c;
    }


    public static boolean ParseID(String strID)
    {
        try
        {
            long id = Long.parseLong(strID, 10);
            return ParseID(id);
        }
        catch (Exception ex)
        {
            return false;
        }
    }
    public static boolean ParseID(long id)
    {
        try
        {
            Calendar c = GetDateTimeWithoutMilliseconds(id);
            int yy = c.get(Calendar.YEAR);
            int mm = c.get(Calendar.MONTH)+1;
            int dd = c.get(Calendar.DATE);

            if(yy<MIN_YEAR )
            {
                return false;
            }
            if(yy>MAX_YEAR)
            {
                return false;
            }
            if(mm<1 || mm>12)
            {
                return false;
            }
            if(dd<1 || dd> 31)
            {
                return false;
            }

            String dt = GetDateTime_yyyy_MM_dd_HH_mm_ss_sss(id);
            if(common.isEmpty(dt))
            {
                return false;
            }
            return true;
        }
        catch(Exception ex)
        {
            return false;
        }
    }


    public static String GetDateTimeWithoutMilliseconds(long id, String format) throws Exception
    {
        Calendar c =GetDateTimeWithoutMilliseconds(id);
        return ConvertToStringFromDateTime(c, format);
    }

    public static String ConvertToStringFromDateTime(Calendar c, String format) throws Exception
    {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        sdf.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
        String str = sdf.format(c.getTime());
        return str;
    }
    public static String ConvertToStringFromDateTime(Date c, String format) throws Exception
    {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        sdf.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
        String str = sdf.format(c.getTime());
        return str;
    }

    public static String GetDateTime_yyyy_MM_dd_HH_mm_ss_sss(long id) throws Exception
    {
        return GetDateTimeWithoutMilliseconds(id, "yyyy-MM-dd HH:mm:ss:SSS");
    }

    public static String DefaultDateTime1 = "1900-01-01 00:00:00";
    public static String DefaultDateTime2 = "2099-12-31 23:59:59";
    public static String EmptyDateTime = "1801-02-03 00:00:00";

    public static boolean IsEmptyDateTime(Calendar c) throws Exception
    {
        String str = GetDatetime_Min(c);
        return str.equals(EmptyDateTime);
    }
    public static boolean IsEmptyDateTime(String c) throws Exception
    {
        return c.equals(EmptyDateTime);
    }
    public static boolean IsEmptyDateTime(Date date) throws Exception
    {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return IsEmptyDateTime(c);
    }


    public static String GetDatetime_Max(Calendar dt) throws Exception
    {
        return  ConvertToStringFromDateTime(dt,"yyyy-MM-dd") +  " 23:59:59.995";
    }
    public static String GetDatetime_Min(Calendar dt) throws Exception
    {
        return  ConvertToStringFromDateTime(dt,"yyyy-MM-dd") + " 00:00:00.002";
    }
    public static String GetNow_Max() throws Exception
    {
        Calendar c= Calendar.getInstance();
        c.setTime(c.getTime());
        return  GetDatetime_Max(c);
    }
    public static String GetNow_Min() throws Exception
    {
        Calendar c= Calendar.getInstance();
        c.setTime(c.getTime());
        return  GetDatetime_Min(c);
    }

    public static Calendar dt_GetDatetime_Max(Calendar dt) throws Exception
    {

        int yy = dt.get(Calendar.YEAR);
        int mm = dt.get(Calendar.MONTH)+1;
        int dd = dt.get(Calendar.DATE);
//        int hh =  datetime.get(Calendar.HOUR_OF_DAY);
//        int MM =  datetime.get(Calendar.MINUTE);
//        int ss =  datetime.get(Calendar.SECOND);
//        int mi =  datetime.get(Calendar.MILLISECOND);
        Calendar c = Calendar.getInstance();
        c.set(yy,mm,dd, 23,59,59);
        return c;
    }
    public static Calendar dt_GetDatetime_Min(Calendar dt) throws Exception
    {
        int yy = dt.get(Calendar.YEAR);
        int mm = dt.get(Calendar.MONTH)+1;
        int dd = dt.get(Calendar.DATE);
//        int hh =  datetime.get(Calendar.HOUR_OF_DAY);
//        int MM =  datetime.get(Calendar.MINUTE);
//        int ss =  datetime.get(Calendar.SECOND);
//        int mi =  datetime.get(Calendar.MILLISECOND);
        Calendar c = Calendar.getInstance();
        c.set(yy,mm,dd, 0,0,0);
        return c;
    }
    public static Calendar dt_GetNow_Max() throws Exception
    {
        Calendar c= Calendar.getInstance();
        c.setTime(c.getTime());
        return dt_GetDatetime_Max(c);
    }
    public static Calendar dt_GetNow_Min() throws Exception
    {
        Calendar c= Calendar.getInstance();
        c.setTime(c.getTime());
        return dt_GetDatetime_Min(c);
    }


}
