package kcg.faics.board.service.impl;

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

import javax.annotation.Resource;

import kcg.faics.board.service.BoardService;
import kcg.faics.board.util.BoardVOHandler;
import kcg.faics.board.vo.BoardCommentVO;
import kcg.faics.board.vo.BoardFileVO;
import kcg.faics.board.vo.BoardSearchVO;
import kcg.faics.board.vo.BoardVO;
import kcg.faics.cmmn.bbs.BaseCommentService;
import kcg.faics.cmmn.bbs.BaseFileService;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import egovframework.rte.fdl.cmmn.EgovAbstractServiceImpl;


/** 
 * BoardServiceImpl.java 
 * @author 임새미 
 * @since 2016. 9. 28.
 *
 *  	 수정일                     수정자                                       수정내용
 *  -------------	--------	---------------------------
 *  2016. 9. 28. 	    임새미				       최초생성
 * 
 */
@Service("boardService")
public class BoardServiceImpl extends EgovAbstractServiceImpl implements BoardService {
	
	/**
	 * BoardMapper - 게시판 데이터처리에 관한 Mapper 클래스
	 **/
    @Resource(name = "boardMapper")
	private BoardMapper boardMapper;
    
    /**
	 * BoardFileService - 게시판 파일에 관한 인터페이스
	 **/
	@Resource(name = "boardFileService")
	private BaseFileService<BoardFileVO> boardFileService;
	
	/**
	 * BoardCommentService - 게시판 덧글에 관한 인터페이스
	 **/
	@Resource(name = "boardCommentService")
	private BaseCommentService<BoardCommentVO> boardCommentService; 
	
	
	/**
	 * 게시판 목록 화면을 반환한다.
	 * 
	 * @param searchVO 검색, 페이지 정보 객체
	 * @return 게시물 리스트
	 * @throws Exception 기본 예외 처리
	 */
	@Override
	public List<BoardVO> selectList(final BoardSearchVO searchVO) throws Exception {
		return boardMapper.selectBoardList(searchVO);
	}
	
    /**
	 * 검색 키워드에 따른 총 게시물 개수를 조회한다.
	 * 
	 * @param searchVO 검색, 페이지 정보 객체
	 * @return 게시물 개수
	 * @exception Exception 기본 예외 처리
	 */
	@Override
	public int selectListCnt(final BoardSearchVO searchVO) throws Exception {
		return boardMapper.selectBoardListTotCnt(searchVO);
	}
	
	/**
	 * 전체 게시물 개수를 가져온다.
	 * 
	 * @return 게시물 개수
	 * @throws Exception 기본 예외 처리
	 */
	@Override
	public int selectTotalCnt(final BoardSearchVO searchVO) throws Exception {
		return boardMapper.selectBoardTotalCnt(searchVO);
	}
	

	/**
	 * 선택한 게시물의 내용을 반환한다.
	 * 
	 * @param bdSeq 게시판 
	 * @return 선택한 게시물 내용 반환
	 * @throws Exception 기본 예외 처리
	 */
	@Override
	public BoardVO select(final BoardVO boardVO) throws Exception {
		return boardMapper.selectBoard(boardVO);
	}	
	
	
	/**
	 * 이전 글 or 다음 글의 시퀀스 번호를 업데이트한다.
	 * 
	 * @param bdSeq 업데이트 대상 게시물 시퀀스
	 * @param prevNextChar 이전(P) or 다음{N)
	 * @param seqValue 시퀀스 값 
	 * @return 1-성공, 0-실패
	 */
	private int updatePrevNextSeq(final BoardVO boardVO, final String prevNextChar, final int seqValue) {
		int result = 0;
		boolean isContinue = false;
		try {
			BoardVO updateBoard = boardMapper.selectBoard(boardVO);
			
			if ("P".equals(prevNextChar)) {
				updateBoard.setPrevSeq(seqValue);
				isContinue = true;
			} else if ("N".equals(prevNextChar)) {
				updateBoard.setNextSeq(seqValue);
				isContinue = true;
			}
			if (isContinue) { 
				result = boardMapper.updatePrevNextSeq(updateBoard);
			}	
		} catch (Exception e) {
			e.printStackTrace();
			return result;
		}
		return result;
	}

