package kcg.faics.sec.service.impl;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import kcg.faics.member.vo.MemberVO;
import kcg.faics.sec.LoginUserVO;
import kcg.faics.sec.role.SecurityRolesVO;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Repository;

import egovframework.rte.fdl.security.securedobject.impl.SelfRegexRequestMatcher;
import egovframework.rte.psl.dataaccess.EgovAbstractMapper;

/** 
 * SecurityMapper.java
 * @author 임새미 
 * @since 2016. 10. 6.
 *
 *  	 수정일                     수정자                                       수정내용
 *  -------------	--------	---------------------------
 *  2016. 10. 6. 	    임새미				       최초생성
 * 
 */
@Repository("securityMapper")
public class SecurityMapper extends EgovAbstractMapper {
	
	/**
	 * 외사경찰 사용자 정보를 가져온다.
	 * 
	 * @param userId 사용자 아이디
	 * @return LoginVO 객체
	 * @throws Exception 기본 예외 처리
	 */
	public LoginUserVO getFaUser(String userId) {
		return selectOne("Security.getFaLoginInfo", userId);
	}
	
	/**
	 * 일반경찰 사용자 정보를 가져온다.
	 * 
	 * @param userId 사용자 아이디
	 * @return LoginVO 객체
	 * @throws Exception 기본 예외 처리
	 */
	public LoginUserVO getCmmnUser(String userId) {
		return selectOne("Security.getCmmnLoginInfo", userId);
	}
	
	/**
	 * 외사경찰 사용자의 ROLE정보를 가져온다.
	 * 
	 * @param userId 사용자 아이디
	 * @return SecurityRolesVO 객체
	 * @throws Exception 기본 예외 처리
	 */
	public SecurityRolesVO getAuthoritiesFaUser(String userId) {
		return selectOne("Security.getAuthoritiesFa", userId);
	}
	
	/**
	 * 일반경찰 사용자의 ROLE정보를 가져온다.
	 * 
	 * @param userId 사용자 아이디
	 * @return SecurityRolesVO 객체
	 */
	public SecurityRolesVO getAuthoritiesCmmnUser(String userId) {
		return selectOne("Security.getAuthoritiesCmmnUser", userId);
	}
	
	/**
	 * ROLE의 계층 리스트를 가져온다.
	 * 
	 * @return CHILD > PARENT로 되어있는 계층정보 문자열
	 */
	public String getHierarchyRoles() {
		List<Map<String, Object>> resultList = selectList("Security.getHierarchyRoles");
		Iterator<Map<String, Object>> itr = resultList.iterator();

    StringBuilder concatedRoles = new StringBuilder();
    Map<String, Object> tempMap;
    while (itr.hasNext()) {
        tempMap = itr.next();
        concatedRoles.append(tempMap.get("child"));
        concatedRoles.append(" > ");
        concatedRoles.append(tempMap.get("parent"));
        concatedRoles.append("\n");
    }
    return concatedRoles.toString();
	}

	/**
	 * ROLE의 계층 리스트를 가져온다.
	 * 
	 * @return URL과 ROLE의 매핑 리스트를 가져온다.
	 */
	public LinkedHashMap<RequestMatcher, List<ConfigAttribute>> getRolesAndUrl() {
		List<Map<String, Object>> resultList = selectList("Security.getRolesAndUrl");
		return patchRequestMatcher(makeLinkedHashMap(resultList));
	}
	
	
	/**
	 * makeLinkedHashMap의 결과 데이터에서 Object key를 RequestMatcher로 캐스팅한다.
	 * egovframework.rte.fdl.security.securedobject.impl.SecuredObjectServiceImpl.getRolesAndUrl() 참조
	 * 
	 * @param data LinkedHashMap으로 변환된 데이터
	 * @return 리턴값 설명
	 */
	private LinkedHashMap<RequestMatcher, List<ConfigAttribute>> patchRequestMatcher(LinkedHashMap<Object, List<ConfigAttribute>> data) {
		LinkedHashMap<RequestMatcher, List<ConfigAttribute>> ret = new LinkedHashMap<RequestMatcher, List<ConfigAttribute>>();
		Set<Object> keys = data.keySet();
		
		for (Object key : keys) {
			ret.put((RequestMatcher) key, data.get(key));
		}
		return ret;
	}
	
