
package nlib.user.web;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.fasterxml.jackson.databind.ObjectMapper;

import egovframework.com.ext.oauth.service.OAuthConfig;
import egovframework.com.ext.oauth.service.OAuthLogin;
import egovframework.com.ext.oauth.service.OAuthUniversalUser;
import egovframework.com.ext.oauth.service.OAuthVO;
import nlib.cmm.NlibCommonController;
import nlib.cmm.crypto.AriaCrypto;
import nlib.cmm.service.NlibProperty;
import nlib.cmm.session.SessionConfig;
import nlib.col.service.CartService;
import nlib.user.service.LoginService;
import nlib.user.service.NlibLoginVO;
import nlib.util.StringUtil;

/**
 * <pre>
 * &#64;Class Name : LoginController.java
 * 
 * &#64;Description : 스프링 시큐리티를 이용한 로그인 처리 컨트롤러 
 * 
 * 
 * &#64;프로젝트명: 지방문화원 통합자료관리시스템 구축사업 (2021)
 *
 * </pre>
 *
 * @ ------------ -------- --------------------------- 
 * @ 수정일                수정자        수정내용 
 * @ ------------ -------- --------------------------- 
 * @ 2021. 7. 9.  KNKIM    최초 생성
 * @ 2021. 8.18.  KNKIM    RESTful -> DB접속 방식으로 변경 처리 
 * @ 2021. 8.19.  KNKIM    지방문화원별 다른 도메인 호스트 접속 처리를 위한 Spring Security 변경 작업, 네이버 전자정보 프레임워크 기반으로 변경  
 * @ 2021. 8.24.  KNKIM    테이블 변경에 따른 항목명 변경 및 코드 정리작업  
 *  
 * 
 * @author 이씨플라자 * DIGITALSHIP KNKIM
 * @since 2021. 7. 9.
 * @version 1.0
 *
 */
@Controller
public class LoginController extends NlibCommonController {
	
	private static final Logger log = LoggerFactory.getLogger(LoginController.class);
	
	//-------------------------------------------
	// SNS 연동 환경설정 정보 : context-oauth.xml 참고 
	//-------------------------------------------
	@Inject
	private OAuthVO naverAuthVO; /* 네이버 */
	
	@Inject
	private OAuthVO googleAuthVO; /* 구글 */

	@Inject
	private OAuthVO kakaoAuthVO; /* 카카오 */
	//-------------------------------------------
	

	@Resource(name = "loginService")
	private LoginService loginService;

    @Resource(name = "cartService")
    private CartService cartService;
    
    
	/**
	 * 접속한 지방문화원정보를 세션에 설정한다. 
	 * 
	 * @param req
	 * @param res
	 * @param returnUrl
	 * @param callType
	 * @throws Exception
	 */
	public void setCouncilInfo(
			HttpServletRequest req, 
			HttpServletResponse res,
			String returnUrl,
			String callType) throws Exception {
		
		HttpSession session = req.getSession();
		String url = req.getRequestURL().toString();
		String councilHomeUrl = url.replaceAll(req.getRequestURI(), "") + req.getContextPath();
		String councilReturnUrl = councilHomeUrl + (StringUtil.isEmpty(returnUrl) ? "/" : returnUrl);
		String councilDnsHost = StringUtil.getHostName(url);
		String councilJsessionId = session.getId();

		// 캐쉬된 요청URL인 존재하는 경우, 리턴URL로 설정 
		RequestCache cache = new HttpSessionRequestCache();
		SavedRequest savedRequest = cache.getRequest(req, res);
		if (savedRequest != null) {
			if(savedRequest.getRedirectUrl().contains("Ajax.do")) {
				cache.removeRequest(req, res);
			} else {
				councilReturnUrl = savedRequest.getRedirectUrl();
			}
			log.debug("setCouncilInfo > HttpSessionRequestCache에서 획득 councilReturnUrl = " + councilReturnUrl);				
		}

		// 지방문화원 코드 확인
		HashMap<String, String> councilInfo = loginService.selectCouncilInfoByDnsHost(councilDnsHost);
		String councilCd = (councilInfo == null ? null : councilInfo.get("councilCd"));
		String councilNm = (councilInfo == null ? null : councilInfo.get("councilNm"));
		
		session.setAttribute("councilReturnUrl", councilReturnUrl);
		session.setAttribute("councilHomeUrl", councilHomeUrl);
		session.setAttribute("councilDnsHost", councilDnsHost);
		session.setAttribute("councilCd", councilCd);
		session.setAttribute("councilNm", councilNm);
		session.setAttribute("callType", callType);
		
		log.debug("setCouncilInfo > REQ URL = " + url);
		log.debug("setCouncilInfo > councilJsessionId = " + councilJsessionId);
		log.debug("setCouncilInfo > councilDnsHost = " + councilDnsHost);
		log.debug("setCouncilInfo > councilReturnUrl = " + councilReturnUrl);
		log.debug("setCouncilInfo > councilHomeUrl = " + councilHomeUrl);
		log.debug("setCouncilInfo > councilCd = " + councilCd);
		log.debug("setCouncilInfo > councilNm = " + councilNm);
		log.debug("setCouncilInfo > callType = " + callType);
		
		// 세션 추가정보 저장소에 회귀 문화원 정보 담기  
		OAuthUniversalUser oauthUser = new OAuthUniversalUser();
		oauthUser.setCouncilJsessionId(councilJsessionId);
		oauthUser.setCouncilHomeUrl(councilHomeUrl);
		SessionConfig.setLoginInfo(councilJsessionId, oauthUser);
		
		return;
	}
	
