package kr.co.uplus.ez.common.utils;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

public class CommonUtils {
	/*============================ 문자열관련 Util ============================*/
    /**
     * 문자열이 null일 경우 기본값으로 반환하는 메소드
     *
     * @param String string : 검사할 문자열
     * @param String defaultValue : 기본값
     * @return String : 반환값
     * @throws Exception : 반환 중 예외 발생시
     */
    public static String nvl(String string, String defaultValue) throws Exception{
        return getString(string, defaultValue);
    }

    /**
     * 문자열이 널일경우 ""으로 반환하는 메소드
     *
     * @param String string : 검사할 문자열
     * @return String : 결과값
     */
    public static String nvl(String string){
        return getString(string);
    }

    /**
     * Object를 받아 문자열 값으로 리턴함.
     * @param obj
     * @return
     */
    public static String getString(Object obj) {
        return getString(obj,"");
    }

    /**
     * Object를 받아 문자열 값으로 리턴함, 없을경우 DefaultValue 리턴.
     * @param obj
     * @param defaultValue
     * @return
     */
    public static String getString(Object obj, String defaultValue) {
        String value = "" + obj;
        try {
            if(obj == null) {
                value = defaultValue;
            } else {
                if(value.equals("null") || value.length() == 0) {
                    value = defaultValue;
                }
            }
        } catch(Exception e){
            value = defaultValue;
        }
        return value;
    }

    /**
     * 기능 : 에러대신 Zero String을 리턴하는 substring 함수    <BR>
     *        (예) getSubstring("1234",4,2) --> ""   <BR>
     * @param    String   str      string source
     * @param    int      start    substring 시작위치
     * @param    int      length   substring 길이
     * @return   String
     */
    public static String getSubstring(String str, int start, int len){
        String result = null;
        int    slen   = 0;

        try{
            str  = nvl(str);
            slen = str.length();

            if((slen < 1) || (start < 0) || (len < 1)){
                throw new Exception();
            }

            if((slen - 1) < start){
                throw new Exception();
            }

            if(slen >= (start + len)){
                slen = start+len;
            }

            result = str.substring(start, slen);
        }
        catch(Exception e){
            result = "";
        }

        return result;
    }

    /**
     * 숫자나 문자열ㅇ르 Int형 문자로 변환
     * @param object
     * @return
     */
    public static String getIntString(Object object) {
        String returnString = "";
        if(object==null) return returnString;
        returnString = String.valueOf(object);
        if("".equals(returnString)) return returnString;
        try {
            Double doubleValue = Double.valueOf(returnString);
            DecimalFormat df = new DecimalFormat( "#,###" );
            return df.format(doubleValue);
        } catch(Exception e) {
            returnString = String.valueOf(object);
        }
        return returnString;
    }
    
    /**
     * 숫자나 문자열ㅇ르 Int형 문자로 변환
     * @param object
     * @return
     */
    public static String getIntString(Object object, String str) {
        String returnString = "";
        if(object==null) return str;
        returnString = String.valueOf(object);
        if(returnString == "") return returnString;
        try {
            Double doubleValue = Double.valueOf(returnString);
            DecimalFormat df = new DecimalFormat( "#,###" );
            return df.format(doubleValue);
        } catch(Exception e) {
            returnString = String.valueOf(object);
        }
        return returnString;
    }

    /**
     * 숫자나 문자열ㅇ르 Int형 문자로 변환 (소숫점 2자리)
     * @param object
     * @return
     */
    public static String getDoubleString(Object object) {
        String returnString = "";
        if(object==null) return returnString;
        returnString = String.valueOf(object);
        if(returnString == "") return returnString;
        try {
            Double doubleValue = Double.valueOf(returnString);
            DecimalFormat df = new DecimalFormat( "#,###.##" );
            return df.format(doubleValue);
        } catch(Exception e) {
            returnString = String.valueOf(object);
        }
        return returnString;
    }

    /**
     * 숫자나 문자열ㅇ르 Int형 문자로 변환 (소숫점 2자리)
     * @param object
     * @return
     */
    public static String getDoubleString(Object object, String str) {
        String returnString = "";
        if(object==null) return str;
        returnString = String.valueOf(object);
        if(returnString == "") return returnString;
        try {
            Double doubleValue = Double.valueOf(returnString);
            DecimalFormat df = new DecimalFormat( "#,###.##" );
            return df.format(doubleValue);
        } catch(Exception e) {
//
            returnString = String.valueOf(object);
        }
        return returnString;
    }


