package kcg.imis.report.web;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kcg.imis.cmmn.CommConstants;
import kcg.imis.cmmn.file.FileResponser;
import kcg.imis.cmmn.service.CodeService;
import kcg.imis.cmmn.vo.CodeVO;
import kcg.imis.member.service.MemberService;
import kcg.imis.member.vo.MemberVO;
import kcg.imis.report.service.ReportFileServiceImpl;
import kcg.imis.report.service.ReportJudgeService;
import kcg.imis.report.service.ReportService;
import kcg.imis.report.vo.ReportJudgeVO;
import kcg.imis.report.vo.ReportSearchVO;
import kcg.imis.report.vo.ReportVO;
import kcg.imis.sec.LoginUserVO;
import kcg.imis.sec.UserUtil;

import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.FileCopyUtils;
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.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springmodules.validation.commons.DefaultBeanValidator;

import egovframework.rte.fdl.property.EgovPropertyService;
import egovframework.rte.fdl.security.userdetails.util.EgovUserDetailsHelper;
import egovframework.rte.ptl.mvc.tags.ui.pagination.PaginationInfo;

/**
  * @FileName : ReportController.java
  * @Project : 국제해양프로젝트
  * @Date : 2018. 3. 29. 
  * @작성자 : Moon
  * @변경이력 : 
  * @프로그램 설명 :
 */
@Controller
@RequestMapping("/report")
public class ReportController {
	/**
	 * properties값을 가져오는 인터페이스.
	 **/
	@Resource(name = "propertiesService")
	private EgovPropertyService propertiesService;
	
	/**
	 * 견문 기본 인터페이스이다. 
	 */
	@Resource(name = "reportService")
	private ReportService reportService;

	/**
	 * 견문 결재 인터페이스 
	 */
	@Resource(name = "reportJudgeService")
	private ReportJudgeService judgeService;
	
	/**
	 * 사용자 인터페이스
	 */
	@Resource(name = "memberService")
	private MemberService memberService;
	
	/**
	 * Validator - 유효성 검사
	 **/
	@Resource(name = "beanValidator")
	private DefaultBeanValidator beanValidator;

	/**
	 * 코드 인터페이스
	 */
	@Resource(name = "codeService")
	private CodeService codeService;