	/**
	 * 로그인 콜백을 위한 설정을 처리한 후, 로그인 페이지로 전환한다.
	 * 
	 * @param req
	 * @param error
	 * @param logout
	 * @param model
	 * @return
	 */
	@RequestMapping("/login/loginPreSet.do")
	public String loginPreSet(HttpServletRequest req, 
			HttpServletResponse response, 
			@RequestParam(required = false) String error,
			@RequestParam(required = false) String message,
			@RequestParam(required = false) String logout, 
			RedirectAttributes redirectAttrs,
			@RequestParam Map<String, String> paramMap,
			Model model, 
			HttpSession session) {
		
		//response.setHeader("X-Frame-Options", "ALLOW-FROM https://nlib-dev.nculture.org");
		//response.setHeader("X-Frame-Options", "ALLOW-FROM https://seoul.nculture.org/");
		
		//----------------------------------------------
		// 지방문화원 사이트에서 접속한 경우, 지방문화원 정보 확인 
		//----------------------------------------------
		String councilJsessionId = paramMap.get("councilJsessionId");
		String councilDnsHost    = paramMap.get("councilDnsHost");
		String councilReturnUrl  = StringUtil.decodeBase64(paramMap.get("councilReturnUrl"));
		String councilHomeUrl    = StringUtil.decodeBase64(paramMap.get("councilHomeUrl"));
		String councilCd         = paramMap.get("councilCd");
		String councilNm         = StringUtil.decodeBase64(paramMap.get("councilNm"));
		String callType          = paramMap.get("callType");
		
		log.debug("loginPreSet > sessionid=" + session.getId());
		log.debug("loginPreSet > councilJsessionId = " + councilJsessionId);
		log.debug("loginPreSet > councilDnsHost = " + councilDnsHost);
		log.debug("loginPreSet > councilReturnUrl = " + councilReturnUrl);
		log.debug("loginPreSet > councilHomeUrl = " + councilHomeUrl);
		log.debug("loginPreSet > councilCd = " + councilCd);
		log.debug("loginPreSet > councilNm = " + councilNm);
		log.debug("loginPreSet > callType = " + callType);

		session.setAttribute("councilJsessionId", councilJsessionId);
		session.setAttribute("councilReturnUrl", councilReturnUrl);
		session.setAttribute("councilHomeUrl"  , councilHomeUrl);
		
		session.setAttribute("councilDnsHost", councilDnsHost);
		session.setAttribute("councilCd"  , councilCd);
		session.setAttribute("councilNm"  , councilNm);
		session.setAttribute("callType"  , callType);
		
		String redirect = null;
		if(OAuthLogin.CALL_TYPE_MEMBER.equalsIgnoreCase(callType)) {
			redirect = councilHomeUrl + NlibProperty.getString("nculture.member.redirect.uri");
		} else {
			redirect = councilHomeUrl + NlibProperty.getString("nculture.login.redirect.uri");
			redirect = StringUtil.addWebParamOfUrl(redirect, "logout", logout);
		}
		
		return "redirect:" + redirect;
	}
	