	/**
	 * makeLinkedHashMap의 결과 데이터에서 Object key를 RequestMatcher로 캐스팅한다.
	 * egovframework.rte.fdl.security.securedobject.impl.SecuredObjectDAO.getRolesAndResources() 참조
	 * 
	 * @param list LinkedHashMap으로 변환된 데이터
	 * @return 리턴값 설명
	 */
	private LinkedHashMap<Object, List<ConfigAttribute>> makeLinkedHashMap(List<Map<String, Object>> list) {
		/* URL패턴, ant/regx/ciRegex 세가지 형태가 있다. */
		String requestMatcherType = "regex";
		/* Method 단위 Role 지정이나 Pointcut을 사용하는 경우에는  
		 * http://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte:fdl:server_security:authorization의 sqlRolesAndMethod, sqlRolesAndPointcut 쿼리와
		 * SecuredObjectDAO, SecuredObjectServiceImpl을 참조해서 변경한다.
		 * */
		boolean isResourcesUrl = true;

    String resourceType ="url";

		LinkedHashMap<Object, List<ConfigAttribute>> resourcesMap = new LinkedHashMap<Object, List<ConfigAttribute>>();
		Iterator<Map<String, Object>> itr = list.iterator();
        Map<String, Object> tempMap;
        String preResource = null;
        String presentResourceStr;
        Object presentResource;
        while (itr.hasNext()) {
            tempMap = itr.next();

            presentResourceStr = (String) tempMap.get(resourceType);
            
            if (isResourcesUrl) {
            	if (requestMatcherType.equalsIgnoreCase("regex")) {
            		presentResource = new SelfRegexRequestMatcher(presentResourceStr, null);
            	} else if (requestMatcherType.equalsIgnoreCase("ciRegex")) {
            		presentResource = new SelfRegexRequestMatcher(presentResourceStr, null, true);
            	} else {
            		presentResource = new AntPathRequestMatcher(presentResourceStr);
            	}
            } else {
            	presentResource = presentResourceStr;
            }
            List<ConfigAttribute> configList = new LinkedList<ConfigAttribute>();

            if (preResource != null && presentResourceStr.equals(preResource)) {
                List<ConfigAttribute> preAuthList = resourcesMap.get(presentResource);
                Iterator<ConfigAttribute> preAuthItr = preAuthList.iterator();
                while (preAuthItr.hasNext()) {
                    SecurityConfig tempConfig = (SecurityConfig) preAuthItr.next();
                    configList.add(tempConfig);
                }
            }

            configList.add(new SecurityConfig((String) tempMap.get("authority")));

            resourcesMap.put(presentResource, configList);

            preResource = presentResourceStr;
        }
        return resourcesMap;
	}
	
	/**
	 * 로그인 정보를 업데이트한다.
	 * 
	 * @param loginUserVO 로그인 사용자 객체
	 * @return 성공 - 1, 실패 - 0
	 */
	public int updateLoginInfo(LoginUserVO loginUserVO) {
		return (Integer) update("Security.updateLoginInfo", loginUserVO);
	}
	/**
	 * 차단 정보를 업데이트한다.
	 * 
	 * @param memberVO 로그인 사용자 객체
	 * @return 성공 - 1, 실패 - 0
	 */
	public int updateChkInfo(MemberVO memberVO) {
		return (Integer) update("Security.updateChkInfo", memberVO);
	}

	/**
	 * 사용자의 견문 권한을 가져온다.
	 * 
	 * @param userId 사용자 아이디
	 * @return 견문권한 관련 레코드값(ID, CODE)이 담겨진 Map
	 */
	public Map<String, Object> getReportAgentAuCode(String userId) {
		return selectOne("Security.getReportAgentAuCode", userId);
	}
	
	/**
	 * 사용자가 어떤 소속의 차장 or 계장인지에 대한 정보를 가져온다.
	 * 
	 * @param userId 사용자 아이디
	 * @return 부서 권한 관련 레코드값(PLACE1, HEAD, SECTION)이 담겨진 Map
	 */
	public Map<String, Object> getReportAgentApprove(String userId) {
		return selectOne("Security.getReportAgentApprove", userId);
	}
	
}
