package cn.com.qmth.examcloud.core.questions.service.util;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
import cn.com.qmth.examcloud.commons.exception.StatusException;
import cn.com.qmth.examcloud.core.questions.base.FileDisposeUtil;
import cn.com.qmth.examcloud.core.questions.base.dto.ExportTempDataDto;
import cn.com.qmth.examcloud.core.questions.base.enums.ExamFileType;
import cn.com.qmth.examcloud.core.questions.base.enums.ExportTemplateType;
import cn.com.qmth.examcloud.core.questions.base.json.JOption;
import cn.com.qmth.examcloud.core.questions.base.json.JOptionDto;
import cn.com.qmth.examcloud.core.questions.base.json.JSection;
import cn.com.qmth.examcloud.core.questions.base.json.JsonImportUtil;
import cn.com.qmth.examcloud.core.questions.base.json.SectionElement;
import cn.com.qmth.examcloud.core.questions.dao.entity.QuesOption;
import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperDetailExp;
import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperDetailUnitExp;
import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperExp;
import cn.com.qmth.examcloud.support.filestorage.FileStorageUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import sun.misc.BASE64Decoder;

public class ExportPaperUtil {

    private static final Logger log = LoggerFactory.getLogger(ExportPaperUtil.class);
    
    private static final String docxBasePath=FileDisposeUtil.getDocxBasePath();
    
    private static final int docImageSzie=12700;

    private static final String DOCX_SUFFIX = ".docx";

    private static final String ZIP_SUFFIX = ".zip";

    public static final String QUESOPS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    public static final String ELEMENT_TYPE_RID = "imageId";

    public static final String ELEMENT_TYPE_TEXT = "text";

    public static final String ELEMENT_TYPE_IMG = "image";
    
    public static final String ELEMENT_TYPE_DOCTAG = "doctag";

    private static final String ENCODING = "UTF-8";

    private static Configuration config;

    private static Template docSection;
    
    private static Template examReamarkDocument;

    private static Template questionSection;

    private static Template paperQuesOps;

    private static Template contentTypes;

    private static Template document;

    private static Template documentRel;

    private static Pattern heightRex = Pattern.compile("height:([\\s\\S]*?)px");