	/**
	 * Ajax 요청에 대한 권한 부재시 오류 처리 
	 * 
	 * @param req
	 * @param res
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value= {"/login/responseDeniedAuth.do"})
	public ResponseEntity<String> responseDeniedAuth(HttpServletRequest req, HttpServletResponse res) throws Exception {
		HttpHeaders headers = new HttpHeaders();
	    headers.add(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8");
		String errorStr = "로그인 후, 이용해 주시기 바랍니다.";
		log.debug("responseDeniedAuth > errorStr=" + errorStr);
		return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).headers(headers).body(errorStr);
	}
	
	/**
	 * 로그인 정보 입력 화면을 출력한다.
	 * 
	 * @param req
	 * @param error
	 * @param logout
	 * @param model
	 * @return
	 */
	@RequestMapping(value= {"/login/loginForm.do", "/login/loginFormPopup.do", "/login/memberSnsForm.do"})
	public String loginForm(
			HttpServletRequest req,
			HttpServletResponse res,
			@RequestParam(required = false) String callType,
			@RequestParam(required = false) String returnUrl,
			@RequestParam(required = false) String login, 
			@RequestParam(required = false) String logout,
			@RequestParam(required = false) String error,
			@RequestParam(required = false) String message,
			RedirectAttributes redirectAttrs,
			Model model) throws Exception {
		
		String reqPath = req.getServletPath(); 

		// Ajax 호출이면서 인증 오류에 따른 요청인 경우, Ajax용 RES 생성 함수로 전환 
		if("req".equals(login)) {
			RequestCache cache = new HttpSessionRequestCache();
			SavedRequest savedRequest = cache.getRequest(req, res);
			if (savedRequest != null && savedRequest.getRedirectUrl().contains("Ajax.do")) { 
				cache.removeRequest(req, res);
				return "redirect:/login/responseDeniedAuth.do";
			}
		}
		
		// callType
		if(StringUtil.isEmpty(callType)) {
			if(reqPath.startsWith("/login/member")) callType = OAuthLogin.CALL_TYPE_MEMBER;
			else callType = OAuthLogin.CALL_TYPE_LOGIN;
		}
		
		// 지방문화원 사이트 정보를 세션 및 추가정보에 담는다.  
		setCouncilInfo(req, res, returnUrl, callType);
		HttpSession session = req.getSession();

		//----------------------------------------------
		// 지방문화원 사이트에서 접속한 경우, 지방문화원 정보 확인 
		//----------------------------------------------
		String councilJsessionId = session.getId();
		String councilDnsHost    = (String)session.getAttribute("councilDnsHost");
		String councilReturnUrl  = (String)session.getAttribute("councilReturnUrl");
		String councilHomeUrl    = (String)session.getAttribute("councilHomeUrl");
		String councilCd         = (String)session.getAttribute("councilCd");
		String councilNm         = (String)session.getAttribute("councilNm");
		
		log.debug("loginForm > sessionid=" + session.getId());
		log.debug("loginForm > councilJsessionId = " + councilJsessionId);
		log.debug("loginForm > councilDnsHost = " + councilDnsHost);
		log.debug("loginForm > councilReturnUrl = " + councilReturnUrl);
		log.debug("loginForm > councilHomeUrl = " + councilHomeUrl);
		log.debug("loginForm > councilCd = " + councilCd);
		log.debug("loginForm > councilNm = " + councilNm);

		//----------------------------------------------
		// SNS 연동 URL 생성 
		//----------------------------------------------
		String encCouncilJsessionId =  AriaCrypto.encode(councilJsessionId);
		OAuthLogin naverLogin = new OAuthLogin(naverAuthVO, callType, councilJsessionId);
		log.debug("naverLogin.getOAuthURL() = "+naverLogin.getOAuthURL(encCouncilJsessionId));
		model.addAttribute("naverUrl", naverLogin.getOAuthURL(encCouncilJsessionId));
		
		OAuthLogin googleLogin = new OAuthLogin(googleAuthVO, callType, councilJsessionId);
		log.debug("googleLogin.getOAuthURL() = "+googleLogin.getOAuthURL(encCouncilJsessionId));
		model.addAttribute("googleUrl", googleLogin.getOAuthURL(encCouncilJsessionId));

		OAuthLogin kakaoLogin = new OAuthLogin(kakaoAuthVO, callType, councilJsessionId);
		log.debug("kakaoLogin.getOAuthURL() = "+kakaoLogin.getOAuthURL(encCouncilJsessionId));
		model.addAttribute("kakaoUrl", kakaoLogin.getOAuthURL(encCouncilJsessionId));
		
		model.addAttribute("error", error);
		model.addAttribute("message", message);
		if(StringUtil.equalsIgnoreCase(logout, "logout")) {
			model.addAttribute("message", "로그아웃되었습니다. 감사합니다.");
		}
		
		model.addAttribute("login", login); // "req"인 경우, 로그인 필수 안내 표출 
		
		String retScreen = "nlib/login/loginFormPopup";
		if(OAuthLogin.CALL_TYPE_MEMBER.equalsIgnoreCase(callType)) retScreen = "nlib/login/memberSnsForm";
		else if(reqPath.equalsIgnoreCase("/login/loginForm.do")) retScreen = "nlib/login/loginForm";
		
		return retScreen;
	}
	
