package kcg.faics.tg.web;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;

import javax.annotation.Resource;
import javax.validation.Valid;

import kcg.faics.cmmn.bbs.PageType;
import kcg.faics.cmmn.excel.ExcelExporter;
import kcg.faics.cmmn.service.CodeService;
import kcg.faics.cmmn.vo.CodeVO;
import kcg.faics.sec.LoginUserVO;
import kcg.faics.sec.UserUtil;
import kcg.faics.tg.service.CorpService;
import kcg.faics.tg.vo.CorpSearchVO;
import kcg.faics.tg.vo.CorpVO;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.support.SessionStatus;
import org.springmodules.validation.commons.DefaultBeanValidator;

import egovframework.rte.fdl.property.EgovPropertyService;
import egovframework.rte.fdl.security.userdetails.util.EgovUserDetailsHelper;

/**
 * 치안대상 컨트롤러.
 * 
 * @author kimnomin
 *
 */
@Controller
@RequestMapping("/target/corp")
public class CorpController {
	/**
	 * properties값을 가져오는 인터페이스.
	 **/
	@Resource(name = "propertiesService")
	private EgovPropertyService propertiesService;

	/**
	 * message.properties의 값을 가져오는 인터페이스.
	 */
	@Autowired
	private MessageSource messageSource;
	
	/**
	 * Validator - 유효성 검사.
	 **/
	@Resource(name = "beanValidator")
	private DefaultBeanValidator beanValidator;

	/**
	 * 코드관련 정보 인터페이스.
	 */
	@Resource(name = "codeService")
	private CodeService codeService;
	
	/**
	 * 치안대상 비지니스 로직 클래스.
	 */
	@Resource(name = "corpService")
	private CorpService corpService;
	
	/**
	 * grpNo에 따른 항목명을 반환한다.
	 * 
	 * @param grpNo
	 *            화면구분
	 * @param locale
	 *            Locale 객체
	 * @return 항목명
	 */
	private LinkedHashMap<String, String> getFieldName(final String grpNo, final Locale locale) {
		LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
		map.put("place1str", messageSource.getMessage("target.corp.place1", null, locale));
		if ("01".equalsIgnoreCase(grpNo)) {
			map.put("name", messageSource.getMessage("target.corp.name01", null, locale));
			map.put("location", messageSource.getMessage("target.corp.location", null, locale));
		} else if ("02".equalsIgnoreCase(grpNo)) {
			map.put("name", messageSource.getMessage("target.corp.name02", null, locale));
			map.put("location", messageSource.getMessage("target.corp.location", null, locale));
			map.put("ceo", messageSource.getMessage("target.corp.ceo", null, locale));
		} else if ("03".equalsIgnoreCase(grpNo)) {
			map.put("name", messageSource.getMessage("target.corp.name", null, locale));
			map.put("location", messageSource.getMessage("target.corp.location", null, locale));
			map.put("shipCnt", messageSource.getMessage("target.corp.shipcnt", null, locale));
			map.put("ceo", messageSource.getMessage("target.corp.ceo", null, locale));
			map.put("memberCnt", messageSource.getMessage("target.corp.membercnt", null, locale));
			map.put("basicYear", messageSource.getMessage("target.corp.basicyear", null, locale));
			map.put("fund", messageSource.getMessage("target.corp.fund", null, locale));
		} else if ("04".equalsIgnoreCase(grpNo)) {
			map.put("name", messageSource.getMessage("target.corp.name", null, locale));
			map.put("location", messageSource.getMessage("target.corp.location", null, locale));
			map.put("ceo", messageSource.getMessage("target.corp.ceo", null, locale));
			map.put("jobType", messageSource.getMessage("target.corp.jobtype", null, locale));
		} else if ("05".equalsIgnoreCase(grpNo)) {
			map.put("name", messageSource.getMessage("target.corp.name", null, locale));
			map.put("location", messageSource.getMessage("target.corp.location", null, locale));
			map.put("ceo", messageSource.getMessage("target.corp.ceo", null, locale));
			map.put("jobType", messageSource.getMessage("target.corp.jobtype", null, locale));
			map.put("partner", messageSource.getMessage("target.corp.partner", null, locale));
		}
		map.put("tel", messageSource.getMessage("target.corp.tel", null, locale));
		map.put("fax", messageSource.getMessage("target.corp.fax", null, locale));
		map.put("comments", messageSource.getMessage("target.corp.comments", null, locale));
		
		return map;
	}

