package com.qmth.qrzk.repository.user.service.impl;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;

import net.sf.json.JSONObject;

import org.apache.commons.io.IOUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.qmth.qrzk.repository.common.base.BaseDao;
import com.qmth.qrzk.repository.service.query.TaskQueryParams;
import com.qmth.qrzk.repository.task.TaskBatch;
import com.qmth.qrzk.repository.user.model.Attachment;
import com.qmth.qrzk.repository.user.model.Course;
import com.qmth.qrzk.repository.user.model.InputQuesTask;
import com.qmth.qrzk.repository.user.model.InputQuesTaskUserLink;
import com.qmth.qrzk.repository.user.model.Question;
import com.qmth.qrzk.repository.user.model.QuestionOption;
import com.qmth.qrzk.repository.user.model.User;
import com.qmth.qrzk.repository.utils.CipherUtil;
import com.qmth.qrzk.repository.utils.Consts;
import com.qmth.qrzk.repository.utils.DateHelper;
import com.qmth.qrzk.repository.utils.General;

@Service
public class InputQuesTaskServiceImpl {
	
	@Autowired private BaseDao dao;
	
	@Autowired
	private CourseServiceImpl courseService;
	
	@Autowired
	private BookServiceImpl bookService;
	
	@Autowired
	private TaskBatchImpl taskBatchService;
	
	public List<InputQuesTask> getInputQuesTasksWithStatByBatchId(int batchId){
		List<InputQuesTask> tasks = dao.getList("getInputQuesTasksByBatchId", batchId);
		Map<Integer,Object[]> inputerDataMap = new LinkedHashMap<Integer, Object[]>();
		for(InputQuesTask t:tasks){
			t.setCourseCode(t.getCourse().getCode());
			t.setCourseName(t.getCourse().getName());
			String inputers = "";
			int inputNum = 0;
			for(InputQuesTaskUserLink ul:t.getInputerLinks()){
				Map<String,Object> param = new HashMap<String, Object>();
				param.put("courseId", t.getCourseId());
				param.put("inputerId", ul.getInputerId());
				param.put("planStartTime", t.getPlanStartTime());
				param.put("planEndTime", t.getPlanEndTime());
				int statInfo2 = dao.getObject("statInputerJobByCourseIdAndInputerId", param);
				inputNum += statInfo2;
				Object[] inputerData = inputerDataMap.get(ul.getInputerId());
				if(inputerData == null){
					inputerData = new Object[2];
					inputerDataMap.put(ul.getInputerId(), inputerData);
					inputerData[0] = Consts.UserMap.get(ul.getInputerId()).getName();
					inputerData[1] = 0;
				}
				inputerData[1] = (Integer)inputerData[1] + statInfo2;
				inputers = inputers + Consts.UserMap.get(ul.getInputerId()).getName() + "(" + statInfo2 + ")，";
			}
			if(inputers.length() > 0){
				inputers = inputers.substring(0, inputers.length() - 1);
			}
			t.setInputNum(inputNum);
			t.setInputers(inputers);
		}
		{
			InputQuesTask total = new InputQuesTask();
			total.setCourseCode("总计");
			total.setCourseName("");
			String inputers = "";
			for(Object[] inputerData:inputerDataMap.values()){
				inputers = inputers + inputerData[0] + "(" + inputerData[1] + ")，";
			}if(inputers.length() > 0){
				inputers = inputers.substring(0, inputers.length() - 1);
			}
			total.setInputers(inputers);
			for(InputQuesTask job:tasks){
				total.setInputNum(total.getInputNum() + job.getInputNum());
			}
			tasks.add(total);
		}
		return tasks;
	}
	
	public List<InputQuesTask> queryTodoInputQuesTasks(TaskQueryParams params){
		return dao.getPagerList("queryTodoInputQuesTasks", params);
	}
	
	public InputQuesTask getInputQuesTaskById(int taskId){
		InputQuesTask task = dao.get("getInputQuesTaskById", taskId);
		return task;
	}
	
	public InputQuesTask addInputQuesTask(InputQuesTask task,User curUser){
		TaskBatch taskBatch = taskBatchService.findById(task.getBatchId());
		task.setPlanStartTime(taskBatch.getPlanStartTime());
		task.setPlanEndTime(taskBatch.getPlanEndTime());
		
		task.setCreatedBy(curUser.getId());
		task.setCreatedTime(new Date());
		task.setUpdatedBy(curUser.getId());
		task.setUpdatedTime(new Date());
		dao.insert("addInputQuesTask", task);
		for(InputQuesTaskUserLink userLink:task.getInputerLinks()){
			userLink.setInputQuesTaskId(task.getId());
			dao.insert("addInputQuesTaskUserLink", userLink);
		}
		return getInputQuesTaskById(task.getId());
	}
	