	@RequestMapping(value = {"/login/loginMessage.do"})
	public String loginMessage(
			HttpServletRequest req, 
			String message,
			Model model) {
		
		model.addAttribute("message", message);
		return "nlib/login/loginMessage";
	}

	/**
	 * SNS 로그인 후, 콜백으로 호출되며 회원가입된 사용자가 존재하는 지 확인하여 로그인 처리가 진행될 수 있도록 한다.
	 * 정상 회원가입자인 경우, 해당 지방문화원 도메인(호스트)주소로 loginCouncilSSO(..)가 재호출되어 실제 세션 로그인 처리 마무리가 이루어진다.
	 *  
	 * @param req
	 * @param oauthServiceName
	 * @param paramMap
	 * @param model
	 * @param session
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = {"/{callType}/{oauthServiceName}/callback.do"}) // /login/{oauthServiceName}/callback.do, /member/{oauthServiceName}/callback.do
	public String loginOauthCallback(
			HttpServletRequest req, 
			@PathVariable String callType,
			@PathVariable String oauthServiceName,
			@RequestParam(required = false) String code,
			@RequestParam(name = "state" , required = false) String councilJsessionId,
			@RequestParam(required = false) String error,
			Model model, 
			HttpSession session) throws Exception {
		String redirectUrl       = NlibProperty.getString("home.uri"); // "/index.do";
		if(StringUtil.isEmpty(councilJsessionId)) {
			model.addAttribute("message", "잘못된 접근입니다. (접속문화원 세션정보 오류)");
			model.addAttribute("loginBtnYn", "Y");
			model.addAttribute("memberBtnYn", "Y");
			return "nlib/login/loginMessage";
		}
		councilJsessionId = AriaCrypto.decode(councilJsessionId);
		OAuthUniversalUser tmpUser = SessionConfig.getLoginInfo(councilJsessionId);
		if(tmpUser == null || StringUtil.isEmpty(tmpUser.getCouncilHomeUrl())) {
			model.addAttribute("message", "잘못된 접근입니다. (접속문화원 정보 오류)");
			model.addAttribute("loginBtnYn", "Y");
			model.addAttribute("memberBtnYn", "Y");
			return "nlib/login/loginMessage";
		}
		String councilHomeUrl    = tmpUser.getCouncilHomeUrl();
		if(StringUtil.isEmpty(councilHomeUrl)) {
			model.addAttribute("message", "잘못된 접근입니다. (접속문화원 URL 정보 오류)");
			model.addAttribute("loginBtnYn", "Y");
			model.addAttribute("memberBtnYn", "Y");
			return "nlib/login/loginMessage";
		}
		
		if(StringUtil.isNotEmpty(error)) {
			
			// 구글 정보 제공 동의 거절한 경우 
			// https://nlib-dev.nculture.org/member/google/callback.do?error=access_denied
			if(StringUtil.equalsIgnoreCase("access_denied", error)) {
				if(OAuthLogin.CALL_TYPE_LOGIN.equalsIgnoreCase(callType)) {
					// 로그인인 경우
					model.addAttribute("loginBtnYn", "Y");
				} else {
					// 회원가입인 경우 
					model.addAttribute("memberBtnYn", "Y");
				}
				redirectUrl = councilHomeUrl + "/login/loginMessage.do";
				model.addAttribute("url", redirectUrl);
				model.addAttribute("message", StringUtil.encodeUrl("서비스를 이용하시려면 SNS의 정보제공 동의가 필요합니다."));
				return "nlib/login/loginPreSet";
			} 
		}
		
		log.debug("loginOauthCallback > sessionid=" + session.getId());
		
		log.debug("oauthLoginCallback: code = ", code);
		
		// SNS 클라이언트 설정 정보 할당 
		OAuthVO oauthVO = null;
		if (StringUtil.equalsIgnoreCase(OAuthConfig.NAVER_SERVICE_NAME, oauthServiceName))
			oauthVO = naverAuthVO;
		else if (StringUtil.equalsIgnoreCase(OAuthConfig.GOOGLE_SERVICE_NAME, oauthServiceName))
			oauthVO = googleAuthVO;
		else if (StringUtil.equalsIgnoreCase(OAuthConfig.KAKAO_SERVICE_NAME, oauthServiceName))
			oauthVO = kakaoAuthVO;
		else {
			throw new Exception("SNS 연동 콜백정보가 올바르지 않습니다.");
		}
		
		//-----------------------------------------------
		// 1. code를 이용해서 Access Token 받기
		// 2. Access Token을 이용해서 사용자 제공 정보 가져오기
		//-----------------------------------------------
		OAuthLogin oauthLogin = new OAuthLogin(oauthVO, callType);
		OAuthUniversalUser oauthUser = oauthLogin.getUserProfile(code); // 1,2번 동시
		log.debug("oauthLoginCallback > Profile ===>>" + oauthUser.getSnsId() + ", " + oauthUser.getSnsName());
		
		// oAuth를 통한 SNS연동이 실패한 경우 
		if(oauthUser == null || !oauthUser.isValid()) {
			redirectUrl = NlibProperty.getString("member.new.url"); // "/member/insertMemberInfoForm.do"
			model.addAttribute("url", redirectUrl); 
			model.addAttribute("message", StringUtil.encodeUrl("먼저 회원가입하신 후, 이용하여 주시기 바랍니다."));
			return "nlib/login/loginPreSet";
		}
		
		//-----------------------------------------------
		// 해당 처리기로 전환 
		//-----------------------------------------------
		if(OAuthLogin.CALL_TYPE_LOGIN.equalsIgnoreCase(callType)) {
			// 로그인인 경우
			SessionConfig.setLoginInfo(councilJsessionId, oauthUser);
			redirectUrl = councilHomeUrl + NlibProperty.getString("nculture.login.post.login.redirect.uri");
		} else {
			// 회원가입인 경우 
			SessionConfig.setNewMemberInfo(councilJsessionId, oauthUser);
			redirectUrl = councilHomeUrl + NlibProperty.getString("nculture.login.post.member.redirect.uri");
		}
		
		model.addAttribute("url", redirectUrl);
		return "nlib/login/loginPreSet";
	}

	/**
	 * ID, PW를 입력받아 로그인을 처리한다. 
	 * (스프링 시큐리티 로그인 수행)
	 * 
	 * @param request
	 * @param response
	 * @param username
	 * @param password
	 * @param model
	 * @return
	 */
	@RequestMapping("/login/login.do")
	public String login(HttpServletRequest request, HttpServletResponse response,
			@RequestParam(required = false) String username, @RequestParam(required = false) String password,
			ModelMap model) throws Exception {

		String loginResult = loginService.login(request, username, password);
		String redirectUrl = NlibProperty.getString("home.uri");

		// 정상적으로 로그인된 경우
		if (StringUtil.isEmpty(loginResult)) {
			RequestCache cache = new HttpSessionRequestCache();
			SavedRequest savedRequest = cache.getRequest(request, response);
			if (savedRequest != null) { 
				redirectUrl = savedRequest.getRedirectUrl();
			}
			
			// 쿠키 카트(비로그인 상태의 카트정보) 존재하는 경우, 해당 사용자 카트(DB)로 등록한 후, 쿠키 카트 삭제 
			//String mbInfoId = getMbInfoId(request);
			//cartService.mergeCart(mbInfoId, request, response);
		}
		// 로그인 실패 
		else {
			redirectUrl = NlibProperty.getString("login.back.url") + "?error=" + loginResult;
		}

		log.debug("login.do > loginResult = " + loginResult);
		log.debug("login.do > redirectUrl = " + redirectUrl);

		return "redirect:" + redirectUrl;
	}
	