	/**
	 * 게시물을 추가한다.
	 * 
	 * @param boardVO 게시판 내용 구성 객체
	 * @return HashMap/ seq : 게시물 , result : 성공 - 1, 실패 - 0
	 * @throws Exception 기본 예외 처리
	 */
	private HashMap<String, Object> insert(final BoardVO boardVO) throws Exception {
		
		HashMap<String, Object> map = new HashMap<String, Object>();

		/* 답글인 경우 */
		if (boardVO.getIsReply() > 0) {
			boardVO.setDepth(boardVO.getDepth() + 1);
			boardVO.setStep(boardVO.getStep() + 1);
			boardVO.setNextSeq(boardVO.getParentSeq());
		}
		
		/* seq 및 insert 결과 */
		map = boardMapper.insertBoard(boardVO);
		
		int seq = (Integer) map.get("seq");
		int result = (Integer) map.get("result");
		
		if (seq > 0 && result > 0) {
			boardVO.setSeq(seq);
			
			/* 답글인 경우 */
			if (boardVO.getIsReply() > 0) {
				// 스텝순서 변경 
				boardMapper.updateGrpStep(boardVO);
				// 추가된 글의 다음글의 prevSeq 변경
				BoardVO nextBoard = BoardVOHandler.getBoardVO(boardVO.getId(), boardVO.getParentSeq());
				this.updatePrevNextSeq(nextBoard, "P", seq);
				
			} else {
				/* 새 게시글 추가의 경우 추가한 게시물의 group seq를 자기 자신으로 설정한다. */
				boardMapper.updateGrpSeq(boardVO);
			}
			
			// 이전글 정보를 가져온다
			BoardVO prevBoard = boardMapper.selectPrevBoard(boardVO);
			if (prevBoard != null) {
				/* 이전 글의 next_seq 설정 */
				this.updatePrevNextSeq(prevBoard, "N", seq);
				/* 현재 글의 prev_seq 설정 */
				this.updatePrevNextSeq(boardVO, "P", prevBoard.getSeq());
			} else {
				this.updatePrevNextSeq(boardVO, "P", 0);
			}
			
		} else {
			throw new Exception();
		}
			
		return map;
	}
	
	/**
	 * 게시물을 추가한다.
	 * 
	 * @param boardVO 게시판 내용 구성 객체
	 * @param fileMap 업로드 파일정보체
	 * @return HashMap/ seq : 게시물 , result : 성공 - 1, 실패 - 0
	 * @exception Exception 기본 예외 처리
	 */
	@Override
	@Transactional
	public HashMap<String, Object> insert(final BoardVO boardVO, final Map<String, MultipartFile> fileMap) throws Exception {
		
		HashMap<String, Object> map = new HashMap<String, Object>();
			
		/* seq 획득 */
		map = insert(boardVO);
		
		int seq = (Integer) map.get("seq");
		int result = (Integer) map.get("result");
		
		/* 파일 업로드 */
		BoardFileVO boardFileVO = BoardVOHandler.getBFileVO(boardVO.getId(), seq, 0);
		
		result = boardFileService.insertAndSaveFiles(boardFileVO, fileMap);

		if (result != 1) {
			throw new Exception();
		} else {
			map.put("result", result);
		}
			
		return map;
	}
	
	
	/**
	 * 게시물을 DB에 업데이트 한다.
	 * 
	 * @param boardVO 게시물 VO
	 * @return 성공 - 1, 실패 - 0
	 * @throws Exception 기본 예외 처리
	 */
	private int updateBoard(final BoardVO boardVO) throws Exception {
		return boardMapper.updateBoard(boardVO);
	};
	