	public void deleteInputQuesTasks(int[] taskIds){
		for(int id:taskIds){
			dao.delete("delInputQuesTaskUserLinksByTaskId", id);
			dao.delete("delInputQuesTaskById", id);
		}
	}

	public void deleteInputQuesTaskById(int id){
		dao.delete("delInputQuesTaskUserLinksByTaskId", id);
		dao.delete("delInputQuesTaskById", id);
	}
	
	public void updateInputQuesTask(InputQuesTask task){
		dao.update("updateInputQuesTask", task);
		updateInputQuesTaskUserLinks(task);
	}
	
	public void updateInputQuesTaskUserLinks(InputQuesTask task){
		dao.delete("delInputQuesTaskUserLinksByTaskId", task.getId());
		for(InputQuesTaskUserLink userLink:task.getInputerLinks()){
			userLink.setInputQuesTaskId(task.getId());
			dao.insert("addInputQuesTaskUserLink", userLink);
		}
	}
	
	public void saveImportData(int batchId,List<InputQuesTask> list,JSONObject object,User curUser){
		TaskBatch taskBatch = taskBatchService.findById(batchId);
		List<String> loginList=new ArrayList<String>();
		Map<String,User> tempMap=new HashMap<String,User>();
		for(Map.Entry<Integer, User> entry : Consts.UserMap.entrySet()){
			tempMap.put(entry.getValue().getLoginName(), entry.getValue());
			loginList.add(entry.getValue().getLoginName());
		}
		boolean existsCourseCode=true;
		boolean isSameCourseCode=false;
		int i=1;
		Set<String> courseCodeSet = new HashSet<String>();
		
		List<InputQuesTask> paperTasks = dao.getList("getInputQuesTasksByBatchId", batchId);
		
		//把当前批次下所有的课程代码和任务单编号放到map里面
		for(InputQuesTask pp:paperTasks){
			Course course=courseService.findById(pp.getCourseId());
			courseCodeSet.add(course.getCode());
		}
		
		for(InputQuesTask at:list){
			
			Course course=courseService.findByCode(at.getCourseCode());
			//校验课程代码是否在系统中存在
			if(course==null){
				existsCourseCode=false;
				break;
			}
			//校验课程代码是否在批次中存在
			if(courseCodeSet.contains(at.getCourseCode())){
				isSameCourseCode=true;
				break;
			}
			
			String[] inputerArr = at.getInputers().split(",|，");
			for(String inputerLoginName:inputerArr){
				if(!loginList.contains(inputerLoginName)){
					//返回前端用户登录名不存在
					object.put("result", "fail");
					object.put("lineNum",i );
					object.put("msg", "录入员[" + inputerLoginName + "]用户信息不存在");
					return;
				}
				InputQuesTaskUserLink userLink = new InputQuesTaskUserLink();
				userLink.setInputerId(tempMap.get(inputerLoginName).getId());
				at.getInputerLinks().add(userLink);
			}
			i++;
		}
		
		if(!existsCourseCode){
			object.put("result", "fail");
			object.put("lineNum",i);
			object.put("msg", "导入的课程代码在基础库中不存在");
		}else if(isSameCourseCode){	//导入的信息中存在相同的courseCode
			object.put("result", "fail");
			object.put("lineNum",i);
			object.put("msg", "导入的文件该批次下存在相同的课程编号");
		}else{
			for(InputQuesTask at:list){
				Course course=courseService.findByCode(at.getCourseCode());
				at.setCourseId(course.getId());
				at.setBatchId(batchId);
				at.setPlanStartTime(taskBatch.getPlanStartTime());
				at.setPlanEndTime(taskBatch.getPlanEndTime());
				
				at.setCreatedBy(curUser.getId());
				at.setCreatedTime(new Date());
				at.setUpdatedBy(curUser.getId());
				at.setUpdatedTime(new Date());
				dao.insert("addInputQuesTask", at);
				for(InputQuesTaskUserLink userLink:at.getInputerLinks()){
					userLink.setInputQuesTaskId(at.getId());
					dao.insert("addInputQuesTaskUserLink", userLink);
				}
			}
			if(object.isEmpty()){
				object.put("result", "success");
				object.put("successNum", list.size());
				object.put("msg", "导入成功!");
			}
		}
	}