	/**
	 * Redirect URI를 조합하여 반환한다.
	 * 
	 * @param pageType
	 *            화면구분
	 * @param vo
	 *            치안대상 VO
	 * @return Redirect URI
	 */
	private String makeRedirectUri(final PageType pageType, final CorpVO vo) {
		String uri = "redirect:/target/corp";
		
		switch (pageType) {
		case View:
			uri = String.format("%s/view.do?place1=%s&orgId=%s&orgNo=%s", uri,
					vo.getPlace1(), vo.getOrgId(), vo.getOrgNo());
			break;
		case List:
			uri = String.format("%s/list.do?place1=%s&orgId=%s&grpNo=%s", uri,
					vo.getPlace1(), vo.getOrgId(), vo.getGrpNo());
			break;
		case Stats:
		default:
			uri += "stats.do";
			break;
		}
		
		return uri;
	}
	
	/**
	 * 치안대상 통계화면을 반환한다.
	 * 
	 * @param model
	 *            Model 객체
	 * @return 치안대상 통계화면
	 * @throws Exception
	 *             기본 예외 처리
	 */
	@RequestMapping(value = "/stats.do")
	public String stats(final Model model) throws Exception {
		List<HashMap<String, Object>> stats = corpService.selectStats();
		model.addAttribute("stats", stats);
		
		return "/tg/corpStats.tiles";
	}
	
	/**
	 * 치안대상 통계현황을 엑셀로 반환한다.
	 * 
	 * @param model
	 *            Model 객체
	 * @return 치안대상 통계현황 엑셀
	 * @throws Exception
	 *             기본 예외 처리
	 */
	@RequestMapping(value = "/statstoexcel.do")
	public String statsToExcel(final Model model) throws Exception {
		String title = "치안대상";
		
		// 엑셀 헤더 생성
		LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
		header.put("ORG_NM", "구분");
		header.put("TOT_CNT", "계");
		List<CodeVO> policeStations = codeService.getPlace1List(CodeService.POLICE_STATION_LIST);
		for (CodeVO placeCode : policeStations) {
			header.put(placeCode.getCode2() + "_CNT", placeCode.getCodenmYak());	
		}
		
		// 데이터 생성
		List<HashMap<String, Object>> stats = corpService.selectStats();
		
		// Export
		model.addAttribute("excel", new ExcelExporter<HashMap<String, Object>>(header, stats, title));
		model.addAttribute("filename", title);
		
		return "excelView";
	}

	/**
	 * 치안대상 목록화면을 반환한다.
	 * 
	 * @param model
	 *            Model 객체
	 * @param searchVO
	 *            검색조건 VO
	 * @param locale
	 *            Locale 객체
	 * @return 치안대상 목록화면
	 * @throws Exception
	 *             기본 예외 처리
	 */
	@RequestMapping(value = "/list.do")
	public String list(final Model model,
			@ModelAttribute("searchVO") final CorpSearchVO searchVO,
			final Locale locale) throws Exception {
		LoginUserVO loginUserVO = UserUtil.getMemberInfo();
		model.addAttribute("loginUserVO", loginUserVO);
		
		List<CodeVO> placeList = codeService.getPlace1List(CodeService.POLICE_STATION_LIST, true);
		model.addAttribute("placeList", placeList);
		
		// place1 조건이 할당되지 않은 상태이고 로그인한 사용자의 소속이 검색조건에 적합하면 소속코드 할당
		if (StringUtils.isEmpty(searchVO.getPlace1())) {
			for (CodeVO place: placeList) {
				if (loginUserVO.getPlace1().equalsIgnoreCase(place.getCode2())) {
					searchVO.setPlace1(loginUserVO.getPlace1());
					break;
				}
			}
		}

		if ("03".equalsIgnoreCase(searchVO.getGrpNo())) {
			List<CodeVO> corpOrgList = codeService.getCorpOrgList();
			LinkedHashMap<String, String> corpOrgMap = new LinkedHashMap<String, String>();
			for (CodeVO vo : corpOrgList) {
				String code2 = vo.getCode2();
				String stChar2 = code2.substring(0, 2);
				String edChar2 = code2.substring(code2.length() - 2);
				if ("03".equalsIgnoreCase(edChar2)) {
					corpOrgMap.put(stChar2, vo.getCodenm());
				}
			}
			model.addAttribute("corpOrgList", corpOrgMap);
		}
		
		List<CorpVO> corpList = corpService.selectList(searchVO);
		model.addAttribute("corpList", corpList);
		
		LinkedHashMap<String, String> fieldNameMap = getFieldName(searchVO.getGrpNo(), locale);
		model.addAttribute("fieldNameMap", fieldNameMap);		
		
		return "/tg/corpList.tiles";
	}
	