    /**
     * String UnEscape 처리
     *
     * @param src
     * @return
     */
    public static String unescape(String src) {
        StringBuffer tmp = new StringBuffer();
        tmp.ensureCapacity(src.length());
        int lastPos = 0, pos = 0;
        char ch;
        while (lastPos < src.length()) {
            pos = src.indexOf("%", lastPos);
            if (pos == lastPos) {
                if (src.charAt(pos + 1) == 'u') {
                    ch = (char) Integer.parseInt(src
                            .substring(pos + 2, pos + 6), 16);
                    tmp.append(ch);
                    lastPos = pos + 6;
                } else {
                    ch = (char) Integer.parseInt(src
                            .substring(pos + 1, pos + 3), 16);
                    tmp.append(ch);
                    lastPos = pos + 3;
                }
            } else {
                if (pos == -1) {
                    tmp.append(src.substring(lastPos));
                    lastPos = src.length();
                } else {
                    tmp.append(src.substring(lastPos, pos));
                    lastPos = pos;
                }
            }
        }
        return tmp.toString();
    }

    /**
     * Object -> int
     */
    public static int getInt (Object quan) throws Exception{
        String  strValue = getString(quan);
        int     value = 0;
        try{
            value = Integer.valueOf(strValue);
        }catch(Exception e){
        }
        return value;
    }
    /*============================ 문자열관련 Util 끝 ============================*/

    /**
     * 공통ID 생성(템플릿ID, 프로젝트ID, 사용자ID 등등)
     *
     * @return
     */
    public static String getCommonId(String prefix, int len) {
    	// 공통 ID 접미사
        String suffix = randomGeneration(len);

        // 공통 ID
        String commonId = prefix + suffix;

        return commonId;
    }

    /**
     * 난수 생성(매개변수로 난수길이 세팅)
     *
     * @param len
     * @return
     */
    public static String randomGeneration(int len) {
        String randomStr = RandomStringUtils.randomAlphanumeric(len);
        return randomStr;
    }

    /**
     * 빈 object인지 확인
     * @param obj
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static Boolean isEmptyObject(Object obj) {
        if (obj instanceof String) return obj == null || "".equals(obj.toString().trim());
        else if (obj instanceof List) return obj == null || ((List) obj).isEmpty();
        else if (obj instanceof Map) return obj == null || ((Map) obj).isEmpty();
        else if (obj instanceof Object[]) return obj == null || Array.getLength(obj) == 0;
        else return obj == null;
    }

    /**
     * 비어있지 않은 object인지 확인
     * @param obj
     * @return
     */
    public static Boolean isNotEmptyObject(Object obj) {
        return !isEmptyObject(obj);
    }

    /**
     * map에 key값에 매핑되는 value가 있는지 확인(빈값 true)
     * @param tMap
     * @param key
     * @return
     */
    public static Boolean isEmptyValue(Map<String, Object> tMap, String key) {
        if(!tMap.containsKey(key) || isEmptyObject(tMap.get(key))) return true;
        else return false;
    }

    /**
     * map에 key값에 매핑되는 value가 없으면 빈값 있으면 해당값을 String으로 return
     * @param tMap
     * @param key
     * @return
     */
    public static String getStrValue(Map<String, Object> tMap, String key) {
        if(isEmptyValue(tMap, key)) return StringUtils.EMPTY;
        else return getString(tMap.get(key));
    }

    /**
     * 시분초 + 쓰는곳 해서 ID 만들어주는것
     * @param targetStr - 3글자 이상 하면 varchar(18) 이상 됨
     * @return
     */
    public static String generationSringToHex(String targetStr) {

        String now = new SimpleDateFormat("HHmmss").format(System.currentTimeMillis()) + targetStr;
        String result = "";
        for (int i = 0; i < now.length(); i++) {
            result += String.format("%02X", (int) now.charAt(i));
        }
        return result;
    }
    