	@SuppressWarnings("unchecked")
	public List<Map<String,Object>> statInputQuestByCourse(Date startDate,Date endDate){
		Map<String,Date> param = new HashMap<String, Date>();
		param.put("startDate", startDate);
		param.put("endDate", endDate);
		List<Map<String, Object>> statInputData = dao.getList("statInputQuestByCourse",param);
		List<Map<String, Object>> statAuditData = dao.getList("statAuditInputQuestByCourse",param);
		Map<String,Integer> statAuditMap = new HashMap<String, Integer>();
		for(Map<String, Object> stat:statAuditData){
			statAuditMap.put(stat.get("courseCode") + "-" + stat.get("statusCode"), General.toInteger(stat.get("num"), 0));
		}
		Map<String,Map<String, Object>> resultMap = new LinkedHashMap<String,Map<String, Object>>();
		int draftNum = 0;
		int approvedNum = 0;
		int rejectedNum = 0;
		int finalApprovedNum = 0;
		int finalRejectedNum = 0;
		int total = 0;
		for(Map<String, Object> stat:statInputData){
			String courseCode = (String) stat.get("courseCode");
			String courseName = (String) stat.get("courseName");
			int num = General.toInteger(stat.get("num"), 0);
			Map<String, Object> result = resultMap.get(courseCode);
			if(result == null){
				result = new HashMap<String, Object>();
				result.put("courseCode", courseCode);
				result.put("courseName", courseName);
				int draftNumTmp = General.toInteger(statAuditMap.get(courseCode + "-QUESTION_DRAFT"), 0);
				int approvedNumTmp = General.toInteger(statAuditMap.get(courseCode + "-QUESTION_APPROVED"), 0);
				int rejectedNumTmp = General.toInteger(statAuditMap.get(courseCode + "-QUESTION_REJECTED"), 0);
				int finalApprovedNumTmp = General.toInteger(statAuditMap.get(courseCode + "-QUESTION_FINAL_APPROVED"), 0);
				int finalRejectedNumTmp = General.toInteger(statAuditMap.get(courseCode + "-QUESTION_FINAL_REJECTED"), 0);
				draftNum += draftNumTmp;
				approvedNum += approvedNumTmp;
				rejectedNum += rejectedNumTmp;
				finalApprovedNum += finalApprovedNumTmp;
				finalRejectedNum += finalRejectedNumTmp;
				result.put("draftNum", draftNumTmp);
				result.put("approvedNum", approvedNumTmp);
				result.put("rejectedNum", rejectedNumTmp);
				result.put("finalApprovedNum", finalApprovedNumTmp);
				result.put("finalRejectedNum", finalRejectedNumTmp);
				resultMap.put(courseCode,result);
			}
			int sum = General.toInteger(result.get("sum"), 0) + num;
			total += num;
			result.put("sum", sum);
			List<Map<String, Object>> typeNums = (List<Map<String, Object>>) result.get("typeNums");
			if(typeNums == null){
				typeNums = new ArrayList<Map<String,Object>>();
				result.put("typeNums", typeNums);
			}
			typeNums.add(stat);
		}
		List<Map<String,Object>> results = new ArrayList<Map<String,Object>>(resultMap.values());
		Map<String, Object> totalResult = new HashMap<String, Object>();
		totalResult.put("courseCode","总计：");
		totalResult.put("draftNum", draftNum);
		totalResult.put("approvedNum", approvedNum);
		totalResult.put("rejectedNum", rejectedNum);
		totalResult.put("finalApprovedNum", finalApprovedNum);
		totalResult.put("finalRejectedNum", finalRejectedNum);
		totalResult.put("sum", total);
		List<Map<String, Object>> typeNums = new ArrayList<Map<String,Object>>();
		typeNums.add(new HashMap<String, Object>());
		totalResult.put("typeNums", typeNums);
		results.add(totalResult);
		return results;
	}
	