    private static Pattern widthRex = Pattern.compile("width:([\\s\\S]*?)px");
    static {

        config = new Configuration(Configuration.VERSION_2_3_25);
        // 设置编码
        config.setDefaultEncoding(ENCODING);
        // 设置ftl模板路径
        config.setClassForTemplateLoading(JsonImportUtil.class, "/export_template/origin_paper/");

        try {
            questionSection = config.getTemplate("question_section.ftl", ENCODING);
            contentTypes = config.getTemplate("content_types.ftl", ENCODING);
            document = config.getTemplate("document.ftl", ENCODING);
            documentRel = config.getTemplate("document_rel.ftl", ENCODING);
            paperQuesOps = config.getTemplate("question_options.ftl", ENCODING);
            docSection=config.getTemplate("doc_section.ftl", ENCODING);
            examReamarkDocument=config.getTemplate("exam_reamark_document.ftl", ENCODING);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }
    //考试说明word文件
    public static File createExamRemarkDocFile(File directory,String fileName,String html) throws IOException {
     // doc固定源文件目录
        File docxDir = new File(docxBasePath);
        // 将要生成的doc源文件目录
        File docxTargetDir = new File(directory.getAbsolutePath() + "/docx/");
        docxTargetDir.mkdir();
        // 复制docx基础文件
        FileUtils.copyDirectory(docxDir, docxTargetDir);
        // 处理并生成doc源文件
        disposeExamRemark(docxTargetDir, html);
        // 压缩docx源文件
        File zipfile = new File(
                docxTargetDir.getParentFile().getAbsolutePath() + File.separator + fileName + ZIP_SUFFIX);
        FileDisposeUtil.createZip(docxTargetDir.getAbsolutePath(), zipfile.getAbsolutePath());
        File docfile = new File(
                docxTargetDir.getParentFile().getAbsolutePath() + File.separator + fileName + DOCX_SUFFIX);
        // 修改压缩包为doc文件
        zipfile.renameTo(docfile);
        FileUtils.deleteDirectory(docxTargetDir);
        return docfile;
    }
    private static void disposeExamRemark(File docxTargetDir, String html) throws IOException {
        ExportTempDataDto dto = new ExportTempDataDto();
        List<JSection> slist=null;
        if (StringUtils.isNotBlank(html)) {
            slist = getSections(html);
            if (slist != null && slist.size() > 0) {
                htmlToDoc(slist, dto);
            }
        }
        // content-type
        writeContentType(docxTargetDir, dto);
        // document
        writeExamRemarkDocument(docxTargetDir, slist);
        // document-rel
        writeDocumentRel(docxTargetDir, dto);
        // image file
        writeImage(docxTargetDir, dto);
    }
    private static void writeExamRemarkDocument(File docxTargetDir, List<JSection> slist) throws IOException {
        StringWriter result = null;
        try {
            result = new StringWriter();
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("sections", slist);
            examReamarkDocument.process(map, result);
        } catch (Exception e) {
            throw new ExamCloudRuntimeException(e);
        }
        File file = new File(docxTargetDir.getAbsolutePath() + "/word/document.xml");
        FileUtils.writeStringToFile(file, result.toString(), "utf-8");
    }
    // 考试试卷
    public static File createPaperDocFile(Long rootOrgId, PaperExp paperExp, File directory, String paperfileName,
            ExportTemplateType templateType) throws Exception {
        DocxTemplateBean docxTemplate = ExportTemplateUtil.getDocxTemplateBean(rootOrgId, templateType);
        // doc固定源文件目录
        File docxDir = new File(docxTemplate.getDocxPath());
        // 将要生成的doc源文件目录
        File docxTargetDir = new File(directory.getAbsolutePath() + File.separator + "docx" + File.separator);
        docxTargetDir.mkdir();
        // 复制docx基础文件
        FileUtils.copyDirectory(docxDir, docxTargetDir);
        // 处理并生成doc源文件
        disposePaperDoc(docxTargetDir, paperExp, docxTemplate);
        // 压缩docx源文件
        File zipfile = new File(docxTargetDir.getParentFile().getAbsolutePath() + File.separator
                + paperfileName.substring(0, paperfileName.lastIndexOf(".")) + ZIP_SUFFIX);
        FileDisposeUtil.createZip(docxTargetDir.getAbsolutePath(), zipfile.getAbsolutePath());
        File docfile = new File(docxTargetDir.getParentFile().getAbsolutePath() + File.separator + paperfileName);
        // 修改压缩包为doc文件
        zipfile.renameTo(docfile);
        FileUtils.deleteDirectory(docxTargetDir);
        return docfile;

    }

    private static void disposePaperDoc(File docxTargetDir, PaperExp paperExp, DocxTemplateBean docxTemplate)
            throws IOException {
        ExportTempDataDto dto = new ExportTempDataDto();
        disposePaperExamRemark(paperExp, dto);
        if (paperExp.getPaperDetails() != null && paperExp.getPaperDetails().size() > 0) {
            for (PaperDetailExp pde : paperExp.getPaperDetails()) {
                if (pde.getPaperDetailUnits() != null && pde.getPaperDetailUnits().size() > 0) {
                    for (PaperDetailUnitExp pdue : pde.getPaperDetailUnits()) {
                        Question qes = pdue.getQuestion();
                        disposePaperQuestion(qes, dto);
                    }
                }
            }
        }
        
        // header
        writePaperHeader(docxTargetDir, paperExp.getCourseName(), docxTemplate);
        // content-type
        writePaperContentType(docxTargetDir, dto, docxTemplate);
        // document
        writePaperDocument(docxTargetDir, paperExp, docxTemplate);
        // document-rel
        writePaperDocumentRel(docxTargetDir, dto, docxTemplate);
        // image file
        writeImage(docxTargetDir, dto);
    }
    
    private static void writePaperHeader(File docxTargetDir, String courseName, DocxTemplateBean docxTemplate)
            throws IOException {
        Template head=docxTemplate.getHeader();
        if(head==null) {
            return;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("courseName", courseName);
        StringWriter result = null;
        try {
            result = new StringWriter();
            head.process(map, result);
        } catch (Exception e) {
            throw new ExamCloudRuntimeException(e);
        }
        File file = new File(docxTargetDir.getAbsolutePath() + "/word/header1.xml");
        FileUtils.writeStringToFile(file, result.toString(), "utf-8");
    }

    private static void writePaperDocument(File docxTargetDir, PaperExp paperExp, DocxTemplateBean docxTemplate)
            throws IOException {
        String doc = getPaperDocumentDoc(paperExp, docxTemplate);
        File file = new File(docxTargetDir.getAbsolutePath() + "/word/document.xml");
        FileUtils.writeStringToFile(file, doc, "utf-8");
    }

    private static String getPaperDocumentDoc(Object paperExp, DocxTemplateBean docxTemplate) {
        StringWriter result = null;
        try {
            result = new StringWriter();
            docxTemplate.getDocument().process(paperExp, result);
            return result.toString();
        } catch (Exception e) {
            throw new ExamCloudRuntimeException(e);
        }
    }

    private static void writePaperContentType(File docxTargetDir, ExportTempDataDto dto, DocxTemplateBean docxTemplate)
            throws IOException {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("images", dto.getTypes());
        String doc = getPaperContentTypesDoc(map, docxTemplate);
        File file = new File(docxTargetDir.getAbsolutePath() + "/[Content_Types].xml");
        FileUtils.writeStringToFile(file, doc, "utf-8");
    }

    private static String getPaperContentTypesDoc(Map<String, Object> map, DocxTemplateBean docxTemplate) {
        StringWriter result = null;
        try {
            result = new StringWriter();
            docxTemplate.getContentTypes().process(map, result);
            return result.toString();
        } catch (Exception e) {
            throw new ExamCloudRuntimeException(e);
        }
    }

    private static void writePaperDocumentRel(File docxTargetDir, ExportTempDataDto dto, DocxTemplateBean docxTemplate)
            throws IOException {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("images", dto.getImages());
        String doc = getPaperDocumentRelDoc(map, docxTemplate);
        File file = new File(docxTargetDir.getAbsolutePath() + "/word/_rels/document.xml.rels");
        FileUtils.writeStringToFile(file, doc, "utf-8");
    }

    private static String getPaperDocumentRelDoc(Map<String, Object> map, DocxTemplateBean docxTemplate) {
        StringWriter result = null;
        try {
            result = new StringWriter();
            docxTemplate.getDocumentRels().process(map, result);
            return result.toString();
        } catch (Exception e) {
            throw new ExamCloudRuntimeException(e);
        }
    }

    // 原始试卷
    public static File createOriginPaperDocFile(PaperExp paperExp, File directory) throws IOException{
        // doc固定源文件目录
        File docxDir = new File(docxBasePath);
        // 将要生成的doc源文件目录
        File docxTargetDir = new File(directory.getAbsolutePath() + "/docx/");
        docxTargetDir.mkdir();
        // 复制docx基础文件
        FileUtils.copyDirectory(docxDir, docxTargetDir);
        // 处理并生成doc源文件
        dispose(docxTargetDir, paperExp);
        // 压缩docx源文件
        String paperfileName = paperExp.getName() + "_" + paperExp.getCourseNo() + "_" + ExamFileType.PAPER.getName();
        File zipfile = new File(
                docxTargetDir.getParentFile().getAbsolutePath() + File.separator + paperfileName + ZIP_SUFFIX);
        FileDisposeUtil.createZip(docxTargetDir.getAbsolutePath(), zipfile.getAbsolutePath());
        File docfile = new File(
                docxTargetDir.getParentFile().getAbsolutePath() + File.separator + paperfileName + DOCX_SUFFIX);
        // 修改压缩包为doc文件
        zipfile.renameTo(docfile);
        FileUtils.deleteDirectory(docxTargetDir);
        return docfile;

    }


    private static List<JSection> getSections(String html) {
        return getSections(html, false);
    }

    private static List<JSection> getSections(String html, boolean diposeFillBlank) {
        if (StringUtils.isBlank(html)) {
            return getEmptySections();
        }
        html = html.trim();
        if (!html.startsWith("<p>")) {
            html = "<p>" + html + "</p>";
        }
        List<JSection> ss = new ArrayList<JSection>();
        Document doc = Jsoup.parse(html);
        Element b = doc.body();
        for (Node e : b.childNodes()) {
            if ("p".equals(e.nodeName()) && e.childNodeSize() > 0) {
                JSection s = new JSection();
                List<SectionElement> ses = new ArrayList<SectionElement>();
                s.setElements(ses);
                for (Node ce : e.childNodes()) {
                    getSectionElement(ce, ses, diposeFillBlank);
                }
                ss.add(s);
            }
        }
        return ss;

    }
    
    private static List<JSection> getEmptySections(){
    	List<JSection> ss = new ArrayList<JSection>();
    	JSection s = new JSection();
        List<SectionElement> ses = new ArrayList<SectionElement>();
        s.setElements(ses);
        SectionElement se=new SectionElement();
        se.setType(ELEMENT_TYPE_TEXT);
        se.setValue("");
        ses.add(se);
        ss.add(s);
        return ss;
    }

    private static void getSectionElement(Node ce, List<SectionElement> ses, boolean diposeFillBlank) {
        if ("span".equals(ce.nodeName()) && ce.childNodeSize() > 0) {
            for (Node e : ce.childNodes()) {
                getSectionElement(e, ses, diposeFillBlank);
            }
        } else {
            if (ce instanceof TextNode) {
            	SectionElement se = new SectionElement();
                TextNode tn = (TextNode) ce;
                se.setType(ELEMENT_TYPE_TEXT);
                String text = tn.text();
                if (diposeFillBlank) {
                    text = text.replaceAll("###", "______").replaceAll("##", "______");
                }
                text = text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\u0000", " ");
                se.setValue(text);
                ses.add(se);
            } else if (ce instanceof Element) {
            	SectionElement se = new SectionElement();
                if ("img".equals(ce.nodeName())) {
                    se.setType(ELEMENT_TYPE_IMG);
                    se.setValue(ce.attr("src"));
                    setImageSize(se, ce);
                } else if ("br".equals(ce.nodeName())) {
                    se.setType(ELEMENT_TYPE_DOCTAG);
                    se.setValue("<w:r w:rsidRPr=\"003A4B1C\"><w:br/></w:r>");
                } else {
                    Element el = (Element) ce;
                    se.setType(ELEMENT_TYPE_TEXT);
                    se.setValue(el.text());
                }
                ses.add(se);
            }
        }
    }

    private static int getWidth(Node ce) {
        int n = 0;
        String str = ce.attr("width");
        if (StringUtils.isNotBlank(str)) {
        	String sizeStr = str.replace("px", "");
        	if (StringUtils.isNotBlank(sizeStr)) {
        		try {
	        		return Integer.valueOf(sizeStr.trim()) * docImageSzie;
	        	} catch (NumberFormatException e) {
					log.warn("image width value is invalid");
					return 0;
				}
        	}
        }
        String style = ce.attr("style");
        if (StringUtils.isNotBlank(style)) {
            Matcher m = widthRex.matcher(style);
            if (m.find()) {
            	String size=m.group(1).trim();
            	if(StringUtils.isNotBlank(size)) {
            		try {
	            		return Integer.valueOf(size) * docImageSzie;
	            	} catch (NumberFormatException e) {
						log.warn("image style width value is invalid");
						return 0;
					}
            	}
            }
        }
        return n;
    }

    private static int getHeight(Node ce) {
        int n = 0;
        String str = ce.attr("height");
        if (StringUtils.isNotBlank(str)) {
        	String sizeStr = str.replace("px", "");
        	if (StringUtils.isNotBlank(sizeStr)) {
        		try {
					return Integer.valueOf(sizeStr.trim()) * docImageSzie;
				} catch (NumberFormatException e) {
					log.error("image height value is invalid");
					return 0;
				}
        	}
        }
        String style = ce.attr("style");
        if (StringUtils.isNotBlank(style)) {
            Matcher m = heightRex.matcher(style);
            if (m.find()) {
            	String size=m.group(1).trim();
            	if(StringUtils.isNotBlank(size)) {
            		try {
	            		return Integer.valueOf(size) * docImageSzie;
	            	} catch (NumberFormatException e) {
						log.error("image style height value is invalid");
						return 0;
					}
            	}
            }
        }
        return n;
    }

    private static void dispose(File docxTargetDir, PaperExp paperExp) throws IOException {
        ExportTempDataDto dto = new ExportTempDataDto();
        if (paperExp.getPaperDetails() != null && paperExp.getPaperDetails().size() > 0) {
            for (PaperDetailExp pde : paperExp.getPaperDetails()) {
                dto.setMainNum(dto.getMainNum() + 1);
                if (pde.getPaperDetailUnits() != null && pde.getPaperDetailUnits().size() > 0) {
                    for (PaperDetailUnitExp pdue : pde.getPaperDetailUnits()) {
                        Question qes = pdue.getQuestion();
                        disposeQuestion(qes, dto);
                    }
                }
            }
        }
        // content-type
        writeContentType(docxTargetDir, dto);
        // document
        writeDocument(docxTargetDir, paperExp);
        // document-rel
        writeDocumentRel(docxTargetDir, dto);
        // image file
        writeImage(docxTargetDir, dto);
    }

    private static void writeImage(File docxTargetDir, ExportTempDataDto dto) throws IOException {
        for (SectionElement se : dto.getImages()) {
            File file = new File(docxTargetDir.getAbsolutePath() + "/word/media/image" + se.getParam().getIndex() + "."
                    + se.getParam().getType());
            String src = se.getValue();
            if (src.contains("data:image")) {//base64图片
            	src = src.substring(src.indexOf(",") + 1);
                BASE64Decoder decoder = new BASE64Decoder();
                byte[] bytes = decoder.decodeBuffer(src);
                FileUtils.writeByteArrayToFile(file, bytes);
            }else {//网络图片
            	FileStorageUtil.saveUrlAs(src, file);
            }
        }
    }

    private static void writeDocumentRel(File docxTargetDir, ExportTempDataDto dto) throws IOException {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("images", dto.getImages());
        StringWriter result = null;
        try {
            result = new StringWriter();
            documentRel.process(map, result);
        } catch (Exception e) {
            throw new ExamCloudRuntimeException(e);
        }
        File file = new File(docxTargetDir.getAbsolutePath() + "/word/_rels/document.xml.rels");
        FileUtils.writeStringToFile(file, result.toString(), "utf-8");
    }

    private static void writeContentType(File docxTargetDir, ExportTempDataDto dto) throws IOException {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("images", dto.getTypes());
        StringWriter result = null;
        try {
            result = new StringWriter();
            contentTypes.process(map, result);
        } catch (Exception e) {
            throw new ExamCloudRuntimeException(e);
        }
        File file = new File(docxTargetDir.getAbsolutePath() + "/[Content_Types].xml");
        FileUtils.writeStringToFile(file, result.toString(), "utf-8");
    }

    private static void writeDocument(File docxTargetDir, PaperExp paperExp) throws IOException {
        StringWriter result = null;
        try {
            result = new StringWriter();
            document.process(paperExp, result);
        } catch (Exception e) {
            throw new ExamCloudRuntimeException(e);
        }
        File file = new File(docxTargetDir.getAbsolutePath() + "/word/document.xml");
        FileUtils.writeStringToFile(file, result.toString(), "utf-8");
    }

    private static void disposeQuestion(Question qes, ExportTempDataDto dto) {
        if (qes != null) {
            //处理题干
            List<JSection> slist1 = getSections(qes.getQuesBody(),false);
            if (slist1 == null||slist1.size()==0) {
                slist1=new ArrayList<JSection>();
                JSection sec=new JSection();
                List<SectionElement> ses=new ArrayList<SectionElement>();
                sec.setElements(ses);
                slist1.add(sec);
            }
            if (qes.getSubQuestions() == null || qes.getSubQuestions().size() == 0) {// 套题题干不加题号
                SectionElement se = new SectionElement();
                se.setType(ELEMENT_TYPE_TEXT);
                se.setValue(qes.getQuestionSeq() + ".");
                slist1.get(0).getElements().add(0, se);
            }

            htmlToDoc(slist1, dto);
            qes.setQuesBodyWord(getQuestionDoc(slist1));

            //处理选项
            if (qes.getQuesOptions() != null && qes.getQuesOptions().size() > 0) {
                int index = 0;
                for (QuesOption qo : qes.getQuesOptions()) {
                    List<JSection> slist2 = getSections(qo.getOptionBody());
                    if (slist2 != null && slist2.size() > 0) {
                        SectionElement se = new SectionElement();
                        se.setType(ELEMENT_TYPE_TEXT);
                        se.setValue(QUESOPS.charAt(index) + ".");
                        index++;
                        slist2.get(0).getElements().add(0, se);
                        htmlToDoc(slist2, dto);
                        qo.setOptionBodyWord(getQuestionDoc(slist2));
                    }

                }
            }
            
            //处理答案
            List<JSection> slist3 = getSections(qes.getQuesAnswer());
            if (slist3 == null||slist3.size()==0) {
                slist3=new ArrayList<JSection>();
                JSection sec=new JSection();
                List<SectionElement> ses=new ArrayList<SectionElement>();
                sec.setElements(ses);
                slist3.add(sec);
            }
            SectionElement se = new SectionElement();
            se.setType(ELEMENT_TYPE_TEXT);
            se.setValue("[答案]:");
            slist3.get(0).getElements().add(0, se);
            htmlToDoc(slist3, dto);
            qes.setQuesAnswerWord(getQuestionDoc(slist3));

            if (qes.getSubQuestions() != null && qes.getSubQuestions().size() > 0) {
                for (Question sunqes : qes.getSubQuestions()) {
                    disposeQuestion(sunqes, dto);// 递归处理套题
                }
            }
        }
    }

    private static void disposePaperExamRemark(PaperExp paperExp, ExportTempDataDto dto) {
        if (StringUtils.isNotBlank(paperExp.getExamRemark())) {
            List<JSection> slist = getSections(paperExp.getExamRemark());
            if (slist != null && slist.size() > 0) {
                htmlToDoc(slist, dto);
                paperExp.setExamRemarkWord(getSectionDoc(slist));
            }
        }
        if(paperExp.getExamRemarkWord()==null) {
            paperExp.setExamRemarkWord("");
        }
    }

    private static void disposePaperQuestion(Question qes, ExportTempDataDto dto) {
        if (qes != null) {
            //处理题干
            List<JSection> slist1 = getSections(qes.getQuesBody(),true);
            if (slist1 == null||slist1.size()==0) {
                slist1=new ArrayList<JSection>();
                JSection sec=new JSection();
                List<SectionElement> ses=new ArrayList<SectionElement>();
                sec.setElements(ses);
                slist1.add(sec);
            }
            if (qes.getSubQuestions() == null || qes.getSubQuestions().size() == 0) {// 套题题干不加题号
                SectionElement se = new SectionElement();
                se.setType(ELEMENT_TYPE_TEXT);
                se.setValue(qes.getQuestionSeq() + ".");
                slist1.get(0).getElements().add(0, se);
            }

            htmlToDoc(slist1, dto);
            qes.setQuesBodyWord(getQuestionDoc(slist1));

            //处理选项
            if (qes.getQuesOptions() != null && qes.getQuesOptions().size() > 0) {
                int index = 0;
                JOptionDto joDto = new JOptionDto();
                List<JOption> ops = new ArrayList<JOption>();
                joDto.setOptions(ops);
                for (QuesOption qo : qes.getQuesOptions()) {
                    List<JSection> slist2 = getSections(qo.getOptionBody());
                    if (slist2 != null && slist2.size() > 0) {
                        SectionElement se = new SectionElement();
                        se.setType(ELEMENT_TYPE_TEXT);
                        se.setValue(QUESOPS.charAt(index) + ".");
                        index++;
                        slist2.get(0).getElements().add(0, se);
                        htmlToDoc(slist2, dto);
                        JOption jo = new JOption();
                        jo.setJsections(slist2);
                        ops.add(jo);
                    }
                }
                disposeQuesOptions(joDto);// 处理选项列数
                qes.setQuesOptionsWord(getPaperQuestionDoc(joDto.getOptions()));
            }
            
            //处理答案
            if (qes.getSubQuestions() == null || qes.getSubQuestions().size() == 0) {// 套题不加答案及序号
                List<JSection> slist3 = getSections(qes.getQuesAnswer());
                if (slist3 == null||slist3.size()==0) {
                    slist3=new ArrayList<JSection>();
                    JSection sec=new JSection();
                    List<SectionElement> ses=new ArrayList<SectionElement>();
                    sec.setElements(ses);
                    slist3.add(sec);
                }
                SectionElement se = new SectionElement();
                se.setType(ELEMENT_TYPE_TEXT);
                se.setValue(qes.getQuestionSeq() + ".");
                slist3.get(0).getElements().add(0, se);

                htmlToDoc(slist3, dto);
                qes.setQuesAnswerWord(getQuestionDoc(slist3));
            }
            

            if (qes.getSubQuestions() != null && qes.getSubQuestions().size() > 0) {
                for (Question sunqes : qes.getSubQuestions()) {
                    disposePaperQuestion(sunqes, dto);// 递归处理套题
                }
            }
        }
    }

    private static void disposeQuesOptions(JOptionDto joDto) {
        for (JOption jo : joDto.getOptions()) {
            if (jo.getJsections().size() > 1) {
                return;
            }
            for (JSection js : jo.getJsections()) {
                for (SectionElement se : js.getElements()) {
                    if (ELEMENT_TYPE_IMG.equals(se.getType())) {
                        return;
                    }
                }
            }
        }
        int columns = 4;
        for (JOption jo : joDto.getOptions()) {
            JSection js = jo.getJsections().get(0);
            for (SectionElement se : js.getElements()) {
                String text = StringEscapeUtils.unescapeXml(se.getValue());
                if (text.length() > 20) {
                    return;
                } else if (text.length() > 9) {
                    columns = 2;
                }
            }

        }
        formatList(joDto, columns);
    }

    private static void formatList(JOptionDto joDto, int size) {
        List<JOption> ret = new ArrayList<JOption>();
        int count = 0;
        for (int i = 0; i < joDto.getOptions().size(); i++) {
            if (count == 0) {
                JOption jo = new JOption();
                jo.setCols(size);
                List<JSection> temlist = new ArrayList<JSection>();
                jo.setJsections(temlist);
                JSection js = new JSection();
                List<SectionElement> ses = new ArrayList<SectionElement>();
                js.setElements(ses);
                temlist.add(js);
                ret.add(jo);
            }
            if (count != 0) {
                joDto.getOptions().get(i).getJsections().get(0).getElements().get(0).getParam().setTab(true);
            }
            for (SectionElement se : joDto.getOptions().get(i).getJsections().get(0).getElements()) {
                ret.get(ret.size() - 1).getJsections().get(0).getElements().add(se);
            }
            count++;
            if (count == size) {
                count = 0;
            }
        }
        joDto.setOptions(ret);
    }

    private static void htmlToDoc(List<JSection> slist, ExportTempDataDto dto) {
        for (JSection js : slist) {
            for (SectionElement se : js.getElements()) {
                if (ELEMENT_TYPE_IMG.equals(se.getType())) {
                    dto.setIndex(dto.getIndex() + 1);
                    se.getParam().setIndex(dto.getIndex());
                    se.getParam().setRid(ELEMENT_TYPE_RID + dto.getIndex());
                    se.getParam().setType(getImageType(se.getValue()));
                    dto.getTypes().add(se.getParam().getType());
                    dto.getImages().add(se);
                }
            }
        }
    }
    private static String getImageType(String src) {
    	if(src.contains("data:image")) {
    		return src.substring(11, src.indexOf(";"));
    	}else {
    		try {
				URL url=new URL(src);
				return url.getPath().substring(url.getPath().lastIndexOf(".")+1);
			} catch (MalformedURLException e) {
				throw new StatusException("1000", "图片链接格式错误:"+src);
			}
    	}
    }
    private static String getSectionDoc(List<JSection> sections) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("sections", sections);
        StringWriter result = null;
        try {
            result = new StringWriter();
            docSection.process(map, result);
            return result.toString();
        } catch (Exception e) {
            throw new ExamCloudRuntimeException(e);
        }
    }

    private static String getQuestionDoc(List<JSection> sections) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("sections", sections);
        StringWriter result = null;
        try {
            result = new StringWriter();
            questionSection.process(map, result);
            return result.toString();
        } catch (Exception e) {
            throw new ExamCloudRuntimeException(e);
        }
    }