	/**
	 * 치안대상 목록을 엑셀로 반환한다.
	 * 
	 * @param model
	 *            Model 객체
	 * @param searchVO
	 *            검색조건 VO
	 * @param locale
	 *            Locale 객체
	 * @return 치안대상 목록 엑셀
	 * @throws Exception
	 *             기본 예외 처리
	 */
	@RequestMapping(value = "/listtoexcel.do")
	public String listToExcel(final Model model,
			@ModelAttribute("searchVO") final CorpSearchVO searchVO,
			final Locale locale) throws Exception {
		String grpNo = searchVO.getGrpNo();
		String title = "치안대상";
		
		// 엑셀 헤더 생성
		LinkedHashMap<String, String> header = getFieldName(grpNo, locale);
		
		// 데이터 생성
		List<CorpVO> corpList = corpService.selectList(searchVO);
		
		// Export
		model.addAttribute("excel", new ExcelExporter<CorpVO>(header, corpList, title));
		model.addAttribute("filename", title);
		
		return "excelView";
	}
	
	/**
	 * 치안대상 정보 조회화면을 반환한다.
	 * 
	 * @param model
	 *            Model 객체
	 * @param locale
	 *            Locale 객체            
	 * @param corpVO
	 *            치안대상 VO
	 * @return 치안대상 정보 조회화면
	 * @throws Exception
	 *             기본 예외 처리
	 */
	@RequestMapping(value = "/view.do")
	public String view(final Model model, final Locale locale,
			final CorpVO corpVO) throws Exception {
		LoginUserVO loginUserVO = UserUtil.getMemberInfo();
		model.addAttribute("loginUserVO", loginUserVO);
		
		CorpVO vo = corpService.select(corpVO);
		model.addAttribute("corpVO", vo);

		LinkedHashMap<String, String> fieldNameMap = getFieldName(vo.getGrpNo(), locale);
		model.addAttribute("fieldNameMap", fieldNameMap);
		
		return "/tg/corpView.tiles";
	}
	
	/**
	 * 치안대상 입력화면을 반환한다.
	 * 
	 * @param model
	 *            Model 객체
	 * @param corpVO
	 *            치안대상 VO
	 * @param locale
	 *            Locale 객체
	 * @return 치안대상 입력화면
	 * @throws Exception
	 *             기본 예외 처리
	 */
	@RequestMapping(value = "/add.do")
	public String add(final Model model,
			@ModelAttribute("corpVO") final CorpVO corpVO, final Locale locale) throws Exception {
		// 사용자 인증 검사
		Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
		
		// 등록은 isAdmin이 true인 사용자만 가능하다.
		if (isAuthenticated && UserUtil.isAdmin()) {
			List<CodeVO> placeList = codeService.getPlace1List(CodeService.POLICE_STATION_LIST);
			model.addAttribute("placeList", placeList);
			
			LoginUserVO loginUserVO = UserUtil.getMemberInfo();
			model.addAttribute("loginUserVO", loginUserVO);

			// 로그인한 사용자가 입력가능한 소속이면 해당 소속으로 할당하고, 
			// 그렇지 않으면 기본값인 파라미터의 소속코드를 사용한다.
			for (CodeVO tempVO : placeList) {
				if (tempVO.getCode2().equalsIgnoreCase(loginUserVO.getPlace1())) {
					corpVO.setPlace1(loginUserVO.getPlace1());
					corpVO.setPlace1str(loginUserVO.getPlace1Str());
					break;
				}
			}
			corpVO.setWriter(loginUserVO.getUserid());
			corpVO.setWriterPlace1(loginUserVO.getPlace1());
			
			LinkedHashMap<String, String> fieldNameMap = getFieldName(corpVO.getGrpNo(), locale);
			model.addAttribute("fieldNameMap", fieldNameMap);
			model.addAttribute("registerFlag", "create");
		}
		return "/tg/corpAdd.tiles";
	}
	
	/**
	 * 치안대상 정보를 입력한다.
	 * 
	 * <pre>
	 * php소스에는 파일 업로드 기능이 있으나, 
	 * 파일 관련 필드가 DB에도 없고 표현기능도 없어서 제외함.
	 * </pre>
	 * 
	 * @param corpVO
	 *            치안대상 VO
	 * @param bindingResult
	 *            유효성 검사결과 객체
	 * @param model
	 *            모델 객체
	 * @param status
	 *            SessionStatus 객체
	 * @param locale
	 *            Locale 객체
	 * @return 치안대상 목록화면
	 * @throws Exception
	 *             기본 예외 처리
	 */
	@RequestMapping(value = "/add.do", method = RequestMethod.POST)
	public String add(@ModelAttribute("corpVO") final CorpVO corpVO,
			final BindingResult bindingResult, final Model model,
			final SessionStatus status, final Locale locale) throws Exception {
		// 사용자 인증 검사
		Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
		
		// 등록은 isAdmin이 true인 사용자만 가능하다.
		if (isAuthenticated && UserUtil.isAdmin()) {
			// 유효성 검사
			beanValidator.validate(corpVO, bindingResult);
			if (bindingResult.hasErrors()) {
				return add(model, corpVO, locale);
			}
			
			HashMap<String, Object> map = corpService.insert(corpVO, null);
			
			status.setComplete();
			
			if ((Integer) map.get("result") == 1) {
				return makeRedirectUri(PageType.List, corpVO);
			}
		}
		
		return "error/bizError";
	}
	