    /**
     * 로그인 아이디 마스킹 처리
     */
    public static String setMaskingLoginId(String loginId){
        String  maskingLoginId  = loginId;
        int     length          = maskingLoginId.length();
        length                  = length-2;
        maskingLoginId          = maskingLoginId.replaceAll("(?=.{"+length+"}).", "*"); //���ڸ� 3�� ����ŷ
        return maskingLoginId;
    }
    
    /**
     * 이름 마스킹 처리
     */
    public static String setMaskingUserNm(String userNm){
    	String firstName = "";
    	String midName = "";
    	String lastName = "";
    	if(!isAlpha(userNm) && !isKorean(userNm)) {
    		firstName = userNm;
    	} else {
        	if(!isAlpha(userNm)) {
        		firstName  = userNm.substring(0, 1);
            	midName = userNm.substring(1, 2);
            	lastName = userNm.substring(2, userNm.length());
        	} else {
        		firstName  = userNm.substring(0, 2);
            	midName = userNm.substring(2, userNm.length()-2);
            	lastName = userNm.substring(userNm.length()-2, userNm.length());
        	}
    		
    	}
    	String masking = "";
    	for(int i = 0; i < midName.length(); i++) {
    		masking += "*";
    	}
    	String rtnUserNm = firstName + masking + lastName;
    	return rtnUserNm;
    }
    
    /**
     * 영어이름인지 확인
     */
    public static boolean isAlpha(String userNm){
    	boolean isAlpha = Pattern.matches("^[a-zA-Z]*$", userNm.subSequence(0, 1));
    	return isAlpha;
    }
    
    /**
     * 한글이름인지 확인
     */
    public static boolean isKorean(String userNm){
    	boolean isKorean = Pattern.matches("^[��-�R]*$", userNm.subSequence(0, 1));
    	return isKorean;
    }

    /**
     * convert List to JSONArray
     * @param list
     * @return
     */
    public static JSONArray convertListToJsonArray(List<Map<String, Object>> list) {
        JSONArray jsonArr = new JSONArray();
        for(Map<String, Object> map : list) {
            jsonArr.add(convertMapToJson(map));
        }
        return jsonArr;
    }

    /**
     * convert Map to JSONObject
     * @param map
     * @return
     */
    public static JSONObject convertMapToJson(Map<String, Object> map) {
        JSONObject jsonObj = new JSONObject();
        for(Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            jsonObj.put(key, value);
        }
        return jsonObj;
    }

    /**
     * 세션 생성
     * @param req
     * @param attrib
     * @param ser
     */
    public static void addToSession(HttpServletRequest req, String attrib, Serializable ser) {
        HttpSession sess = req.getSession(true);
        sess.setAttribute(attrib, sess);
    }


    // 핸드폰번호 유효성 체크
    public static boolean isHpNumber(String value) {
        String regExp = "^01(?:0|1|[6-9])[.-]?(\\d{3}|\\d{4})[.-]?(\\d{4})$";
        return value.matches(regExp);
    }
    
    // 중복제거 메소드, key는 제거할 맵 대상
  	public static List<Map<String, Object>> distinctArray(List<Map<String, Object>> target, Object key){ 
  		if(target != null){
  			target = target.stream().filter(distinctByKey(o-> o.get(key))).collect(Collectors.toList());
  		}
  		return target;
  	}

  	// 중복 제거를 위한 함수
  	public static <T> Predicate<T> distinctByKey(Function<? super T,Object> keyExtractor) {
  		Map<Object,Boolean> seen = new ConcurrentHashMap<>();
  		return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
  	}
  	
  	// 검색 조건 날짜 배열에 넣어서 리턴해주는 함수
  	public static String[] dateArrReturn(String startDate, String endDate) throws Exception{
  		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
  		
  		Date strDate = dateFormat.parse(startDate);
		Date edDate = dateFormat.parse(endDate);
		
		long diffSec = (edDate.getTime() - strDate.getTime()) / 1000;
		int diffDays = (int) diffSec / (24 * 60 * 60);
		
		String[] dateArr = new String[diffDays + 1];
		
		for(int i=0; i<=diffDays; i++) {
			Calendar cal = Calendar.getInstance();
			cal.setTime(strDate);
			cal.add(Calendar.DATE, i);
			String dateStr = dateFormat.format(cal.getTime());
			dateArr[i] = dateStr;
		}
  		
  		return dateArr;
  	}

}