    private static String getPaperQuestionDoc(List<JOption> options) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("options", options);
        StringWriter result = null;
        try {
            result = new StringWriter();
            paperQuesOps.process(map, result);
            return result.toString();
        } catch (Exception e) {
            throw new ExamCloudRuntimeException(e);
        }
    }
    
    
    private static void setImageSize(SectionElement imageEle,Node ce) {
    	int width=getWidth(ce);
    	int height=getHeight(ce);
    	if(width<100||height<100) {
    		String base64=imageEle.getValue();
    		if (base64.contains("data:image")) {
                base64 = base64.substring(base64.indexOf(",") + 1);
            }
            BASE64Decoder decoder = new BASE64Decoder();
    		
    		InputStream is = null;
            try {
            	byte[] bytes = decoder.decodeBuffer(base64);
                is = new ByteArrayInputStream(bytes);
                BufferedImage image = ImageIO.read(is);
                width=image.getWidth()* docImageSzie;
                height=image.getHeight()* docImageSzie;
            }catch (IOException e) {
            	log.error(e.getMessage(), e);
            } finally {
                if (is != null) {
                    try {
						is.close();
					} catch (IOException e) {
						log.error(e.getMessage(), e);
					}
                }
            }
    	}
    	imageEle.getParam().setHeight(height);
    	imageEle.getParam().setWidth(width);
		
	}

}