	@SuppressWarnings("unchecked")
	public List<Map<String,Object>> statInputQuestByInputer(Date startDate,Date endDate){
		Map<String,Date> param = new HashMap<String, Date>();
		param.put("startDate", startDate);
		param.put("endDate", endDate);
		List<Map<String, Object>> statData = dao.getList("statInputQuestByInputer",param);
		Set<String> dateStrSet = new HashSet<String>();
		for(Map<String, Object> stat:statData){
			dateStrSet.add((String)stat.get("createdTime"));
		}
		List<String> dateStrList = new ArrayList<String>(dateStrSet);
		Collections.sort(dateStrList, new Comparator<String>() {
			@Override
			public int compare(String o1, String o2) {
				return o1.compareTo(o2);
			}
		});
		List<Map<String,Object>> results = new ArrayList<Map<String,Object>>();
		Map<String,Object> thMap = new HashMap<String, Object>();
		thMap.put("dateStrList", dateStrList);
		results.add(thMap);

		Map<String,Integer> dataStrNumMapForTotal = new LinkedHashMap<String, Integer>();
		for(String str:(List<String>)thMap.get("dateStrList")){
			dataStrNumMapForTotal.put(str, null);
		}
		
		Map<Integer,Map<String, Object>> resultMap = new LinkedHashMap<Integer,Map<String, Object>>();
		int total = 0;
		for(Map<String, Object> stat:statData){
			int userId = General.toInteger(stat.get("userId"), 0);
			String userName = (String) stat.get("userName");
			String createdTime = (String) stat.get("createdTime");
			int num = General.toInteger(stat.get("num"), 0);
			Map<String, Object> result = resultMap.get(userId);
			if(result == null){
				result = new HashMap<String, Object>();
				result.put("userName", userName);
				Map<String,Integer> dataStrNumMap = new LinkedHashMap<String, Integer>();
				for(String str:(List<String>)thMap.get("dateStrList")){
					dataStrNumMap.put(str, null);
				}
				result.put("dataStrNumMap", dataStrNumMap);
				resultMap.put(userId,result);
			}
			Map<String,Integer> dataStrNumMap = (Map<String,Integer>)result.get("dataStrNumMap");
			dataStrNumMap.put(createdTime, num);
			int sum = General.toInteger(result.get("sum"), 0) + num;
			dataStrNumMapForTotal.put(createdTime, General.toInteger(dataStrNumMapForTotal.get(createdTime), 0) + num);
			total += num;
			result.put("sum", sum);
		}
		results.addAll(resultMap.values());
		Map<String, Object> totalResult = new HashMap<String, Object>();
		totalResult.put("userName","总计：");
		totalResult.put("sum", total);
		totalResult.put("dataStrNumMap", dataStrNumMapForTotal);
		results.add(totalResult);
		return results;
	}
	