	/**
	 * 정상적인 사용자의 로그인 요청이 검증된 후, 실제 해당 지방문화원 사이트 URL로 호출되는 함수로써 로그인 최종 처리를 진행한다.
	 * 
	 * @param req
	 * @param res
	 * @param session
	 * @param model
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value= {"/login/loginCouncilSSO.do"})
	public String loginCouncilSSO(
			HttpServletRequest request, 
			HttpServletResponse response,
			HttpSession session,
			ModelMap model) throws Exception {
		
		String jsessionId = session.getId();
		String councilCd = (String)session.getAttribute("councilCd");
		String councilReturnUrl = (String)session.getAttribute("councilReturnUrl");
		OAuthUniversalUser oauthUser = SessionConfig.getLoginInfo(jsessionId);
		
		if(oauthUser == null || !oauthUser.isValid()) {
			SessionConfig.removeLoginInfo(jsessionId);
			model.addAttribute("message", "잘못된 접근입니다. 정상적인 방법으로 이용바랍니다.");
			model.addAttribute("loginBtnYn", "Y");
			model.addAttribute("memberBtnYn", "Y");
			return "nlib/login/loginMessage";
		}
		
		//-----------------------------------------------
		// 로그인 처리
		//-----------------------------------------------
		String loginResult = loginService.loginCouncilSSO(request, councilCd, oauthUser);
		
		// 정상 SNS 연동 로그인
		if(loginResult == null) {
			String mbInfoId = getMbInfoId(request);
			cartService.mergeCart(mbInfoId, request, response);
			SessionConfig.removeLoginInfo(jsessionId);
			// 세션에 설정된 redirect 주소 확인
			return "redirect:" + councilReturnUrl;
		}
		
		// 휴면계좌
		if(StringUtil.equalsIgnoreCase(loginResult, loginService.WRN_CODE_DORMANT)) {
			return "redirect:" + NlibProperty.getString("login.dormant.url");
		}
		
		// SNS 로그인은 정상적이나, NLIB 시스템에 등록되지 않은 사용자 : 회원가입으로 전환   
		model.addAttribute("error", loginResult);
		if(StringUtil.equalsIgnoreCase(loginResult, loginService.ERR_CODE_REQ_MEMBERSHIP)) {
			SessionConfig.setNewMemberInfo(jsessionId, oauthUser);
			SessionConfig.removeLoginInfo(jsessionId);
			model.addAttribute("message", "먼저 회원가입하신 후, 이용하여 주시기 바랍니다.");
			model.addAttribute("memberBtnYn", "Y");
			return "nlib/login/loginMessage";
		} else if(StringUtil.equalsIgnoreCase(loginResult, loginService.ERR_CODE_REQ_SNSLOGIN)) {
			SessionConfig.setNewMemberInfo(jsessionId, oauthUser);
			SessionConfig.removeLoginInfo(jsessionId);
			model.addAttribute("message", "먼저 로그인할 SNS를 선택하여 로그인 바랍니다.");
			model.addAttribute("loginBtnYn", "Y");
			return "nlib/login/loginMessage";
		}

		// 잘못된 접근 또는 기타 오류  
		SessionConfig.removeLoginInfo(jsessionId);
		model.addAttribute("message", "로그인에 실패하였습니다. 관리자에게 문의바랍니다 : " + loginResult);
		return "nlib/login/loginMessage";
		
	}
	
	/**
	 * 로그아웃 후의 처리를 담당한다. 스프링 시큐리티에서 로그아웃이 수행된 후, 호출된다.
	 * 
	 * @param req
	 * @return
	 */
	@RequestMapping("/login/logout.do")
	public String logout(HttpServletRequest req, ModelMap model) {
		model.addAttribute("message", "이용해 주셔서 감사드립니다.");
		model.addAttribute("loginBtnYn", "Y");
		model.addAttribute("logout", "logout");
		return "nlib/login/loginMessage";
	}