	/**
	 * 치안대상 수정화면을 반환한다.
	 * 
	 * @param model
	 *            Model 객체
	 * @param locale
	 *            Locale 객체
	 * @param corpVO
	 *            치안대상 VO
	 * @return 치안대상 수정화면
	 * @throws Exception
	 *             기본 예외 처리
	 */
	@RequestMapping(value = "/update.do")
	public String update(final Model model, final Locale locale, final CorpVO corpVO) throws Exception {
		LoginUserVO loginUserVO = UserUtil.getMemberInfo();
		model.addAttribute("loginUserVO", loginUserVO);
		
		// 등록은 관리자만 가능하지만, 수정/삭제는 관리자 + 해당 기관도 가능하다.
		if (loginUserVO.getIsAdmin()
				|| loginUserVO.getPlace1().equalsIgnoreCase(corpVO.getPlace1())) {
			CorpVO vo = corpService.select(corpVO);
			model.addAttribute("corpVO", vo);
			
			LinkedHashMap<String, String> fieldNameMap = getFieldName(vo.getGrpNo(), locale);
			model.addAttribute("fieldNameMap", fieldNameMap);
			model.addAttribute("registerFlag", "modify");
			
			return "/tg/corpAdd.tiles";
		}
		
		return makeRedirectUri(PageType.View, corpVO);
	}
	
	/**
	 * 치안대상 정보를 수정한다.
	 * 
	 * <pre>
	 * php소스에는 파일 업로드 기능이 있으나, 
	 * 파일 관련 필드가 DB에도 없고 표현기능도 없어서 제외함.
	 * </pre>
	 * 
	 * @param corpVO
	 *            치안대상 VO
	 * @param bindingResult
	 *            유효성 검사결과 객체
	 * @param model
	 *            모델 객체
	 * @param status
	 *            SessionStatus 객체
	 * @param locale
	 *            Locale 객체
	 * @return 치안대상 목록화면
	 * @throws Exception
	 *             기본 예외 처리
	 */
	@RequestMapping(value = "/update.do", method = RequestMethod.POST)
	public String update(@Valid @ModelAttribute("corpVO") final CorpVO corpVO,
			final BindingResult bindingResult, final Model model,
			final SessionStatus status, final Locale locale) throws Exception {
		// 사용자 인증 검사
		Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
		if (isAuthenticated) {
			LoginUserVO loginUserVO = UserUtil.getMemberInfo();
			
			// 등록은 관리자만 가능하지만, 수정/삭제는 관리자 + 해당 기관도 가능하다.
			if (loginUserVO.getIsAdmin()
					|| loginUserVO.getPlace1().equalsIgnoreCase(corpVO.getPlace1())) {
				// 유효성 검사
				beanValidator.validate(corpVO, bindingResult);
				if (bindingResult.hasErrors()) {
					return update(model, locale, corpVO);
				}

				corpVO.setWriter(loginUserVO.getUserid());
				corpVO.setWriterPlace1(loginUserVO.getPlace1());

				HashMap<String, Object> map = corpService.update(corpVO, null,
						null);

				status.setComplete();

				if ((Integer) map.get("result") == 1) {
					return makeRedirectUri(PageType.View, corpVO);
				}
			}
		}
		
		return "error/bizError";
	}
	
	/**
	 * 치안대상 정보를 삭제하고 목록화면을 반환한다.
	 * 
	 * @param model
	 *            Model 객체
	 * @param locale
	 *            Locale 객체            
	 * @param corpVO
	 *            치안대상 VO
	 * @return 치안대상 목록화면
	 * @throws Exception
	 *             기본 예외 처리
	 */
	@RequestMapping(value = "/delete.do", method = RequestMethod.POST)
	public String delete(final Model model, final Locale locale, final CorpVO corpVO) throws Exception {
		LoginUserVO loginUserVO = UserUtil.getMemberInfo();
		
		// 등록은 관리자만 가능하지만, 수정/삭제는 관리자 + 해당 기관도 가능하다.
		if (loginUserVO.getIsAdmin()
				|| loginUserVO.getPlace1().equalsIgnoreCase(corpVO.getPlace1())) {
			CorpVO vo = corpService.select(corpVO);
			
			HashMap<String, Object> result = corpService.delete(corpVO);
			if ((Integer) result.get("result") == 1) {
				return makeRedirectUri(PageType.List, vo);
			}
		}
		return makeRedirectUri(PageType.View, corpVO);
	}
}