	@SuppressWarnings("unchecked")
	public Attachment exportInputStat(Date startDate,Date endDate,User curUser){
		String title = "时间段：" + DateHelper.toLongString(startDate) + "至" + DateHelper.toLongString(endDate) + "。\r\n报表生成时间：" + DateHelper.getNow();
		List<Map<String,Object>> statByCourse = statInputQuestByCourse(startDate, endDate);
		List<Map<String,Object>> statByInputer = statInputQuestByInputer(startDate, endDate);
		HSSFWorkbook workbook = new HSSFWorkbook();
		// 生成一个字体
	    HSSFFont normalFont1 = workbook.createFont();
	    normalFont1.setColor(HSSFColor.BLACK.index);
		
		// 生成一个字体
	    HSSFFont normalFont2 = workbook.createFont();
	    normalFont2.setColor(HSSFColor.BLACK.index);
	    normalFont2.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
	    
	    //标题边框，粗体，居中对齐，不可换行
  		HSSFCellStyle border_th = workbook.createCellStyle();
  		border_th.setBorderTop(HSSFCellStyle.BORDER_THIN);
  		border_th.setBorderBottom(HSSFCellStyle.BORDER_THIN);
  		border_th.setBorderLeft(HSSFCellStyle.BORDER_THIN);
  		border_th.setBorderRight(HSSFCellStyle.BORDER_THIN);
  		border_th.setAlignment(HSSFCellStyle.ALIGN_CENTER);
  		border_th.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
  		border_th.setWrapText(false);
  		border_th.setFont(normalFont2);
	    
	    //普通字符边框，居左对齐，可换行
  		HSSFCellStyle border_str = workbook.createCellStyle();
  		border_str.setBorderTop(HSSFCellStyle.BORDER_THIN);
  		border_str.setBorderBottom(HSSFCellStyle.BORDER_THIN);
  		border_str.setBorderLeft(HSSFCellStyle.BORDER_THIN);
  		border_str.setBorderRight(HSSFCellStyle.BORDER_THIN);
  		border_str.setAlignment(HSSFCellStyle.ALIGN_LEFT);
  		border_str.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
  		border_str.setWrapText(true);
  		border_str.setFont(normalFont1);
	    
	    //数值边框，居右对齐，不可换行
  		HSSFCellStyle border_num = workbook.createCellStyle();
  		border_num.setBorderTop(HSSFCellStyle.BORDER_THIN);
  		border_num.setBorderBottom(HSSFCellStyle.BORDER_THIN);
  		border_num.setBorderLeft(HSSFCellStyle.BORDER_THIN);
  		border_num.setBorderRight(HSSFCellStyle.BORDER_THIN);
  		border_num.setAlignment(HSSFCellStyle.ALIGN_RIGHT);
  		border_num.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
  		border_num.setWrapText(false);
  		border_num.setFont(normalFont1);
	    
  		{
			HSSFSheet sheetByCourse = workbook.createSheet("按课程统计");
			sheetByCourse.setColumnWidth(0, 3000);
			sheetByCourse.setColumnWidth(1, 5000);
			sheetByCourse.setColumnWidth(2, 4000);
			sheetByCourse.setColumnWidth(3, 2000);
			sheetByCourse.setColumnWidth(4, 2000);
			sheetByCourse.setColumnWidth(5, 3000);
			sheetByCourse.setColumnWidth(6, 3000);
			sheetByCourse.setColumnWidth(7, 3000);
			sheetByCourse.setColumnWidth(8, 3000);
			sheetByCourse.setColumnWidth(9, 2000);
			{
				HSSFRow row0 = sheetByCourse.createRow(0);
				row0.setHeight((short)600);
				sheetByCourse.addMergedRegion(new CellRangeAddress(0, 0, 0, 9));
				HSSFCell ce = row0.createCell(0);
		        ce.setCellValue("按课程统计结果，" + title);
		        ce.setCellStyle(border_str);
		        row0.createCell(1).setCellStyle(border_str);
		        row0.createCell(2).setCellStyle(border_str);
		        row0.createCell(3).setCellStyle(border_str);
		        row0.createCell(4).setCellStyle(border_str);
		        row0.createCell(5).setCellStyle(border_str);
		        row0.createCell(6).setCellStyle(border_str);
		        row0.createCell(7).setCellStyle(border_str);
		        row0.createCell(8).setCellStyle(border_str);
		        row0.createCell(9).setCellStyle(border_str);
			}
			{
				HSSFRow row1 = sheetByCourse.createRow(1);
				row1.setHeight((short)300);
				HSSFCell ce0 = row1.createCell(0);
		        ce0.setCellValue("课程代码");
		        ce0.setCellStyle(border_th);
				HSSFCell ce1 = row1.createCell(1);
		        ce1.setCellValue("课程名称");
		        ce1.setCellStyle(border_th);
				HSSFCell ce2 = row1.createCell(2);
		        ce2.setCellValue("题型名称");
		        ce2.setCellStyle(border_th);
				HSSFCell ce3 = row1.createCell(3);
		        ce3.setCellValue("数量");
		        ce3.setCellStyle(border_th);
				HSSFCell ce4 = row1.createCell(4);
		        ce4.setCellValue("草稿");
		        ce4.setCellStyle(border_th);
				HSSFCell ce5 = row1.createCell(5);
		        ce5.setCellValue("审核通过");
		        ce5.setCellStyle(border_th);
				HSSFCell ce6 = row1.createCell(6);
		        ce6.setCellValue("审核拒绝");
		        ce6.setCellStyle(border_th);
				HSSFCell ce7 = row1.createCell(7);
		        ce7.setCellValue("终审通过");
		        ce7.setCellStyle(border_th);
				HSSFCell ce8 = row1.createCell(8);
		        ce8.setCellValue("终审拒绝");
		        ce8.setCellStyle(border_th);
				HSSFCell ce9 = row1.createCell(9);
		        ce9.setCellValue("总计");
		        ce9.setCellStyle(border_th);
			}
			{
				int index = 0;
				for(int i=0;i<statByCourse.size();i++){
					Map<String,Object> stat = statByCourse.get(i);
			        List<Map<String, Object>> typeNums = (List<Map<String, Object>>) stat.get("typeNums");
			        for(int j=0;j<typeNums.size();j++){
			        	Map<String, Object> typeNum = typeNums.get(j);
			        	
						HSSFRow row = sheetByCourse.createRow(2+index);
						
						if(j == 0){
							sheetByCourse.addMergedRegion(new CellRangeAddress(2+index, 2+index + typeNums.size()-1, 0, 0));
							sheetByCourse.addMergedRegion(new CellRangeAddress(2+index, 2+index + typeNums.size()-1, 1, 1));
							sheetByCourse.addMergedRegion(new CellRangeAddress(2+index, 2+index + typeNums.size()-1, 4, 4));
							sheetByCourse.addMergedRegion(new CellRangeAddress(2+index, 2+index + typeNums.size()-1, 5, 5));
							sheetByCourse.addMergedRegion(new CellRangeAddress(2+index, 2+index + typeNums.size()-1, 6, 6));
							sheetByCourse.addMergedRegion(new CellRangeAddress(2+index, 2+index + typeNums.size()-1, 7, 7));
							sheetByCourse.addMergedRegion(new CellRangeAddress(2+index, 2+index + typeNums.size()-1, 8, 8));
							sheetByCourse.addMergedRegion(new CellRangeAddress(2+index, 2+index + typeNums.size()-1, 9, 9));
						}
						if(i == statByCourse.size()-1){
							sheetByCourse.addMergedRegion(new CellRangeAddress(2+index, 2+index, 0, 3));
						}
						HSSFCell ce0 = row.createCell(0);
						HSSFCell ce1 = row.createCell(1);
						HSSFCell ce4 = row.createCell(4);
						HSSFCell ce5 = row.createCell(5);
						HSSFCell ce6 = row.createCell(6);
						HSSFCell ce7 = row.createCell(7);
						HSSFCell ce8 = row.createCell(8);
						HSSFCell ce9 = row.createCell(9);
						if(j == 0){
							ce0.setCellValue(General.null2String(stat.get("courseCode")));
							if(i < statByCourse.size()-1){
								ce1.setCellValue(General.null2String(stat.get("courseName")));
							}
							ce4.setCellValue(General.toInteger(stat.get("draftNum"), 0));
							ce5.setCellValue(General.toInteger(stat.get("approvedNum"), 0));
							ce6.setCellValue(General.toInteger(stat.get("rejectedNum"), 0));
							ce7.setCellValue(General.toInteger(stat.get("finalApprovedNum"), 0));
							ce8.setCellValue(General.toInteger(stat.get("finalRejectedNum"), 0));
							ce9.setCellValue(General.toInteger(stat.get("sum"), 0));
						}
				        ce0.setCellStyle(border_str);
				        ce1.setCellStyle(border_str);
				        ce4.setCellStyle(border_num);
				        ce5.setCellStyle(border_num);
				        ce6.setCellStyle(border_num);
				        ce7.setCellStyle(border_num);
				        ce8.setCellStyle(border_num);
				        ce9.setCellStyle(border_num);
				        
						HSSFCell ce2 = row.createCell(2);
						if(i < statByCourse.size()-1){
							ce2.setCellValue(General.null2String(typeNum.get("typeName")));
						}
				        ce2.setCellStyle(border_str);
						HSSFCell ce3 = row.createCell(3);
						if(i < statByCourse.size()-1){
							ce3.setCellValue(General.toInteger(typeNum.get("num"), 0));
						}
				        ce3.setCellStyle(border_num);
				        index++;
			        }
				}
			}
  		}
  		
  		{
			HSSFSheet sheetByInputer = workbook.createSheet("按录入员统计");
			Map<String,Object> first = statByInputer.get(0);
			List<String> dateStrList = (List<String>)first.get("dateStrList");
			
			sheetByInputer.setColumnWidth(0, 3000);
			for(int i=0;i<dateStrList.size();i++){
				sheetByInputer.setColumnWidth(1 + i, 3000);
			}
			sheetByInputer.setColumnWidth(1 + dateStrList.size(), 2000);
			{
				HSSFRow row0 = sheetByInputer.createRow(0);
				if(dateStrList.size() == 0){
					row0.setHeight((short)1600);
				}else if(dateStrList.size() == 1){
					row0.setHeight((short)1000);
				}else if(dateStrList.size() == 2 || dateStrList.size() == 3){
					row0.setHeight((short)850);
				}else{
					row0.setHeight((short)600);
				}
				sheetByInputer.addMergedRegion(new CellRangeAddress(0, 0, 0, 1 + dateStrList.size()));
				HSSFCell ce = row0.createCell(0);
		        ce.setCellValue("按录入员统计，" + title);
		        ce.setCellStyle(border_str);
		        row0.createCell(1).setCellStyle(border_str);
		        for(int i=0;i<=dateStrList.size();i++){
		        	row0.createCell(1+i).setCellStyle(border_str);
		        }
			}
			{
				HSSFRow row1 = sheetByInputer.createRow(1);
				row1.setHeight((short)300);
				HSSFCell ce0 = row1.createCell(0);
		        ce0.setCellValue("姓名");
		        ce0.setCellStyle(border_th);
		        for(int i=0;i<dateStrList.size();i++){
					HSSFCell ce1 = row1.createCell(1+i);
			        ce1.setCellValue(dateStrList.get(i));
			        ce1.setCellStyle(border_th);
		        }
				HSSFCell ce2 = row1.createCell(1+dateStrList.size());
		        ce2.setCellValue("总计");
		        ce2.setCellStyle(border_th);
			}
			{
				for(int i=1;i<statByInputer.size();i++){
					Map<String,Object> stat = statByInputer.get(i);
					HSSFRow row = sheetByInputer.createRow(1+i);
					HSSFCell ce0 = row.createCell(0);
					ce0.setCellValue((String)stat.get("userName"));
					ce0.setCellStyle(border_str);
					Map<String,Integer> dataStrNumMap = (Map<String,Integer>)stat.get("dataStrNumMap");
					int j=0;
					for(Integer num:dataStrNumMap.values()){
						HSSFCell ce1 = row.createCell(1+j);
						if(num == null){
							ce1.setCellValue("");
						}else{
							ce1.setCellValue(num);
						}
						ce1.setCellStyle(border_num);
						j++;
					}
					HSSFCell ce2 = row.createCell(1+dateStrList.size());
			        ce2.setCellValue(General.toInteger(stat.get("sum"),0));
			        ce2.setCellStyle(border_num);
				}
			}
  		}
		
		File xlsFile = General.newTmpFile();
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(xlsFile);
			workbook.write(fos);
		} catch (Exception e) {
			throw new RuntimeException("写入Excel数据到临时文件：" + xlsFile.getAbsolutePath() + "中失败，原因：" + e.getMessage(), e);
		} finally{
			General.close(fos);
		}
		File newFile = General.newAttFile();
		xlsFile.renameTo(newFile);
		Attachment att = new Attachment();
		att.setCreatedBy(curUser.getId());
		att.setOriginalName("题卡录入报表_" + DateHelper.getNow(DateHelper.shortSimpleDateFormatWithoutSplit) + ".xls");
		att.setCurName(newFile.getName());
		att.setFileLength(newFile.length());
		att.setStorePath(newFile.getAbsolutePath());
		att.setStatus(Consts.AttachmentStatus.DRAFT);
		dao.insert("addAttachment", att);
		return att;
	}
	
	public Attachment expInputTaskQuestions(int batchId,User curUser){
		Attachment zipAtt = null;
		TaskBatch tb = taskBatchService.findById(batchId);
		List<InputQuesTask> tasks = dao.getList("getInputQuesTasksByBatchId", batchId);
		List<Question> questions = new ArrayList<Question>();
		ExportInputQuestionBean bean = new ExportInputQuestionBean(questions,tb);
		for(InputQuesTask t:tasks){
			t.setCourseCode(t.getCourse().getCode());
			t.setCourseName(t.getCourse().getName());
			for(InputQuesTaskUserLink ul:t.getInputerLinks()){
				Map<String,Object> param = new HashMap<String, Object>();
				param.put("courseId", t.getCourseId());
				param.put("inputerId", ul.getInputerId());
				param.put("planStartTime", t.getPlanStartTime());
				param.put("planEndTime", t.getPlanEndTime());
				List<Question> quesListTmp = dao.getList("getQuestionsByCourseIdAndInputerId", param);
				questions.addAll(quesListTmp);
			}
		}
		
		FileOutputStream fos = null;
		ZipOutputStream zos = null;
		try {
            JAXBContext context = JAXBContext.newInstance(ExportInputQuestionBean.class);  
            Marshaller marshaller = context.createMarshaller();
            File newFile = General.newTmpFile();
            fos = new FileOutputStream(newFile);
            zos = new ZipOutputStream(fos);
            zos.putNextEntry(new ZipEntry("data.xml"));
            marshaller.marshal(bean, zos);
            zos.closeEntry();
        	General.close(zos);
        	General.close(fos);
        	zos = null;
        	fos = null;
        	File destFile = General.newAttFile();
        	CipherUtil.encrypt(newFile,destFile,Consts.key);
			
			zipAtt = new Attachment();
			zipAtt.setCreatedBy(curUser.getId());
			zipAtt.setOriginalName(tb.getName() + "录入试题_" + DateHelper.getNow(DateHelper.shortSimpleDateFormatWithoutSplit) + ".qrzktk");
			zipAtt.setCurName(destFile.getName());
			zipAtt.setFileLength(destFile.length());
			zipAtt.setStorePath(destFile.getAbsolutePath());
			zipAtt.setStatus(Consts.AttachmentStatus.DRAFT);
			dao.insert("addAttachment", zipAtt);
        } catch (Exception e) {
        	throw new RuntimeException("写入zip压缩文件失败，原因：" + e.getMessage(), e);
        } finally{
        	General.close(zos);
        	General.close(fos);
        }
		return zipAtt;
	}
	
	
	public Map<String,Integer> revertInputTaskQuestions(int attId,User curUser){
		Map<String,Integer> resultMap = new HashMap<String, Integer>();
		File decryptedFile = null;
		ZipFile zipFile = null;
		ExportInputQuestionBean dataBean = null;
		List<Question> newQuesList = new ArrayList<Question>();
		int successNum = 0;
		int ignoreNum = 0;
		try {
			Attachment att = dao.get("getAttachmentById", attId);
			try{
				decryptedFile = General.newTmpFile();
				CipherUtil.decrypt(new File(att.getStorePath()), decryptedFile, Consts.key);
				zipFile = new ZipFile(decryptedFile);
			} catch (ZipException e) {
				throw new RuntimeException("不可解析的题卡数据文件", e);
			} catch (IOException e) {
				throw new RuntimeException("不可解析的题卡数据文件", e);
			} catch (GeneralSecurityException e) {
				throw new RuntimeException("不可解析的题卡数据文件", e);
			}
			ZipEntry dataEntry = zipFile.getEntry("data.xml");
			if(dataEntry == null){
				throw new RuntimeException("不可解析的备份数据文件");
			}
			File dataFile1 = null;
			File dataFile2 = null;
			FileInputStream fis1 = null;
			FileOutputStream fos1 = null;
			FileInputStream fis2 = null;
			FileOutputStream fos2 = null;
			try{
				JAXBContext context = JAXBContext.newInstance(ExportInputQuestionBean.class);  
				Unmarshaller unmarshaller = context.createUnmarshaller();
				dataFile1 = General.newTmpFile();
				dataFile2 = General.newTmpFile();
				dataFile1.createNewFile();
				dataFile2.createNewFile();
				fos1 = new FileOutputStream(dataFile1);
				fos2 = new FileOutputStream(dataFile2);
				IOUtils.copyLarge(zipFile.getInputStream(dataEntry), fos1);
				fos1.flush();
				General.close(fos1);
				fos1 = null;
				fis1 = new FileInputStream(dataFile1); 
				char c = 0X16;//备份的xml文件里面的特殊字符，导致程序无法正常解析xml文件，现只能用空格来替换
				BufferedReader bufReader =
	                    new BufferedReader(
	                            new InputStreamReader(fis1 ,"UTF-8"));
				//采用分段字节流读取，防止内存溢出 update by songyue
				BufferedWriter bufWriter = new BufferedWriter(new OutputStreamWriter(fos2 ,"UTF-8"));
				char[] buf = new char[1024*100];
		        int len = 0 ;
		        while((len = bufReader.read(buf)) != -1){
		        	for(int i = 0;i < len;i++){
		        		if(buf[i] == c){
		        			buf[i] = ' ';
		        		}
		        	}
		        	bufWriter.write(buf, 0, len);
		        } 
//	            for (String tmp1 = null; (tmp1 = bufReader.readLine()) != null; tmp1 = null) {
//	            	fos2.write((tmp1.replace(c, ' ') + "\n").getBytes("UTF-8"));
//	            }
		        bufWriter.flush();
	            fos2.flush();
	            General.close(fos2);
	            fos2 = null;
	            General.close(bufReader);
	            General.close(bufWriter);
	            
//	            System.out.println(dataFile2.getAbsolutePath());
				
	            fis2 = new FileInputStream(dataFile2);
				dataBean = (ExportInputQuestionBean)unmarshaller.unmarshal(fis2);
			}catch(Exception e){
				throw new RuntimeException("不可解析的备份数据文件", e);
			}finally{
				General.close(fos1);
				General.close(fos2);
				General.close(fis1);
				General.close(fis2);
				General.delete(dataFile1);
				General.delete(dataFile2);
			}
			
			if(dataBean.getQuesList() != null){
				for(Question tmp : dataBean.getQuesList()){
					Question localQues = dao.get("findQuestionByGuid", tmp.getGuid());
					if(localQues == null){
						dao.insert("saveQuestion", tmp);
						if(tmp.getOptions() != null){
							for(QuestionOption opt:tmp.getOptions()){
								opt.setQuestionId(tmp.getId());
								dao.insert("saveOption", opt);
							}
						}
						successNum++;
						newQuesList.add(tmp);
					}else{
						ignoreNum++;
					}
				}
			}
			
			for(Question ques:newQuesList){
				Course course = dao.get("findCourseById", ques.getCourseId());
				ques.setQuestionNo(General.getNewQuestionNo(course.getCode()));
				dao.update("updateQuestionNo", ques);
			}
		}finally{
			General.close(zipFile);
		}
		resultMap.put("successNum", successNum);
		resultMap.put("ignoreNum", ignoreNum);
		return resultMap;
	}

}

@XmlRootElement
class ExportInputQuestionBean{
	private List<Question> quesList;
	
	private TaskBatch taskBatch;
	
	public ExportInputQuestionBean() {
		//do nothing
	}

	public ExportInputQuestionBean(List<Question> quesList, TaskBatch taskBatch) {
		super();
		this.quesList = quesList;
		this.taskBatch = taskBatch;
	}

	public List<Question> getQuesList() {
		return quesList;
	}

	public void setQuesList(List<Question> quesList) {
		this.quesList = quesList;
	}

	public TaskBatch getTaskBatch() {
		return taskBatch;
	}

	public void setTaskBatch(TaskBatch taskBatch) {
		this.taskBatch = taskBatch;
	}

}