package kr.co.kihyun.beans.totsys.totper;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;

import javax.jdo.PersistenceManager;
import javax.jdo.Transaction;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.co.kihyun.beans.entity.MDept;
import kr.co.kihyun.beans.entity.TotDoc;
import kr.co.kihyun.beans.entity.TotReport;
import kr.co.kihyun.beans.entity.TotReportProcess;
import kr.co.kihyun.beans.entity.util.*;
import kr.co.kihyun.beans.user.HttpSSOLogin;
import kr.co.kihyun.db.CommonDBManager;
import kr.co.kihyun.lang.MLong;
import kr.co.kihyun.lang.MString;
import kr.co.kihyun.moumi.MoumiConfig;
import kr.co.kihyun.text.html.ServletUtil;

import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Servlet implementation class HttpFileDownLoad
 */
@WebServlet("/servlet/kr.co.kihyun.beans.totsys.totper.HttpFileDownLoad")
public class HttpFileDownLoad extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private static final Logger LOG = LoggerFactory.getLogger(HttpFileDownLoad.class);
	private static final int BUFFER = 4096;

	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		doPost(req, res);
	}

	@Override
	public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		if (!HttpSSOLogin.isLogin(req)) {
			String connURL = "location='/index.html';";
			res.getWriter().println("<script> alert(\""+MoumiConfig.getMessageBundle().getString("moumi.message.popup.useLogin")+"\")</script>");
			res.getWriter().println(ServletUtil.getJavaScript(connURL));
			return;
		}

		Long docID = MLong.parseLong(req.getParameter("docID"));
		Long repDocID = 0L;
        //LJH
        String saveAs=req.getParameter("saveAs");
		String[] reportIDArray = MString.checkNull(req.getParameter("reportIDs")).split(",");
		//LOG.debug("[파라미터로 넘어온 reportIDArray 다음과 같다]["+reportIDArray+"]");

		boolean setUserName = Boolean.parseBoolean(req.getParameter("setUserName"));
		res.setContentType("application/zip;charset=UTF-8");
        //LJH
        String fname=URLEncoder.encode(saveAs, "UTF-8").replaceAll(":","_").replace("+", " ") +";";
        String fnameE=URLEncoder.encode(saveAs, "UTF-8").replaceAll(":","_").replace("+", " ") +";";
        String fnameD=URLDecoder.decode(saveAs, "UTF-8").replaceAll(":","_").replace("+", " ") +";";

        //3.디렉토리 경로 조작(getParameter)_CWE-22/23/36 : Add by KWON,HAN
        fname = fnameD;
        if(fname.contains("..") || fname. contains("/")) { // 특수문자열 검증
            return;
        }
        fname =  fnameE;
        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


		res.setHeader("Content-Disposition", "attachment; filename="+fname);

		byte data[] = new byte[BUFFER];
		ZipArchiveOutputStream out = new ZipArchiveOutputStream(new BufferedOutputStream(res.getOutputStream()));
		out.setEncoding("UTF-8");

		PersistenceManager pm = new MPersistenceManager(PMF.get().getPersistenceManager());
		Transaction tx = pm.currentTransaction();
		CommonDBManager acdbm=new CommonDBManager();
		ResultSet rs= null;
		try {
			tx.begin();

			TotDoc totDoc = pm.getObjectById(TotDoc.class, docID);

			//1. DB에 저장된 첨부파일의 총 크기를 가져 온다. by wonseok Lee 20170908
			int file_check_cnt = 0;
			int report_cnt = 0;
		    String speChar = "[^\uAC00-\uD7A3xfe0-9a-zA-Z\\s]";	//특수문자를 '_'로 변환하기 위한 변수
			StringBuilder sql = new StringBuilder(250);
			File[] attachFileList = null;
			String qryString = "";

			//LOG.debug("[선택한 reportIDArray 다음과 같다]["+reportIDArray.length+"]");

			//체크박스 선택한 reportID 축출을 위한 쿼리문 추가함 by wonseok Lee 20170915
			if (!(reportIDArray.length == 1 && reportIDArray[0].length() == 0)) {
				for(int i = 0; i < reportIDArray.length; i++){
					if(i==0) {
						if(reportIDArray.length == 1 ){
							qryString += " AND R.ID IN("+reportIDArray[i]+")";
							continue;
						}else{
							qryString += " AND R.ID IN("+reportIDArray[i]+",";
						}
					}else if(i == (reportIDArray.length-1)) {
						qryString += reportIDArray[i]+" )";
					}else {
						qryString += " "+reportIDArray[i]+",";
					}
				}
			}
			LOG.debug("[선택한 reportID는 다음과 같다]["+qryString+"]");

			sql.append(" SELECT COUNT(R.ID) AS REPORT_CNT, SUM(DECODE(FILE_CHECK,'Y',1,0)) AS FILE_CHECK_CNT");
			sql.append(" FROM MOUMI_TOT_REPORT R");
			sql.append(" WHERE 1=1");
			sql.append(qryString);
			sql.append(" AND (R.DOC_ID =? OR R.REP_DOC_ID=?)");
			sql.append(" AND R.DEL_TYPE='N'");
			sql.append(" AND (R.PRSS='6' OR R.PRSS='14') ");

			LOG.debug("sql ===== " + sql);

			rs= acdbm.execQuery(sql,docID,docID);

			if(rs.next()){
				report_cnt = rs.getInt(1);
				file_check_cnt = rs.getInt(2);
			}
			if(null != rs)rs.close();
			acdbm.pstmt.close();
			LOG.debug("report_cnt["+report_cnt+"]  file_check_cnt["+file_check_cnt+"]");

			long[] reportIDs 	= new long[report_cnt]; 		//제출ID
			String[] deptIDs 	= new String[report_cnt];	//부서ID
			String[] deptNames 	= new String[report_cnt];	//부서명ID
			String[] upperIDs 	= new String[report_cnt];	//상위부서ID
			String[] upperNames	= new String[report_cnt];	//상위부서명ID
			String[] organIDs 	= new String[report_cnt];	//organID
			String[] organNames = new String[report_cnt];	//organ명
			long[] repDocIDs 	= new long[report_cnt];     //docid

			String[] attacheFilePath = new String[report_cnt];


			//2. reportID를 가져온다
			sql.delete(0, sql.length());

			sql.append(" SELECT R.ID,");
			sql.append(" 		R.DEPT_ID,");
			sql.append(" 		D.NAME,");
			sql.append(" 		D.UPPER_DEPT,");
			sql.append(" 		(SELECT NAME FROM MOUMI_DEPT WHERE ID=D.UPPER_DEPT) AS UPPER_DEPT_NAME,");
			sql.append(" 		D.ORGAN, ");
			sql.append(" 		(SELECT NAME FROM MOUMI_DEPT WHERE ID=D.ORGAN) AS ORGAN_NAME,");
			sql.append(" 		R.DOC_ID, ");
			sql.append(" 		D.SEL_TYPE");
			sql.append(" FROM 	MOUMI_TOT_REPORT R,");
			sql.append(" 		MOUMI_DEPT D");
			sql.append(" WHERE 1=1 ");
			sql.append(qryString);
			sql.append(" AND (R.DOC_ID =? OR R.REP_DOC_ID=?) ");
			sql.append(" AND R.DEL_TYPE='N' ");
			sql.append(" AND (R.PRSS='6' OR R.PRSS='14')");
			sql.append(" AND R.DEPT_ID=D.ID  				") ;
			sql.append(" ORDER BY D.ORGAN , D.UPPER_DEPT, D.GRADE, D.FOUNDATION, D.NAME") ;


			LOG.debug("sql  >>>>>>>>>>>>>>>>>>> ["+sql+"]");
			rs= acdbm.execQuery(sql,docID,docID);
			for (int i = 0; rs.next(); i++) {
				reportIDs[i]	= rs.getInt(1);
				deptIDs[i] 		= rs.getString(2);
				deptNames[i]	= rs.getString(3);
				upperIDs[i] 	= rs.getString(4);
				upperNames[i] 	= rs.getString(5);
				organIDs[i] 	= rs.getString(6);
				organNames[i] 	= rs.getString(7);
				repDocIDs[i] 	= rs.getLong(8);
			}
			if(null != rs) rs.close();
			acdbm.pstmt.close();

			List<TotReport> totReports = new ArrayList<TotReport>();
	        List<TotReport> totReportsComp = new ArrayList<TotReport>();
	        List<TotReport> esbTotReportsComp = new ArrayList<TotReport>();
	        List<TotReport> totReportsNote = new ArrayList<TotReport>();

			if (reportIDArray.length == 1 && reportIDArray[0].length() == 0) {

            	totReportsComp = totDoc.getPrssReports(pm, TotReportProcess.COMP, "", null,null);  //6:제출완료
             	esbTotReportsComp = totDoc.getRecursivePrssReports(pm, totReportsComp, null); //연계자료 조회
             	totReportsNote = totDoc.getPrssReports(pm, TotReportProcess.NOTE, "", null,null);  //14:회수요청

            	for (TotReport report : esbTotReportsComp) {
                	totReports.add(report);
               	}
              	for (TotReport report : totReportsNote) {
                	totReports.add(report);
             	}
			} else {
				LOG.debug("reportIDArray.length == 1 && reportIDArray[0].length()["+reportIDArray.length+"]  ["+ reportIDArray[0].length() +"]" );

				for (String reportIDStr : reportIDArray) {
					Long reportID = MLong.parseLong(reportIDStr);
					totReports.add(pm.getObjectById(TotReport.class, reportID));
				}
			}


			for (TotReport report : totReports) {
				if(null == report.getAttachmentsPath() || "".equals(report.getAttachmentsPath())){  //파일패스가 없으면 디비에서 찾아라
					for (Entry<String, List<Byte>> entry : report.getAttachments().entrySet()) {
						MDept mDept = report.getDept(pm);
						MDept mDeptOrgan = mDept.getOrgan(pm);
						while (mDept != null && !mDept.isDocUnit())
							mDept = mDept.getUpperDept(pm);
						StringBuilder entryGrName = new StringBuilder(mDeptOrgan.getName().replaceAll(speChar, "_"));
						StringBuilder entryName = new StringBuilder(mDept.getName().replaceAll(speChar, "_"));

						Byte[] content = entry.getValue().toArray(new Byte[]{});
						byte[] contentPri = new byte[content.length];
						for (int i = 0; i < content.length; i++)
							contentPri[i] = content[i];
						BufferedInputStream origin = new BufferedInputStream(new ByteArrayInputStream(contentPri), BUFFER);

		                try {
		                	if (setUserName) {
		                		entryName.append("_").append(report.getOwnerName(pm));
		                	}

		                    entryGrName.append("_").append(entryName.append("_").append(entry.getKey()));
		                    ZipArchiveEntry zipEntry = new ZipArchiveEntry(entryGrName.toString());
		                    out.putArchiveEntry(zipEntry);
		                    int count = 0;
		                    while ((count = origin.read(data, 0, BUFFER)) != -1) {
		                    	out.write(data, 0, count);
		                    }
		                 } catch (IOException e) {
		                	e.printStackTrace();
		                 } finally {
		                 	origin.close();
		                 }
					}
				}else{	//파일패스가 있으면...서버에서 찾아라.
					long report_id = report.getId();

					int jj = 0;
					for(int i=0; i < reportIDs.length; i++){
						if(reportIDs[i] == report_id){
							jj = i;
							break;
						}
					}

       	    		attacheFilePath[jj] = MoumiConfig.getFileDirectory()+"/"+repDocIDs[jj]+"/"+reportIDs[jj]+"/"+deptIDs[jj];
       	    		LOG.debug("attacheFilePath[i]  .["+attacheFilePath[jj]+"]");
			       	File attachePath = new File(attacheFilePath[jj]);

			       	//디렉토리가 있고
			       	if(attachePath.exists()){
			       		attachFileList = attachePath.listFiles();
			       		//파일이 있으면
			       		if(attachFileList!=null) {
				       		for(int ii=0; ii< attachFileList.length; ii++) {
								StringBuilder entryGrName = new StringBuilder(organNames[jj].replaceAll(speChar, "_"));
								StringBuilder entryName = new StringBuilder(deptNames[jj].replaceAll(speChar, "_"));
				            	if (setUserName){
				            		//entryName.append("_").append(report.(pm));
				            	}

			                    entryGrName.append("_").append(entryName);
			                    ZipArchiveEntry zipEntry = new ZipArchiveEntry(entryGrName.toString()+"_"+attachFileList[ii].getName());
				                out.putArchiveEntry(zipEntry);

				                if(attachFileList[ii].exists()){
				                	FileInputStream fis = null;
							        try {
										fis = new FileInputStream(attachFileList[ii]);
							            byte[] content = new byte[(int) attachFileList[ii].length()];
							            fis.read(content);	//파일의 내용을 읽는다.
							            out.write(content);	//읽은 파일내용을 압축파일에 쓴다.
							            fis.close();
							        } catch (IOException e) {
							           	e.printStackTrace();
							    		out.flush();
							    		out.close();
							        } finally {
							        	fis.close(); //파일실행을 끊어줌.// 예외 발생 여부와 상관없이 자원 해제
							        }
				    			}
				       		}
			       		}

				    }
	       	    }
			}
			tx.rollback();

			if (out.getCount() > 0)
				out.closeArchiveEntry();
			out.flush();
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try{
		   		if(null != rs) rs.close();
		   	}catch(Exception e1){
		   		e1.printStackTrace();
		   	}
			acdbm.execClose();
			if (tx.isActive())
				tx.rollback();
			pm.close();
		}
	}

}
