package com.uas.report.service.impl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.sql.DataSource;

import org.apache.commons.io.output.FileWriterWithEncoding;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.dom4j.tree.DefaultElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.uas.report.SpecialProperties;
import com.uas.report.SystemProperties;
import com.uas.report.jasperreports.engine.export.CustomJRXlsExporter;
import com.uas.report.model.Master;
import com.uas.report.service.FileService;
import com.uas.report.service.PrintService;
import com.uas.report.util.CollectionUtils;
import com.uas.report.util.ExceptionUtils;
import com.uas.report.util.FileUtils;
import com.uas.report.util.MasterManager;
import com.uas.report.util.Platform;
import com.uas.report.util.ReportConstants;
import com.uas.report.util.ReportUtils;
import com.uas.report.util.StringUtils;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRRtfExporter;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.xml.JRXmlLoader;
import net.sf.jasperreports.export.ExporterInput;
import net.sf.jasperreports.export.OutputStreamExporterOutput;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;
import net.sf.jasperreports.export.SimplePdfReportConfiguration;
import net.sf.jasperreports.export.SimpleWriterExporterOutput;
import net.sf.jasperreports.export.WriterExporterOutput;

/**
 * 报表打印
 * 
 * @author sunyj
 * @since 2016年8月18日 下午2:58:28
 */
@Service
public class PrintServiceImpl implements PrintService {

	@Autowired
	private FileService fileService;

	@Autowired
	private SystemProperties systemProperties;

	@Autowired
	private SpecialProperties specialProperties;

	// @Autowired
	// private ResourceService resourceService;

	private Logger logger = LoggerFactory.getLogger(getClass());

	@Override
	public byte[] export(String userName, String profile, String reportName, String whereCondition,
			String otherParameters, String exportFileType)
			throws JRException, IOException, DocumentException, SQLException {
		Map<String, Object> result = print(userName, profile, reportName, whereCondition, otherParameters,
				exportFileType, null);
		if (!CollectionUtils.isEmpty(result)) {
			return (byte[]) result.get("data");
		}
		return null;
	}

	@Override
	public Map<String, Object> preview(String userName, String profile, String reportName, String whereCondition,
			String otherParameters, Integer pageIndex)
			throws JRException, IOException, DocumentException, SQLException {
		return print(userName, profile, reportName, whereCondition, otherParameters, null, pageIndex);
	}