	/**
	 * 게시물을 업데이트 한다.
	 * 
	 * @param boardVO 게시물 VO
	 * @param fileMap MultipartFile형태의 파일정보 
	 * @param deleteFiles 삭제할 파일리스트
	 * @return HashMap/ seq : 게시물 번호 , result : 성공 - 1, 실패 - 0
	 */
	@Override
	@Transactional
	public HashMap<String, Object> update(final BoardVO boardVO, final Map<String, MultipartFile> fileMap, final String[] deleteFiles) throws Exception {
		
		HashMap<String, Object> map = new HashMap<String, Object>();
		int result = 0;
		
		BoardFileVO boardFileVO= BoardVOHandler.getBFileVO(boardVO);
		boardFileVO.setDeleteFiles(deleteFiles);
		boardFileService.delete(boardFileVO);
		boardFileService.insertAndSaveFiles(boardFileVO, fileMap);
		
		result = this.updateBoard(boardVO);
		
		if (result != 1) {
			throw new Exception();
		} else {
			map.put("result", result);
			map.put("seq", boardVO.getSeq());
		}
		
		return map;
	}

	
	/**
	 * 게시물을 삭제한다.
	 * 
	 * @param bdSeq 게시물 번호
	 * @return HashMap/ seq : 게시물 번호 , result : 성공 - 1, 실패 - 0
	 */
	@Transactional
	@Override
	public HashMap<String, Object> delete(final BoardVO boardVO) throws Exception {
		
		HashMap<String, Object> map = new HashMap<String, Object>();
		int result = 0;
		
		/* 삭제 후 처리를 위해 데이터 캐싱 */
		BoardVO delBoard = boardMapper.selectBoard(boardVO);
		
		result = boardMapper.deleteBoard(delBoard);
		
		if (result == 1) {
			/* 이전 글, 다음 글의 이전/다음 시퀀스 재조정 */
			int prevSeq = boardVO.getPrevSeq();
			int nextSeq = boardVO.getNextSeq();
			if (prevSeq > 0) {
				this.updatePrevNextSeq(BoardVOHandler.getBoardVO(boardVO.getId(), prevSeq), "N", nextSeq);
			}
			if (nextSeq > 0) {
				this.updatePrevNextSeq(BoardVOHandler.getBoardVO(boardVO.getId(), nextSeq), "P", prevSeq);
			}
			
			/* 파일을 삭제한다. */
			boardFileService.deleteAndRemoveFiles(BoardVOHandler.getBFileVO(delBoard));
			
			/* 댓글을 삭제한다. */
			boardCommentService.deleteAll(BoardVOHandler.getBCommentVO(delBoard));
			
			map.put("result", result);
		} else {
			throw new Exception();
		}
		
		return map;
	};
	
	/**
	 * 선택한 게시물들을 삭제한다.
	 * 
	 * @param bdSeqs 선택한 게시물 아이디 목록
	 * @return 성공 - 1, 실패 - 0
	 */
	@Override
	public HashMap<String, Object> selectAndDelete(final BoardVO boardVO, final int[] boardList) throws Exception {
		
		HashMap<String, Object> map = new HashMap<String, Object>();
		int result = 0;
		
		if (boardList != null) {
			for (int seq : boardList) {
				boardVO.setSeq(seq);
				map = delete(boardVO);
				result = (Integer) map.get("result");
				if (result != 1) {
					throw new Exception();
				}
			}
		}
		
		map.put("result", result);
		
		return map;
	};
	
	/**
	 * 조회수를 1 증가시킨다.
	 * 
	 * @param boardVO 게시물 VO
	 * @return 1-성공, 0-실패
	 */
	@Override
	public int incHit(final BoardVO boardVO) throws Exception {
		int result = 0;
		boardVO.incHit();
		result = this.updateBoard(boardVO);
		return result;
	}

	@Override
	public List<BoardVO> selectListAll(BoardSearchVO searchVO) throws Exception {
		return null;
	}
}