	/**
	 * 휴면계좌 안내 및 해지 선택 화면을 표출한다. 
	 * 
	 * @param req
	 * @param error
	 * @param message
	 * @param logout
	 * @param redirectAttrs
	 * @param paramMap
	 * @param model
	 * @param session
	 * @return
	 */
	@RequestMapping("/login/activateDormantAccForm.do")
	public String activateDormantAccForm(
			HttpServletRequest req, 
			RedirectAttributes redirectAttrs,
			@RequestParam Map<String, String> paramMap,
			Model model, 
			HttpSession session) {
		
		//----------------------------------------------
		// 지방문화원 사이트에서 접속한 경우, 지방문화원 정보 확인 
		//----------------------------------------------
		String councilJsessionId = (String)session.getAttribute("councilJsessionId");
		String councilDnsHost    = (String)session.getAttribute("councilDnsHost");
		String councilReturnUrl  = (String)session.getAttribute("councilReturnUrl");
		String councilHomeUrl    = (String)session.getAttribute("councilHomeUrl");
		String councilCd         = (String)session.getAttribute("councilCd");
		String councilNm         = (String)session.getAttribute("councilNm");
		
		log.debug("activateDormantAccForm > sessionid=" + session.getId());
		log.debug("activateDormantAccForm > councilJsessionId = " + councilJsessionId);
		log.debug("activateDormantAccForm > councilDnsHost = " + councilDnsHost);
		log.debug("activateDormantAccForm > councilReturnUrl = " + councilReturnUrl);
		log.debug("activateDormantAccForm > councilHomeUrl = " + councilHomeUrl);
		log.debug("activateDormantAccForm > councilCd = " + councilCd);
		log.debug("activateDormantAccForm > councilNm = " + councilNm);

		OAuthUniversalUser oauthUser = SessionConfig.getLoginInfo(session.getId());
		model.addAttribute("oauthUser", oauthUser);
		return "nlib/login/activateDormantAccForm";
	}