	/**
	 * 임시저장목록을 조회한다.
	 * 
	 * @param rptSearchVO 견문 검색조건 vo
	 * @param model 모델객체
	 * @return 임시저장목록 화면
	 */
	@RequestMapping(value = "/saveList.do")
	public String reportSaveList(@ModelAttribute("reportSearchVO") final ReportSearchVO rptSearchVO, final Model model) {
		LoginUserVO loginUserVO = UserUtil.getMemberInfo();
		try {
			rptSearchVO.setUserid(loginUserVO.getUserid());
			rptSearchVO.setUsegrade(loginUserVO.getUsegrade());
			rptSearchVO.setType(loginUserVO.getType());

			/* 페이징 처리 정보 */
			rptSearchVO.setPageUnit(propertiesService.getInt("pageUnit"));
			rptSearchVO.setPageSize(propertiesService.getInt("pageSize"));

			/* 페이징 처리 */
			PaginationInfo paginationInfo = new PaginationInfo();
			paginationInfo.setCurrentPageNo(rptSearchVO.getPageIndex());
			paginationInfo.setRecordCountPerPage(rptSearchVO.getRecordCountPerPage());
			paginationInfo.setPageSize(rptSearchVO.getPageSize());

			rptSearchVO.setFirstIndex(paginationInfo.getFirstRecordIndex());
			rptSearchVO.setLastIndex(paginationInfo.getLastRecordIndex());
			rptSearchVO.setRecordCountPerPage(paginationInfo.getRecordCountPerPage());

			int totSearchCnt = reportService.selectSaveListCnt(rptSearchVO);
			paginationInfo.setTotalRecordCount(totSearchCnt);
			model.addAttribute("paginationInfo", paginationInfo);

			// 임시저장목록은 전체 갯수가 의미 없으므로 검색결과 총 갯수로 대신한다.
			model.addAttribute("totalCnt", totSearchCnt);

			List<ReportVO> reportList = reportService.selectSaveList(rptSearchVO);
			model.addAttribute("reportList", reportList);
			
			model.addAttribute("reportSearchVO", rptSearchVO);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return "report/reportSaveList.tiles";
	}
	
	/**
	 * 견문 입력 화면을 반환한다.
	 * @param model 맵 모델
	 * @return String 뷰이름
	 */
	@RequestMapping(value = "/add.do", method = RequestMethod.GET)
	public String insertReport(final Model model) {
		
		try {
			model.addAttribute("category1", codeService.getCodeMap(CommConstants.CODE_CATE1));
			model.addAttribute("category2", codeService.getCodeMap(CommConstants.CODE_CATE2));
			
			model.addAttribute("myGroupCode", ReportCommon.getMyGroupCode());
			
			if (!model.containsAttribute("reportVO")) {
				ReportVO reportVO = new ReportVO();
				LoginUserVO userVO = UserUtil.getMemberInfo();		
				
				reportVO.setInType(String.valueOf(userVO.getType()));
				reportVO.setInAgencyCode(ReportCommon.getAgencyCode(userVO.getPlace1()));
				reportVO.setInPlaceCode(userVO.getPlace1());
				reportVO.setInPlaceName(ReportCommon.getPlaceShortName(userVO.getPlace1Str()));
				reportVO.setInPlaceNum(reportService.selectPlaceNum(reportVO));
				
				model.addAttribute("reportVO", reportVO);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
		return "report/reportAdd.tiles";
	}
	
	/**
	 * 견문을 입력한 뒤 입력된 견문의 상세 조회 화면으로 이동한다.
	 * @param multiRequest 
	 * @param reportVO 견문 모델 객체
	 * @param bindingResult 
	 * @param model 
	 * @param status 
	 * @return String 뷰 이름
	 * @throws Exception 기본 예외 처리
	 */
	@RequestMapping(value = "/add.do", method = RequestMethod.POST)
	public String insertReport(final MultipartHttpServletRequest multiRequest, @ModelAttribute("reportVO") final ReportVO reportVO, 
			final BindingResult bindingResult, final Model model, final SessionStatus status) throws Exception {
		// 사용자 인증 검사
		Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
		if (isAuthenticated) {
			// 유효성 검사
			beanValidator.validate(reportVO, bindingResult);
			if (bindingResult.hasErrors()) {
				model.addAttribute("reportVO", reportVO);
				return insertReport(model);
			}

			// 사용자로부터 받아오는 정보
			LoginUserVO userVO = UserUtil.getMemberInfo();
			reportVO.setInPlace(userVO.getPlace1());
			reportVO.setInPlace1(userVO.getPlace1Str());
			reportVO.setInPlace2(userVO.getPlace2Str());
			reportVO.setInDuty(userVO.getDutyStr());
			reportVO.setInName(userVO.getName());
			reportVO.setInUserid(userVO.getUserid());
			reportVO.setInIp(multiRequest.getRemoteAddr());
			reportVO.setInType(String.valueOf(userVO.getType()));
			
			reportVO.setInAgencyCode(ReportCommon.getAgencyCode(userVO.getPlace1()));
			reportVO.setInPlaceCode(userVO.getPlace1());
			reportVO.setInPlaceName(ReportCommon.getPlaceShortName(userVO.getPlace1Str()));
			reportVO.setInPlaceNum(reportService.selectPlaceNum(reportVO));
			
			// 보고일 파싱
			String infoDate = reportVO.getStrInfodate().toString();
			reportVO.setInInfoYear(Integer.valueOf(infoDate.split("-")[0]));
			reportVO.setInInfoMonth(Integer.valueOf(infoDate.split("-")[1]));
			reportVO.setInInfoDay(Integer.valueOf(infoDate.split("-")[2]));
			
			// 파일 저장 및 데이터 입력
			final Map<String, MultipartFile> fileMap = multiRequest.getFileMap();
			HashMap<String, Object> map = reportService.insert(reportVO, fileMap);

			status.setComplete();

			int seq = (Integer) map.get("seq");
			int result = (Integer) map.get("result");
			if (result == 1 && seq > 0) {
				reportVO.setInSeq(seq);
				model.addAttribute("submitResultMsg", "입력이 완료되었습니다. 수정화면으로 이동합니다.");
				model.addAttribute("submitResultSeq", seq);
				return this.insertReport(model);
			}
		}		
		return "error/bizError";
	}

	/**
	 * 선택된 견문의 조회/수정화면을 반환한다.
	 * 
	 * @param reportVO 임시 저장된 견문 객체
	 * @param model model객체
	 * @return 견문 수정 화면
	 * @throws Exception 기본예외처리
	 */
	@RequestMapping(value = {"/update.do", "/updateApprove.do", "/updateJudge.do", "/updateMyReport.do", "/updatePresent.do", "/updateList.do"}, method = RequestMethod.GET)
	public String update(@ModelAttribute("reportVO") final ReportVO reportVO, final Model model) throws Exception {
		ReportVO vo = reportService.select(reportVO);
		vo.setStateCodeName(ReportCommon.getStateCodeNm(vo.getInStateCode()));
		model.addAttribute("reportVO", vo);
		
		LoginUserVO user = UserUtil.getMemberInfo();
		model.addAttribute("loginUser", user);
		
		int myGroupCode = ReportCommon.getMyGroupCode();
		model.addAttribute("myGroupCode", myGroupCode);
		
		int myDutiesCode = ReportCommon.getDutiesCodeForApprove(UserUtil.getMemberInfo().getDuties());
		boolean modifyProcess = ((!"99".equals(vo.getInStateCode())) && "1".equals(vo.getInStateCode().charAt(1)));
		boolean modifyAuth = (!user.getUserid().equals(vo.getInUserid()) && myDutiesCode != 3);
		
		model.addAttribute("viewDoc", ((modifyProcess | modifyAuth) & !UserUtil.isSysAdmin()));
		
		model.addAttribute("statusName", vo.getStateCodeName());
		
		model.addAttribute("myDutiesCode", ReportCommon.getDutiesCodeForApprove(user.getDuties()));
		model.addAttribute("docGroupCode", ReportCommon.getGroupCode(vo.getInPlaceCode()));
		
		model.addAttribute("juSection", judgeService.selectOne(vo.getInJuseqSection()));
		model.addAttribute("juHead", judgeService.selectOne(vo.getInJuseqHead()));
		
		if (!StringUtils.isBlank(vo.getInOfflineUserid())) {
			MemberVO memberVO = getOffUser(vo.getInOfflineUserid());
			if (memberVO != null) {
				memberVO.setPlace1Str(ReportCommon.getPlaceShortName(memberVO.getPlace1Str()));
				model.addAttribute("offUser", memberVO);
			}
		}
		
		//분류 1,2,3,4
		model.addAttribute("category1", codeService.getCodeMap(CommConstants.CODE_CATE1));
		model.addAttribute("category2", codeService.getCodeMap(CommConstants.CODE_CATE2));

		return "report/reportModify.tiles";
	}

	/**
	 * 견문을 수정하고 조회 페이지를 반환한다.
	 * 
	 * @param multiRequest 멀티리퀘스트객체
	 * @param reportVO 견문 객체
	 * @param bindingResult 바인딩객체
	 * @param model 모델 객체
	 * @param status 세션 객체
	 * @return 조회 화면
	 * @throws Exception 기본예외처리
	 */
	@RequestMapping(value = {"/update.do", "/updateReport.do"}, method = RequestMethod.POST)
	public String updateReport(@ModelAttribute("reportVO") final ReportVO reportVO, final MultipartHttpServletRequest multiRequest, 
			final BindingResult bindingResult, final Model model, final SessionStatus status) throws Exception {
		
		// 사용자 인증 검사
		Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
		if (isAuthenticated) {
			// 유효성 검사
			/*beanValidator.validate(reportVO, bindingResult);*/
			if (bindingResult.hasErrors()) {
				return update(reportVO, model);
			}
			
			ReportVO vo  = reportService.select(reportVO);
			
			vo.setInCategory1(reportVO.getInCategory1());
			vo.setInCategory2(reportVO.getInCategory2());
			vo.setInMemo(reportVO.getInMemo());
			vo.setInDocPlace(reportVO.getInDocPlace());
			vo.setInMemo(reportVO.getInMemo());
			vo.setInSubject(reportVO.getInSubject());
			vo.setInContent(reportVO.getInContent());
			vo.setStrInfodate(reportVO.getStrInfodate());
			if(vo.getInJudge() != reportVO.getInJudge()){
				vo.setInJudge(reportVO.getInJudge());
			}
			
			if (!vo.getInStateCode().equals(reportVO.getInStateCode())) {
				vo.setInStateCode(reportVO.getInStateCode());
			}
			
			// 보고일 파싱
			String infoDate = reportVO.getStrInfodate().toString();
			vo.setInInfoYear(Integer.valueOf(infoDate.split("-")[0]));
			vo.setInInfoMonth(Integer.valueOf(infoDate.split("-")[1]));
			vo.setInInfoDay(Integer.valueOf(infoDate.split("-")[2]));
			
			// 파일 저장 및 데이터 입력
			String[] deleteFiles = multiRequest.getParameterValues("deleteFile");
			final Map<String, MultipartFile> fileMap = multiRequest.getFileMap();

			// 관리자가 수정했을 때 처리
			if (UserUtil.isSysAdmin()) {
				int judge = 0;
				
				// 경찰서 과장 결재 정보
				ReportJudgeVO judgeVO = judgeService.selectOne(vo.getInJuseqHead());
				if (judgeVO != null) {
					judgeVO.setJuJudge(reportVO.getInJudge());
					judgeService.update(judgeVO);
					vo.setInJudge(reportVO.getInJudge());
					judge = reportVO.getInJudge();
				}
				
				if (judge > 0) {
					vo.setInJudge(judge);
				}
			
			}
			
			// 견문 수정
			HashMap<String, Object> map = reportService.update(vo, fileMap, deleteFiles);

			status.setComplete();

			int seq = (Integer) map.get("seq");
			int result = (Integer) map.get("result");
			if (result == 1 && seq > 0) {
				
				String requestUrl = multiRequest.getRequestURL().toString();
				if (requestUrl.indexOf("/updateReport.do") > 0) {
					model.addAttribute("submitResultMsg", "성공적으로 보고되었습니다.");
				} else {
					model.addAttribute("submitResultMsg", "수정이 완료되었습니다.");
				}
				return this.update(reportVO, model);
			}
		}
		
		return "error/bizError";
	}
	
	/**
	 * 일괄입력 유저 정보를 반환한다.
	 * 
	 * @param offType 일괄입력 종류
	 * @param offUserId 일괄입력 사용자id
	 * @return 사용자vo
	 * @throws Exception 기본 예외 처리
	 */
	private MemberVO getOffUser(final String offUserId) throws Exception {
		MemberVO memberVO = new MemberVO();
		memberVO.setUserid(offUserId);
		
		try {
			memberVO = memberService.getMemberInfo(offUserId);
		} catch (Exception e) {
		}
		
		return memberVO;
	}
	
	/**
	 * 선택된 견문을 삭제한다.
	 * 
	 * @param map 맵 객체
	 * @param status SessionStatus 객체
	 * @return 견문 임시저장목록 화면
	 * @throws Exception 기본예외처리
	 */
	@ResponseBody
	@RequestMapping(value = "/delete.do")
	public int deleteAjax(@RequestParam final HashMap<String, Object> map, final SessionStatus status) throws Exception {
		try {
			int result = 0;
			String[] selectedSeq = new String[map.size()];
			int cnt = 0;
			for (String key : map.keySet()) {
				selectedSeq[cnt] = map.get(key).toString();
				cnt++;
			}

			if (selectedSeq != null) {
				result = reportService.deleteSelected(selectedSeq);
			}
			status.setComplete();
			
 			return result;
		} catch (Exception e) {
			return 0;
		}
	}

	/**
	 * 선택된 견문을 삭제하고 임시저장목록을 반환한다.
	 * 
	 * @param reportVO 견문 객체
	 * @param model model객체
	 * @param status SessionStatus 객체
	 * @return 견문 임시저장목록 화면
	 * @throws Exception 기본예외처리
	 */
	@RequestMapping(value = "/deleteAndSaveList.do")
	public String delete(@ModelAttribute final ReportVO reportVO, final Model model, 
			final SessionStatus status) throws Exception {
		try {
			String[] selectedSeq = {String.valueOf(reportVO.getInSeq())};
			
			if (selectedSeq != null) {
				reportService.deleteSelected(selectedSeq);
			}
			status.setComplete();
			return "redirect:/report/myList.do";
		} catch (Exception e) {
			return "error/bizError";
		}
		
	}

	/**
	 * 파일을 반환한다.
	 * 
	 * @param seq 파일시퀀스
	 * @param no 파일명
	 * @param request HttpServletRequest 객체
	 * @param response HttpServletResponse 객체
	 * @throws Exception 기본 예외 처리
	 */
	@RequestMapping(value = "/download.do")
	public void fileResponse(final int seq, final int no, final HttpServletRequest request, final HttpServletResponse response) throws Exception {
		ReportVO reportVO = new ReportVO();
		reportVO.setInSeq(seq);
		reportVO = reportService.select(reportVO);
		
		String filename = "";
		if (no == 1) {
			filename = reportVO.getInFileName1();
		} else if (no == 2) {
			filename = reportVO.getInFileName2();
		} else if (no == 3) {
			filename = reportVO.getInFileName3();
		} 
		
		// 20180523 첨부파일 관련되서 파일명으로 다운받게 추가
		String infilename = "";
		if (no == 1) {
			infilename = reportVO.getInFile1();
		} else if (no == 2) {
			infilename = reportVO.getInFile2();
		} else if (no == 3) {
			infilename = reportVO.getInFile3();
		} 
		
		if (StringUtils.isNotBlank(filename)) {
			filename = filename.trim();
			String fileFullPath = propertiesService.getString(ReportFileServiceImpl.FILE_PATH_KEYWORD) + String.valueOf(reportVO.getInFsseq()) + "/" + filename;
			
			File file = new File(fileFullPath);
			if (file.isFile()) {
				// 20180523 첨부파일 관련되서 파일명으로 다운받게 수정
				//FileResponser.setResponse(file, filename, request, response);
				FileResponser.setResponse(file, infilename, request, response);
				BufferedInputStream in = null;
				
				try {
					in = new BufferedInputStream(new FileInputStream(file));
					FileCopyUtils.copy(in, response.getOutputStream());
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					if (in != null) {
						try {
							in.close();
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
			} else {
				response.setStatus(HttpStatus.NOT_FOUND.value());			
				throw new Exception();
			}
		} else {
			response.setStatus(HttpStatus.NOT_FOUND.value());			
			throw new Exception();
		}
	}
	
	/**
	 * 견문보고서를 인쇄한다.
	 * 
	 * @param inSeq 견문시퀀스
	 * @param model 모델객체
	 * @return 견문보고서 화면
	 * @throws Exception 기본예외처리
	 */
	@RequestMapping(value = "/print.do")
	public String print(@RequestParam("inSeq") final int inSeq, final Model model) throws Exception {
		ReportVO reportVO = new ReportVO();
		reportVO.setInSeq(inSeq);
		reportVO = reportService.select(reportVO);
		model.addAttribute("reportVO", reportVO);
		
		int stateCode1 = Character.getNumericValue(reportVO.getInStateCode().charAt(0));
		if (stateCode1 <= ReportCommon.getMyGroupCode()) {
			int seqSection = reportVO.getInJuseqSection();
			int seqHead =reportVO.getInJuseqHead();
			
			model.addAttribute("judgeSectionCheif", judgeService.selectOne(seqSection));
			model.addAttribute("judgeHeadCheif", judgeService.selectOne(seqHead));
		}
		
		model.addAttribute("tempDoc", reportVO.getInStateCode().equals("99"));
		model.addAttribute("myDutiesCode", ReportCommon.getDutiesCodeForApprove(UserUtil.getMemberInfo().getDuties()));
		model.addAttribute("myGroupCode", ReportCommon.getMyGroupCode());
		
		return "report/reportView";
	}

	
	@RequestMapping(value = {"/reportCategory.do"}, method = RequestMethod.GET)
	public String categoryManage(final Model model) throws Exception {
		
		CodeVO codeVO = new CodeVO();
		model.addAttribute("codeVO", codeVO);
		return "report/reportCategory.tiles";
	}
}
