package utis.wall.common.util;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Desc     : 보안처리에 적용할 함수 제공
 */
public class SecurityUtil {
	
	
	//log4j class
	private static Logger logger = LoggerFactory.getLogger(SecurityUtil.class);
	
	private static Pattern[] patterns = new Pattern[]{       
		Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),
		Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),  
		Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), 
		Pattern.compile("</script>", Pattern.CASE_INSENSITIVE),
		Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),   
		Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), 
		Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), 
		Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE),  
		Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE),
		Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL) 
	}; 
	
	
	/**
	 *	<PRE>
	 * xss 방어 
	 *	</PRE>
	 **/ 
	public static String xssFilter(String input) throws Exception {
		
	    String output = CommonUtil.parseString(input , "");
		try {
			output = output.replaceAll("<", "&lt;");
			output = output.replaceAll(">", "&gt;");
		//	output = output.replaceAll("\\(", "&#40;");
		//	output = output.replaceAll("\\)", "&#41;");
			output = output.replaceAll("\"", "&quot;");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return output;
	}
	
	
	/**
    * <pre>
    *  HttpServletRequest 혹은 @ReqeustBody 의 객체의 필수값 체크
    *  R : 필수값
    *  N : 필수값 & 더블형 
    *  @author 김응기 , 조지현
    *  @return [0] : true/false String , [1] bad parameter(or body) name 
    * </pre> 
    * */
	@SuppressWarnings("rawtypes")
	public static String[] paramsChk(Map<String,Object> params, Map<String,Object> paramsReqs) throws Exception {
	
		if(paramsReqs.isEmpty()) 	return new String[]{"true",""};
		
		Object key = null;
		Iterator iterator = paramsReqs.keySet().iterator();
		String result[] = new String[]{"false",""};
		
		while (iterator.hasNext()) {
			key = iterator.next();		   
			logger.debug( String.format("-----------------params.get(\"%s\")" , key ));
			logger.debug( String.format("-----------------=%s" ,  params.get(key).toString() ));
			/*
			logger.debug( params.get(key) instanceof String );
			logger.debug( params.get(key) instanceof List );
			logger.debug( params.get(key) instanceof HashMap );
			*/
			if(paramsReqs != null 
			   && !paramsReqs.isEmpty() 
			   && paramsReqs.containsKey(key)
			   ){
				   //필수 요구 사항일 경우
				   if(paramsReqs.get(key).toString().toUpperCase().contains("R")){
					   
					    if(params.get(key) != null  && params.containsKey(key) ) {
					    	
					    	if ( params.get(key) instanceof String  ) {
					    		if("".equals(CommonUtil.parseString(params.get(key).toString().trim(),""))){
						    		result = new String[]{"false",key.toString()};
						    		break;
						    	}else{
						    		result = new String[]{"true",""};
						    	}
					    	
					    	// 리스트	
					    	} else  if ( params.get(key) instanceof List  ) {
					    		
					    		ArrayList paList = new ArrayList();
					    		paList = (ArrayList) params.get(key);
					    		for ( int i = 0 ; i <  paList.size(); i++) {
					    			if("".equals(CommonUtil.parseString( paList.get(i).toString().trim(),""))){
							    		result = new String[]{"false",key.toString()};
							    		break;
							    	}else{
							    		result = new String[]{"true",""};
							    	}
					    		}
					    		
					    	// JSON 링크맵 	
					    	} else if ( params.get(key) instanceof LinkedHashMap ) {
					    		
					    		LinkedHashMap lhm = new LinkedHashMap();
					    		lhm = (LinkedHashMap) params.get(key);
					    		
					    		Object subKey = null;
					    		Iterator subIterator = lhm.keySet().iterator();
					    		
					    		while (subIterator.hasNext()) {
					    			subKey = subIterator.next();		
					    		
					    			if(lhm != null 
			    					   && !lhm.isEmpty() 
			    					   && lhm.containsKey(subKey)
			    					){
					    				if( lhm.get(subKey) != null  ) {
									    	if ( lhm.get(subKey) instanceof String  ) {
									    		if("".equals(CommonUtil.parseString( lhm.get(subKey).toString().trim(),""))){
										    		result = new String[]{"false",key.toString()};
										    		break;
										    	}else{
										    		//logger.debug( String.format("-----------------lhm.get(\"%s\")" , subKey ));
													//logger.debug( String.format("-----------------=%s" ,  lhm.get(subKey).toString() ));
										    		result = new String[]{"true",""};
										    	}
									    	} else if ( lhm.get(subKey) instanceof List  ) {
									    		
									    		ArrayList paList = new ArrayList();
									    		paList = (ArrayList) lhm.get(subKey);
									    		for ( int i = 0 ; i <  paList.size(); i++) {
									    			if("".equals(CommonUtil.parseString( paList.get(i).toString().trim(),""))){
											    		result = new String[]{"false",key.toString()};
											    		break;
											    	}else{
											    		//logger.debug( String.format("-----------------lhm.get(\"%s\")" , subKey ));
														//logger.debug( String.format("-----------------=%s" ,  lhm.get(subKey).toString() ));
											    		result = new String[]{"true",""};
											    	}
									    		}
									    	}
					    				}
					    				
					    			} else {
					    				result = new String[]{"false",key.toString()};
								    	break;
					    			}
					    		
					    		}
					    	}
					    }else{
					    	result = new String[]{"false",key.toString()};
					    	break;
					    }
				   }
				   
				   //숫자타입 확인
				   if(paramsReqs.get(key).toString().toUpperCase().contains("N")){
					   if(params.get(key) != null && params.containsKey(key)	) {	  
						  
						   if (params.get(key) instanceof String || (params.get(key) instanceof Integer) || (params.get(key) instanceof Double)) {
								if(!isStringDouble(params.get(key).toString())){
						    		result = new String[]{"false",key.toString()};
						    		break;
						    	}else{
						    		result = new String[]{"true",""};;
						    	}	 
							// 리스트	
						   } else  if ( params.get(key) instanceof List  ) {	
						   
					    		ArrayList paList = new ArrayList();
					    		paList = (ArrayList) params.get(key);
					    		for ( int i = 0 ; i <  paList.size(); i++) {
					    			if(!isStringDouble(paList.get(i).toString())){
							    		result = new String[]{"false", key.toString()};
							    		break;
							    	}else{
							    		result = new String[]{"true",""};
							    	}
					    		}
					    		// JSON 링크맵 	
					    	} else if ( params.get(key) instanceof LinkedHashMap ) {
					    		
					    		LinkedHashMap lhm = new LinkedHashMap();
					    		lhm = (LinkedHashMap) params.get(key);
					    		
					    		Object subKey = null;
					    		Iterator subIterator = lhm.keySet().iterator();
					    		
					    		while (subIterator.hasNext()) {
					    			subKey = subIterator.next();		
					    		
					    			if(lhm != null 
			    					   && !lhm.isEmpty() 
			    					   && lhm.containsKey(subKey)
			    					){
					    				if( lhm.get(subKey) != null  ) {
									    	if ( lhm.get(subKey) instanceof String  ) {
									    		if(!isStringDouble(lhm.get(subKey).toString())){
										    		result = new String[]{"false",key.toString()};
										    		break;
										    	}else{
										    		//logger.debug( String.format("-----------------lhm.get(\"%s\")" , subKey ));
													//logger.debug( String.format("-----------------=%s" ,  lhm.get(subKey).toString() ));
										    		result = new String[]{"true",""};
										    	}
									    	} else if ( lhm.get(subKey) instanceof List  ) {
									    		
									    		ArrayList paList = new ArrayList();
									    		paList = (ArrayList) lhm.get(subKey);
									    		for ( int i = 0 ; i <  paList.size(); i++) {
									    			if(!isStringDouble(paList.get(i).toString())){
											    		result = new String[]{"false",key.toString()};
											    		break;
											    	}else{
											    		//logger.debug( String.format("-----------------lhm.get(\"%s\")" , subKey ));
														//logger.debug( String.format("-----------------=%s" ,  lhm.get(subKey).toString() ));
											    		result = new String[]{"true",""};
											    	}
									    		}
									    	}
					    				}
					    				
					    			} else {
					    				result = new String[]{"false",key.toString()};
								    	break;
					    			}
					    		
					    		}
					    	} 
				    	
					    }else{
					    	result = new String[]{"false",key.toString()};
					    	break;
					    }
				   }   
				} 
			}	
	
		return result;
	}
	
		
	/**
	 *   PathVariable 애노테이션으로 넘어온 변수들 중 
	 *   DB 숫자타입이 "" 으로 들어가기 전  client side 로 리턴.
	 * */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static Map stripXSSParams(Map params) throws Exception {
		
		Object key = null;		
		Iterator iterator = params.keySet().iterator();

		while (iterator.hasNext()) {
			key = iterator.next();	
			if(params.get(key) instanceof String){
				params.put(key, stripXSS(params.get(key)) );	
			}
		}
		return params;
	}
	
	
	
	/**
	 * <pre>xss 체크 (널체크 포함)</pre>
	 * */
	private static String stripXSS(Object value) throws Exception{
		
		String v = CommonUtil.parseString(value , "");
        if (!v.equals("")) { 
             v = v.replaceAll("\0", ""); 
            for (Pattern scriptPattern : patterns){ 
                v = scriptPattern.matcher(v).replaceAll(""); 
            } 
           	v = xssFilter(v);
        } 
        return v; 
    } 
	


	
	/**
	 * <pre>[스트링->더블] 타입 변환 체크</pre>
	 * */
   public static boolean isStringDouble(String s) {
	    try {
	        Double.parseDouble(s);
	        return true;
	    } catch (NumberFormatException e) {
	        return false;
	    }
	 }
   
	

}