	/**
	 * 휴면계좌 안내 및 해지 선택 화면을 표출한다. 
	 * 
	 * @param req
	 * @param error
	 * @param message
	 * @param logout
	 * @param redirectAttrs
	 * @param paramMap
	 * @param model
	 * @param session
	 * @return
	 */
	@RequestMapping("/login/activateDormantAcc.do")
	public String activateDormantAcc(
			HttpServletRequest req, 
			@RequestParam Map<String, String> paramMap,
			Model model, 
			HttpSession session) {
		
		String mbInfoId = StringUtil.getString(paramMap.get("mbInfoId"), "");
		
		//----------------------------------------------
		// 지방문화원 사이트에서 접속한 경우, 지방문화원 정보 확인 
		//----------------------------------------------
		String councilDnsHost    = (String)session.getAttribute("councilDnsHost");
		String councilReturnUrl  = (String)session.getAttribute("councilReturnUrl");
		String councilHomeUrl    = (String)session.getAttribute("councilHomeUrl");
		String councilCd         = (String)session.getAttribute("councilCd");
		String councilNm         = (String)session.getAttribute("councilNm");
		
		log.debug("activateDormantAcc > sessionid=" + session.getId());
		log.debug("activateDormantAcc > councilDnsHost = " + councilDnsHost);
		log.debug("activateDormantAcc > councilReturnUrl = " + councilReturnUrl);
		log.debug("activateDormantAcc > councilHomeUrl = " + councilHomeUrl);
		log.debug("activateDormantAcc > councilCd = " + councilCd);
		log.debug("activateDormantAcc > councilNm = " + councilNm);

		OAuthUniversalUser oauthUser = SessionConfig.getLoginInfo(session.getId());
		NlibLoginVO loginVO = oauthUser.getNlibVO();
		
		if(loginVO == null || !mbInfoId.equals(loginVO.getMbInfoId())) {
			model.addAttribute("code", "TIMEOUT");
			model.addAttribute("message", "잘못된 접근입니다. 장시간 대기로 다시 로그인 하신 후, 이용해 주시기 바랍니다.");
			return "nlib/login/activateDormantAccForm";
		}
		
		int ret = loginService.activateDormantAcc(loginVO);

		if(ret < 1) {
			model.addAttribute("code", "NO_TARGET");
			model.addAttribute("message", "휴면사용자가 아닙니다. \\n다시 로그인하시거나 관리자에게 문의하여 주시기 바랍니다.");
			return "nlib/login/activateDormantAccForm";
		}
		
		model.addAttribute("oauthUser", oauthUser);

		return "nlib/login/activateDormantAcc";
	}
}