	/**
	 * 输出报表的数据
	 * 
	 * @param userName
	 * @param profile
	 * @param reportName
	 * @param whereCondition
	 * @param otherParameters
	 * @param exportFileType
	 * @param pageIndex
	 * @return 页码pageSize:int，数据data:byte[]
	 * @throws JRException
	 * @throws IOException
	 * @throws DocumentException
	 * @throws SQLException
	 */
	private Map<String, Object> print(String userName, String profile, String reportName, String whereCondition,
			String otherParameters, String exportFileType, Integer pageIndex)
			throws JRException, IOException, DocumentException, SQLException {
		// TODO 重新实现jasperserver接口
		// try {
		// resourceService.syncResources(userName);
		// } catch (URISyntaxException | IOException e) {
		// throw new ReportException(e).setDetailedMessage(e);
		// }

		DataSource dataSource = MasterManager.getDataSource(userName, profile);
		if (dataSource == null) {
			throw new SQLException("获取数据源失败");
		}

		String masterOfJrxml = getMasterOfJrxml(userName, reportName);
		String jrxmlFilePath = fileService.getJrxmlFilePath(masterOfJrxml, reportName);

		// 向报表模板传递参数：报表路径、where条件、其他参数
		Map<String, Object> parameters = new HashMap<>();
		parameters.put(ReportConstants.PARAMETER_REPORT_DIR, fileService.getMasterPath(masterOfJrxml));
		if (!StringUtils.isEmpty(whereCondition)) {
			parameters.put(ReportConstants.PARAMETER_WHERE_CONDITION, whereCondition);
		}

		// 不为空，并且去除空格后的长度大于2（不为{}）
		if (!StringUtils.isEmpty(otherParameters) && otherParameters.replace(" ", "").length() > 2) {
			parameters.putAll(JSONObject.parseObject(otherParameters));
		}

		Connection connection = null;
		try {
			logger.info("dataSource.getConnection..." + userName);
			connection = dataSource.getConnection();
			logger.info("dataSource.getConnection done..." + userName);

			String jasperFilePath = maybeCompileJrxmlFile(jrxmlFilePath, otherParameters, connection);

			Map<String, Object> result = new HashMap<>();
			byte[] data = null;
			// 从数据库获取数据填充报表
			JasperPrint jasperPrint = null;
			ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
			// exportFileType导出文件的格式不为空，表示是导出，并非预览
			if (!StringUtils.isEmpty(exportFileType)) {
				logger.info("export fillReport...");
				boolean customCellStyle = false;
				// 只导出数据
				if (exportFileType.equals(ReportConstants.FILE_TYPE_EXCEL_DATA)) {
					// 需自定义单元格格式
					customCellStyle = true;
					JasperDesign jasperDesign = JRXmlLoader.load(jrxmlFilePath);
					// 移除模板中多余元素
					removeUnusedElements(jasperDesign);
					exportFileType = ReportConstants.FILE_TYPE_EXCEL;
					JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
					jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, connection);

				} else if (exportFileType.equals(ReportConstants.FILE_TYPE_WORD)) {
					// 导出word时需要对行距等进行调整
					InputStream inputStream = new ByteArrayInputStream(
							modifyLineSpacing(jrxmlFilePath).getBytes("UTF-8"));
					JasperReport jasperReport = JasperCompileManager.compileReport(inputStream);
					jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, connection);
					inputStream.close();
				} else {
					jasperPrint = JasperFillManager.fillReport(jasperFilePath, parameters, connection);
				}

				if (exportFileType.equals(ReportConstants.FILE_TYPE_EXCEL)) {
					exportReportToXls(jasperPrint, outputStream, customCellStyle);
				} else if (exportFileType.equals(ReportConstants.FILE_TYPE_WORD)) {
					exportReportToDoc(jasperPrint, outputStream);
				} else {
					exportReportToPdf(jasperPrint, outputStream, pageIndex);
				}
				logger.info("export fillReport done...");
				data = outputStream.toByteArray();
				outputStream.close();
			}
			// 报表预览，则直接输出pdf，并且也许需要分页
			else {
				logger.info("preview fillReport...");
				jasperPrint = JasperFillManager.fillReport(jasperFilePath, parameters, connection);
				exportReportToPdf(jasperPrint, outputStream, pageIndex);
				logger.info("preview fillReport done...");
				data = outputStream.toByteArray();
				outputStream.close();
				result.put("pageSize", jasperPrint.getPages().size());
			}
			result.put("data", data);
			return result;
		} finally {
			if (connection != null) {
				connection.close();
			}
		}
	}

	/**
	 * 可能需要编译报表模板文件
	 * 
	 * @param jrxmlFilePath
	 *            报表模板文件
	 * @param otherParameters
	 * @param connection
	 * @return 编译后的jasper文件路径
	 * @throws IOException
	 * @throws SQLException
	 * @throws DocumentException
	 */
	private String maybeCompileJrxmlFile(String jrxmlFilePath, String otherParameters, Connection connection)
			throws IOException, DocumentException, SQLException {
		if (StringUtils.isEmpty(jrxmlFilePath)) {
			logger.error("参数不能为空：" + jrxmlFilePath);
			return null;
		}
		File jrxmlFile = new File(jrxmlFilePath);
		// 报表模板不存在
		if (!jrxmlFile.exists()) {
			// 替换windows下路径中的双反斜杠为单斜杠
			throw new FileNotFoundException("报表模板不存在");
		}

		// 首先解析jrxml文件，检查是否引用子报表，如果是，先（递归）编译子报表
		List<String> subJrxmlFilePaths = getSubJrxmlFilePath(jrxmlFilePath);
		for (String subJrxmlFilePath : subJrxmlFilePaths) {
			maybeCompileJrxmlFile(subJrxmlFilePath, otherParameters, connection);
		}

		String jasperFilePath = jrxmlFilePath.replace(".jrxml", ".jasper");
		// 报表模板编译后的文件
		File jasperFile = new File(jasperFilePath);
		try {
			// 报表模板未编译过
			if (!jasperFile.exists()) {
				logger.info("正在编译报表模板... " + jrxmlFilePath);
				compileReportToFile(jrxmlFilePath, jasperFilePath, otherParameters, connection);
			}
			// 如果在编译之后，报表模板有更改过 ，重新编译
			else if (jrxmlFile.lastModified() > jasperFile.lastModified()) {
				logger.info("正在重新编译报表模板... " + jrxmlFilePath);
				compileReportToFile(jrxmlFilePath, jasperFilePath, otherParameters, connection);
			}
		} catch (JRException e) {
			throw new IllegalStateException("编译报表模板失败: " + jrxmlFilePath + " " + ExceptionUtils.getDetailedMessage(e));
		}
		return jasperFilePath;
	}

	/**
	 * 获取报表模板所引用的子报表路径
	 * 
	 * @param jrxmlFilePath
	 * @return
	 * @throws DocumentException
	 */
	private List<String> getSubJrxmlFilePath(String jrxmlFilePath) throws DocumentException {
		List<String> subJrxmlFilePaths = new ArrayList<>();
		SAXReader saxReader = new SAXReader();
		File jrxmlFile = new File(jrxmlFilePath);
		Document document = saxReader.read(jrxmlFile);
		@SuppressWarnings("unchecked")
		// 解析模板中subreportExpression元素
		List<Node> elements = document.selectNodes("//*[name()='subreportExpression']");
		for (Node element : elements) {
			// 格式为$P{REPORT_DIR} + "/jrxml/FreeClaimQT.jasper"
			String text = element.getText();
			int beginIndex = text.indexOf("/jrxml/");
			int endIndex = text.indexOf(".jasper");
			if (beginIndex < 0 || endIndex < 0) {
				throw new IllegalStateException("嵌套报表源码解析失败：" + jrxmlFile.getName() + "，子报表引用格式错误：" + text);
			}
			beginIndex += "/jrxml/".length();
			subJrxmlFilePaths.add(jrxmlFile.getParent() + "/" + text.substring(beginIndex, endIndex) + ".jrxml");
		}
		return subJrxmlFilePaths;
	}

	/**
	 * 编译jrxml报表模板为jasper文件
	 * 
	 * @param jrxmlFilePath
	 *            模板文件
	 * @param jasperFilePath
	 *            编译后的文件
	 * @param otherParameters
	 * @param connection
	 *            数据库连接
	 * @throws JRException
	 * @throws IOException
	 * @throws FileNotFoundException
	 * @throws DocumentException
	 * @throws SQLException
	 */
	private void compileReportToFile(String jrxmlFilePath, String jasperFilePath, String otherParameters,
			Connection connection)
			throws JRException, FileNotFoundException, IOException, DocumentException, SQLException {
		replaceFont(jrxmlFilePath);
		processFields(jrxmlFilePath, otherParameters, connection);
		JasperCompileManager.compileReportToFile(jrxmlFilePath, jasperFilePath);
	}

	/**
	 * 处理模板中的field（与数据库中列名进行比较，删除表中无对应列名的field）
	 * 
	 * @param jrxmlFilePath
	 * @param otherParameters
	 * @param connection
	 * @throws IOException
	 * @throws DocumentException
	 * @throws SQLException
	 */
	private void processFields(String jrxmlFilePath, String otherParameters, Connection connection)
			throws IOException, DocumentException, SQLException {
		XMLWriter xmlWriter = null;
		try {
			SAXReader saxReader = new SAXReader();
			Document document = saxReader.read(new File(jrxmlFilePath));
			Element rootElement = document.getRootElement();
			// 查询语句
			Element queryStringElement = rootElement.element("queryString");
			String queryString = queryStringElement.getText();
			// 如果查询语句中含有WHERE_CONDITION参数，需将其替换掉
			if (queryString.contains("$P!{WHERE_CONDITION}")) {
				queryString = queryString.replace("$P!{WHERE_CONDITION}", "where rownum = 0");
			}
			// 如果查询语句中含有where条件，则可能有用到一些参数，需将其替换掉
			else if (queryString.toUpperCase().contains("WHERE")) {
				queryString = queryString.substring(0, queryString.toUpperCase().indexOf("WHERE")) + "where rownum = 0";
			}
			queryString = replaceOtherParameters(queryString, otherParameters);
			List<String> columnNames = getColumnNames(connection, queryString);
			if (CollectionUtils.isEmpty(columnNames)) {
				throw new SQLException("未查询到任何列：" + queryString);
			}
			Set<String> usedFields = getUsedFields(jrxmlFilePath);
			// 指定的field
			@SuppressWarnings("unchecked")
			List<Element> elements = rootElement.elements("field");
			boolean needModifying = false;
			for (Element element : elements) {
				String columnName = element.attribute("name").getText();
				// 如果指定的Field在当前帐套的表中不存在，或者在模板中并未实际使用，则删除该Field
				if (!columnNames.contains(columnName.toUpperCase()) || !usedFields.contains(columnName.toUpperCase())) {
					needModifying = true;
					rootElement.remove(element);
					logger.info("Removed... " + columnName);
				}
			}
			// 如果需要修改，则重新写入模板文件
			if (needModifying) {
				xmlWriter = new XMLWriter(new FileWriterWithEncoding(jrxmlFilePath, "UTF-8"));
				xmlWriter.write(document);
				xmlWriter.flush();
			}
		} finally {
			if (xmlWriter != null) {
				xmlWriter.close();
			}
		}
	}

	/**
	 * 从数据库获取列名
	 * 
	 * @param connection
	 * @param sql
	 * @return
	 * @throws SQLException
	 */
	private List<String> getColumnNames(Connection connection, String sql) throws SQLException {
		List<String> result = new ArrayList<>();
		PreparedStatement preparedStatement = connection.prepareStatement(sql);
		ResultSet resultSet = preparedStatement.executeQuery();
		ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
		for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
			result.add(resultSetMetaData.getColumnName(i).toUpperCase());
		}
		return result;
	}

	/**
	 * 获取模板中实际使用的Field
	 * 
	 * @param jrxmlFilePath
	 * @return
	 * @throws IOException
	 */
	private Set<String> getUsedFields(String jrxmlFilePath) throws IOException {
		String xml = FileUtils.readAsString(new File(jrxmlFilePath));
		Set<String> result = new HashSet<>();
		// 格式为$F{PD_TOTAL}
		Pattern pattern = Pattern.compile("\\$F\\{([^\\$]*)\\}");
		Matcher matcher = pattern.matcher(xml);
		while (matcher.find()) {
			result.add(matcher.group(1).toUpperCase());
		}
		return result;
	}

	/**
	 * 替换字体
	 * 
	 * @param jrxmlFilePath
	 * @throws IOException
	 * @throws FileNotFoundException
	 */
	private void replaceFont(String jrxmlFilePath) throws FileNotFoundException, IOException {
		File jrxmlFile = new File(jrxmlFilePath);
		String xml = FileUtils.readAsString(jrxmlFile);
		xml = xml.replace("MSYahei", ReportConstants.MICROSOFT_YAHEI_UI_FONT_NAME);
		FileUtils.write(jrxmlFile, xml);
	}

	/**
	 * 更改可换行的textField的行距
	 * 
	 * @param jrxmlFilePath
	 * @return 修改后的jrxml源码
	 * @throws FileNotFoundException
	 * @throws IOException
	 * @throws DocumentException
	 */
	private String modifyLineSpacing(String jrxmlFilePath)
			throws FileNotFoundException, IOException, DocumentException {
		File jrxmlFile = new File(jrxmlFilePath);
		SAXReader saxReader = new SAXReader();
		Document document = saxReader.read(jrxmlFile);
		@SuppressWarnings("unchecked")
		// 获取所有textElement节点（jrxml的XPath格式为：/*[name()='jasperReport']/*[name()='columnHeader']/*[name()='band']/*[name()='textField']）
		List<Element> textElements = document.selectNodes("//*[name()='textElement']");
		for (Element textElement : textElements) {
			// 更改可换行的textField的行距
			Element parent = textElement.getParent();
			if (parent != null && Objects.equals(parent.getName(), "textField")) {
				// 如果textElement节点指定isStretchWithOverflow为true（可换行），则调整行距
				Attribute isStretchWithOverflow = parent.attribute("isStretchWithOverflow");
				if (isStretchWithOverflow != null && Objects.equals(isStretchWithOverflow.getText(), "true")) {
					// 修改paragraph节点
					Element paragraphElement = (Element) textElement.selectSingleNode("*[name()='paragraph']");
					if (paragraphElement == null) {
						paragraphElement = new DefaultElement("paragraph", textElement.getNamespace());
						textElement.add(paragraphElement);
					}
					// 调整行距为固定值12磅
					Attribute lineSpacing = paragraphElement.attribute("lineSpacing");
					if (lineSpacing != null) {
						lineSpacing.setText("Fixed");
					} else {
						paragraphElement.addAttribute("lineSpacing", "Fixed");
					}
					Attribute lineSpacingSize = paragraphElement.attribute("lineSpacingSize");
					if (lineSpacingSize != null) {
						lineSpacingSize.setText("12.0");
					} else {
						paragraphElement.addAttribute("lineSpacingSize", "12.0");
					}
				}
			}
		}
		return document.asXML();
	}

	/**
	 * 以xls的格式导出报表
	 * 
	 * @param jasperPrint
	 * @param outputStream
	 * @throws JRException
	 */
	private void exportReportToXls(JasperPrint jasperPrint, OutputStream outputStream, boolean customCellStyle)
			throws JRException {
		JRXlsExporter exporter = new CustomJRXlsExporter(customCellStyle);
		ExporterInput exporterInput = new SimpleExporterInput(jasperPrint);
		exporter.setExporterInput(exporterInput);
		OutputStreamExporterOutput exporterOutput = new SimpleOutputStreamExporterOutput(outputStream);
		exporter.setExporterOutput(exporterOutput);
		exporter.exportReport();
	}

	/**
	 * 以doc的格式导出报表
	 * 
	 * @param jasperPrint
	 * @param outputStream
	 * @throws JRException
	 * @throws IOException
	 */
	private void exportReportToDoc(JasperPrint jasperPrint, OutputStream outputStream) throws JRException, IOException {
		exportReportToRtf(jasperPrint, outputStream);
	}

	/**
	 * 以rtf的格式导出报表
	 * 
	 * @param jasperPrint
	 * @param outputStream
	 * @throws JRException
	 * @throws IOException
	 */
	private void exportReportToRtf(JasperPrint jasperPrint, OutputStream outputStream) throws JRException, IOException {
		JRRtfExporter exporter = new JRRtfExporter();
		ExporterInput exporterInput = new SimpleExporterInput(jasperPrint);
		exporter.setExporterInput(exporterInput);
		WriterExporterOutput exporterOutput = new SimpleWriterExporterOutput(outputStream);
		exporter.setExporterOutput(exporterOutput);
		exporter.exportReport();
	}

	/**
	 * 以pdf的格式导出报表
	 * 
	 * @param jasperPrint
	 * @param outputStream
	 * @param pageIndex
	 * @throws JRException
	 */
	private void exportReportToPdf(JasperPrint jasperPrint, OutputStream outputStream, Integer pageIndex)
			throws JRException {
		JRPdfExporter exporter = new JRPdfExporter();
		if (pageIndex != null) {
			// 前端显示时页码从1开始，生成报表时页码从0开始
			pageIndex -= 1;
			// 页码并非有效数值，重置为第一页
			if (pageIndex < 0 || pageIndex >= jasperPrint.getPages().size()) {
				pageIndex = 0;
			}
			SimplePdfReportConfiguration configuration = new SimplePdfReportConfiguration();
			configuration.setPageIndex(pageIndex);
			exporter.setConfiguration(configuration);
		}
		ExporterInput exporterInput = new SimpleExporterInput(jasperPrint);
		exporter.setExporterInput(exporterInput);
		OutputStreamExporterOutput exporterOutput = new SimpleOutputStreamExporterOutput(outputStream);
		exporter.setExporterOutput(exporterOutput);
		exporter.exportReport();
	}

	/**
	 * 移除除了Column Header和Detail之外的元素
	 * 
	 * @param jasperDesign
	 */
	private void removeUnusedElements(JasperDesign jasperDesign) {
		if (jasperDesign == null) {
			return;
		}
		jasperDesign.setTitle(null);
		jasperDesign.setPageHeader(null);
		jasperDesign.setColumnFooter(null);
		jasperDesign.setPageFooter(null);
		jasperDesign.setLastPageFooter(null);
		// jasperDesign.setSummary(null);
		jasperDesign.setNoData(null);
		jasperDesign.setBackground(null);
		// 忽略分页，以使列名只打印一次
		jasperDesign.setIgnorePagination(true);

		// 设置页边距，页宽，以免存在空白表格
		jasperDesign.setPageWidth(
				jasperDesign.getPageWidth() - jasperDesign.getLeftMargin() - jasperDesign.getRightMargin());
		jasperDesign.setTopMargin(0);
		jasperDesign.setLeftMargin(0);
		jasperDesign.setBottomMargin(0);
		jasperDesign.setRightMargin(0);
	}

	@Override
	public String getMasterOfJrxml(String userName, String reportName) {
		ReportUtils.checkParameters(userName, reportName);
		if (userName.startsWith("B2B")) {
			String jrxmlFilePath = fileService.getJrxmlFilePath(userName, reportName);
			File jrxmlFile = new File(jrxmlFilePath);
			// 报表模板不存在，返回B2B标准模板账套
			if (!jrxmlFile.exists()) {
				return specialProperties.getStandardMaster() + "/B2B";
			}
		} else {
			// 如果主账套与子账套共用模板
			if (specialProperties.shareJrxmlsWithSubMaster()) {
				Master master = MasterManager.getMaster(userName);
				if (master != null) {
					// 获取账套的主账套
					while (master.hasParent()) {
						master = MasterManager.getMaster(master.getParent().getName());
					}
					userName = master.getName();
				}
			}
		}
		return userName;
	}

	@Override
	public boolean overload(String userName, String profile, String reportName, String whereCondition,
			String otherParameters, Platform platform) throws SQLException, IOException, DocumentException {
		// 支持打印的最大记录行数
		int maxRecordSize = 0;
		switch (platform) {
		case PC:
			maxRecordSize = systemProperties.getMaxRecordSizePc();
			break;
		case PHONE:
			maxRecordSize = systemProperties.getMaxRecordSizePhone();
			break;
		}

		int count = getCount(userName, profile, reportName, whereCondition, otherParameters);
		return count >= maxRecordSize;
	}

	@Override
	public int getCount(String userName, String profile, String reportName, String whereCondition,
			String otherParameters) throws SQLException, IOException, DocumentException {
		DataSource dataSource = MasterManager.getDataSource(userName, profile);
		if (dataSource == null) {
			throw new SQLException("获取数据源失败");
		}

		String masterOfJrxml = getMasterOfJrxml(userName, reportName);
		String jrxmlFilePath = fileService.getJrxmlFilePath(masterOfJrxml, reportName);
		Connection connection = null;
		try {
			logger.info("dataSource.getConnection..." + userName);
			connection = dataSource.getConnection();
			logger.info("dataSource.getConnection done..." + userName);

			File jrxmlFile = new File(jrxmlFilePath);
			// 报表模板不存在
			if (!jrxmlFile.exists()) {
				// 替换windows下路径中的双反斜杠为单斜杠
				throw new FileNotFoundException("报表模板不存在");
			}

			// 因为子报表数据量较小，而且其参数来自主报表，无法简单地进行判断，所以不判断子报表是否过载
			int count = getCount(jrxmlFilePath, whereCondition, otherParameters, connection);
			logger.info("count... " + count);
			return count;
		} finally {
			if (connection != null) {
				connection.close();
			}
		}
	}

	/**
	 * 获取该模板在当前条件下的结果数目
	 * 
	 * @param jrxmlFilePath
	 * @param whereCondition
	 * @param otherParameters
	 * @param connection
	 * @throws IOException
	 * @throws SQLException
	 * @throws DocumentException
	 */
	private int getCount(String jrxmlFilePath, String whereCondition, String otherParameters, Connection connection)
			throws IOException, SQLException, DocumentException {
		XMLWriter xmlWriter = null;
		try {
			SAXReader saxReader = new SAXReader();
			Document document = saxReader.read(new File(jrxmlFilePath));
			Element rootElement = document.getRootElement();
			// 查询语句
			Element queryStringElement = rootElement.element("queryString");
			String queryString = queryStringElement.getText();
			queryString.replace("\"", "");
			// 如果查询语句中含有WHERE_CONDITION参数，需将其替换掉
			if (queryString.contains("$P!{WHERE_CONDITION}")) {
				if (StringUtils.isEmpty(whereCondition)) {
					throw new IllegalArgumentException("未指定查询条件！");
				}
				queryString = queryString.replace("$P!{WHERE_CONDITION}", whereCondition);
			}
			queryString = replaceOtherParameters(queryString, otherParameters);
			return getCount(connection, queryString);
		} finally {
			if (xmlWriter != null) {
				xmlWriter.close();
			}
		}
	}

	/**
	 * 替换sql语句中的动态参数
	 * 
	 * @param sql
	 * @param otherParameters
	 * @return
	 */
	private String replaceOtherParameters(String sql, String otherParameters) {
		// 替换其他参数
		if (sql.contains("$P{")) {
			if (StringUtils.isEmpty(otherParameters)) {
				throw new IllegalArgumentException("未传入动态参数");
			}
			JSONObject parameters = JSONObject.parseObject(otherParameters);
			Pattern pattern = Pattern.compile("\\$P\\{([^\\$]*)\\}");
			Matcher matcher = pattern.matcher(sql);
			while (matcher.find()) {
				String match = matcher.group();
				String parameterName = match.substring("$P{".length(), match.length() - 1);
				Object value = parameters.get(parameterName);
				if (value == null) {
					throw new IllegalArgumentException("未传入动态参数：" + parameterName);
				}
				// 如果不是数字，需以单引号括起来
				if (value instanceof Number) {
					sql = sql.replace(match, value.toString());
				} else {
					sql = sql.replace(match, "'" + value.toString() + "'");
				}
			}
		}
		return sql;
	}

	/**
	 * 获取当前查询语句的结果数目
	 * 
	 * @param connection
	 * @param sql
	 * @return
	 * @throws SQLException
	 */
	private int getCount(Connection connection, String sql) throws SQLException {
		sql = "select count(1) from (" + sql + ")";
		PreparedStatement preparedStatement = connection.prepareStatement(sql);
		ResultSet resultSet = preparedStatement.executeQuery();
		resultSet.next();
		int count = resultSet.getInt(1);
		return count;
	}

}
