package cn.myapps.report.engine;

import static net.sf.dynamicreports.report.builder.DynamicReports.report;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;

import cn.myapps.common.auth.IUser;
import cn.myapps.common.data.ParamsTable;
import cn.myapps.common.model.application.Application;
import cn.myapps.common.model.datasource.DataSource;
import cn.myapps.common.model.report.Report;
import cn.myapps.common.model.view.AbstractView;
import cn.myapps.common.util.StringUtil;
import cn.myapps.common.Environment;
import cn.myapps.designtime.application.service.ApplicationDesignTimeService;
import cn.myapps.designtime.common.service.DesignTimeServiceFactory;
import cn.myapps.designtime.common.service.DesignTimeServiceManager;
import cn.myapps.designtime.datasource.service.DataSourceDesignTimeService;
import cn.myapps.designtime.form.service.FormDesignTimeService;
import cn.myapps.designtime.report.service.ReportDesignTimeService;
import cn.myapps.designtime.report.service.ReportDesignTimeServiceImpl;
import cn.myapps.designtime.view.service.ViewDesignTimeService;
import cn.myapps.report.examples.Templates;
import cn.myapps.runtime.dynaform.document.ejb.Document;
import cn.myapps.runtime.dynaform.form.ejb.Form;
import cn.myapps.runtime.dynaform.form.ejb.ValidateMessage;
import cn.myapps.runtime.macro.runner.IRunner;
import cn.myapps.runtime.macro.runner.JavaScriptFactory;
import cn.myapps.runtime.report.model.DRDataSource;
import cn.myapps.runtime.report.model.JRBeanCollectionDataSource;
import net.sf.dynamicreports.jasper.builder.JasperReportBuilder;
import net.sf.dynamicreports.jasper.builder.export.JasperHtmlExporterBuilder;
import net.sf.dynamicreports.jasper.builder.export.JasperPdfExporterBuilder;
import net.sf.dynamicreports.jasper.builder.export.JasperXlsExporterBuilder;
import net.sf.dynamicreports.report.builder.DynamicReports;
import net.sf.dynamicreports.report.builder.QueryBuilder;
import net.sf.dynamicreports.report.builder.column.ColumnBuilder;
import net.sf.dynamicreports.report.constant.QueryLanguage;
import net.sf.dynamicreports.report.exception.DRException;
import net.sf.jasperreports.engine.JRDataSource;
import org.apache.commons.lang.StringUtils;

/**
 * 天翎动态报表引擎接口
 * @author zhanbo
 */
public class ReportEngine {

	private static ReportEngine INSTANCE;

	public static ReportEngine getInstance() {
		if (INSTANCE == null) {
			INSTANCE = new ReportEngine();
		}
		return INSTANCE;
	}

	private JRDataSource createViewDataSource(Report report, ParamsTable params, IUser user) throws Exception {
		//TODO
		return null;
	}

	private QueryBuilder createSqlDataSource(Report report, ParamsTable params, IUser user) throws Exception {
		if (!StringUtil.isBlank(report.getDataSourceSqlScript())) {
			IRunner runner = JavaScriptFactory.getInstance(user.getSessionid(), report.getApplicationid());
			runner.initBSFManager(null, params, user, new ArrayList<ValidateMessage>());
			Object result = runner.run(report, "Report[" + report.getName() + "]-" + report.getId(), report.getDataSourceSqlScript());

			if (result instanceof String) {
				String sql = (String)result;
				QueryBuilder query = DynamicReports.query(sql, QueryLanguage.SQL);
				return query;

			} else {
				throw new Exception("Report[" + report.getName() + "]脚本运算结果不合法，请返回字符串！");
			}
		}
		return null;
	}

	private JRDataSource createCustomDataSource(Report report, ParamsTable params, IUser user) throws Exception {
		JRDataSource dataSource = null;

		if (!StringUtil.isBlank(report.getScriptTemplate())) {
			IRunner runner = JavaScriptFactory.getInstance(user.getSessionid(), report.getApplicationid());
			runner.initBSFManager(null, params, user, new ArrayList<ValidateMessage>());
			Object result = runner.run(report,"Report[" + report.getName() + "]-" + report.getId(), report.getScriptTemplate());
			if (result instanceof JRDataSource) {
				dataSource = (JRDataSource) result;
			} else {
				throw new Exception("Report[" + report.getName() + "]脚本运算结果不合法，请返回字符串！");
			}
		}
		return dataSource;
	}

	public JasperReportBuilder build(Report report, ParamsTable params, IUser user) throws Exception {
		JasperReportBuilder builder = null;
		if (Report.TYPE_SCRIPT.equals(report.getTemplateType())) {
			if (!StringUtil.isBlank(report.getScriptTemplate())) {
				JavaScriptFactory.clear();
				Document document = null;
				if(report.getDataSourceType().equals(Report.DATASOURCE_TYPE_VIEW) && report.getIsPrint() == 0){
					String viewId = report.getViewId();
					ViewDesignTimeService viewProcess = DesignTimeServiceManager.viewDesignTimeService();
					AbstractView view = viewProcess.doView(viewId);
					Form searchForm = view.getSearchForm();
					if(searchForm != null){
						document = searchForm.createDocument(params, user);
					}
				}else if(report.getDataSourceType().equals(Report.DATASOURCE_TYPE_SQL) && report.getIsPrint() == 0){
					String searchFormId = report.getDataSourceSearchForm();
					if (!StringUtils.isBlank(searchFormId)) {
						FormDesignTimeService fs = DesignTimeServiceManager.formDesignTimeService();
						Form searchForm = fs.doView(searchFormId);
						if(searchForm != null){
							document = searchForm.createDocument(params, user);
						}
					}
				}
				IRunner runner = JavaScriptFactory.getInstance(user.getSessionid(), report.getApplicationid());
				runner.initBSFManager(document, params, user, new ArrayList<ValidateMessage>());
				Object result = runner.run(report,"Report[" + report.getName() + "]-" + report.getId(), report.getScriptTemplate());
				if (result instanceof JasperReportBuilder) {
					builder = (JasperReportBuilder) result;

					if (Report.DATASOURCE_TYPE_VIEW.equals(report.getDataSourceType())) {
						if (!StringUtil.isBlank(report.getDataSourceView())) {
							JRDataSource jrds = createViewDataSource(report, params, user);
							builder.setDataSource(jrds);
						}
					}

					else if (Report.DATASOURCE_TYPE_SQL.equals(report.getDataSourceType())) {
						if (!StringUtil.isBlank(report.getDataSourceSqlScript())) {
							String id = report.getDataSourceSqlConnectDs();
							DataSourceDesignTimeService  service = DesignTimeServiceManager.dataSourceDesignTimeService();
							DataSource ds = (DataSource)service.findById(id);
							Connection connection = ds.getConnection();

							QueryBuilder query = createSqlDataSource(report, params, user);

							builder.setDataSource(query, connection);

						}
					}

					else if (Report.DATASOURCE_TYPE_CUSTOM.equals(report.getDataSourceType())) {
						if (!StringUtil.isBlank(report.getScriptTemplate())) {

							JRDataSource jrds = createCustomDataSource(report, params, user);
							builder.setDataSource(jrds);
						}
					}
				} else {
					throw new Exception("Report[" + report.getName() + "]脚本运算结果不合法，请返回字符串！");
				}
			}
		}
		return builder;
	}

	public String exportPdf(Report report, ParamsTable params, IUser user) throws DRException, Exception {
		Environment env = Environment.getInstance();
		String path = "/uploads/reports/" + report.getName() + ".pdf";

		String realPath = env.getRealPath(path);
		DataSource dataSource = getDataSource(report);
		ReportDesignTimeService reportService = new ReportDesignTimeServiceImpl();
		//子报表数据源
		DRDataSource subDrDataSource = null;
		//判断是否存在子报表
		if(!StringUtil.isBlank(report.getSubReportId())){
			Report subReport = reportService.doView(report.getSubReportId());
			subDrDataSource = (DRDataSource) subReport.getDRDataSource();
		}
		if (Report.TYPE_SCRIPT.equals(report.getTemplateType())) {
			JasperPdfExporterBuilder exporterBuilder = DynamicReports.export.pdfExporter(realPath);
			build(report, params, user).export(exporterBuilder);

		} else if (Report.TYPE_JRXML.equals(report.getTemplateType())) {
			JasperPdfExporterBuilder exporterBuilder = DynamicReports.export.pdfExporter(realPath);

			String jrxmlFilePath = report.getJrxmlFilePath();
			String isDefaultStyle = report.getIsDefaultStyle();
			DRDataSource drDataSource = (DRDataSource) report.getDRDataSource();
			List<ColumnBuilder> reportColumnInfos = (List<ColumnBuilder>) report.getReportColumnInfos();

			if (jrxmlFilePath == null || isDefaultStyle  == null /*|| drDataSource == null || reportColumnInfos == null */) {
				return null;
			}

			String jrxmlFileRealPath = env.getRealPath(jrxmlFilePath);
			File jrxmlFile = new File(jrxmlFileRealPath);
			InputStream jrxmlInputStream = new FileInputStream(jrxmlFile);

			// 使用默认样式显示
			if (isDefaultStyle.equals("1")) {
				JasperReportBuilder jasperReport = report();

				jasperReport.setTemplate(Templates.reportTemplate)
						.setTemplateDesign(jrxmlInputStream)
						.title(Templates.createTitleComponent(report.getName()));

				if (reportColumnInfos != null ) {
					jasperReport.columns(reportColumnInfos.toArray(new ColumnBuilder[reportColumnInfos.size()]));
				}

				if (drDataSource != null ) {
					jasperReport.setDataSource(drDataSource);
				}

				jasperReport.export(exporterBuilder);

				// 使用自定义样式显示
			} else {
				JasperReportBuilder jasperReport = report();

				jasperReport.setTemplateDesign(jrxmlInputStream)
						.setDataSource(drDataSource)
						.setParameter("REPORT_CONNECTION",dataSource.getConnection())
						.addParameter("REPORT_DATA", JRBeanCollectionDataSource.class)
						.setParameter("REPORT_DATA",subDrDataSource == null ? null : new JRBeanCollectionDataSource(subDrDataSource.getValues(),false))
						.export(exporterBuilder);

			}

		}
		return path;
	}

	public String exportHtml(Report report, ParamsTable params, IUser user) throws DRException, Exception {
		String path = "/uploads/reports/" + report.getId() + ".html";
		Environment env = Environment.getInstance();
		String realPath = env.getRealPath("/uploads/reports");
		File folder = new File(realPath);
		//文件夹不存在则创建
		if(!folder.exists()){
			folder.mkdirs();
		}
		//文件生成路径
		realPath = realPath +File.separator+ report.getId() + ".html";
		DataSource dataSource = getDataSource(report);

		ReportDesignTimeService reportService = new ReportDesignTimeServiceImpl();
		//子报表
		List<Report> subReports = new ArrayList<Report>();
		//Report subReport = reportService.doView("__jdsdYE5lltfGaGrLw3d");
		//subDrDataSource = subReport.getDRDataSource();
		//判断是否存在子报表
		String subReportId = report.getSubReportId();
		if(!StringUtil.isBlank(subReportId)){
			// 是否存在多个子报表
			if (subReportId.indexOf(",") == -1) {
				Report subReport = reportService.doView(subReportId);
				subReports.add(subReport);
			} else {
				String[] subReportIds = subReportId.split(",");
				for (int i = 0; i < subReportIds.length; i++) {
					Report subReport = reportService.doView(subReportIds[i]);
					subReports.add(subReport);
				}
			}
		}


		String htmlHeader = "<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n" +
				"<tr><td width=\"50%\" style=\"background:#eee;\">&nbsp;</td><td align=\"center\">\n";
		String htmlFooter = "<td width=\"50%\" style=\"background:#eee;\">&nbsp;</td></tr>";
		if (Report.TYPE_SCRIPT.equals(report.getTemplateType())) {
			JasperHtmlExporterBuilder exporterBuilder = DynamicReports.export.htmlExporter(realPath);
			build(report, params, user).export(exporterBuilder);

		} else if (Report.TYPE_JRXML.equals(report.getTemplateType())) {
			JasperHtmlExporterBuilder exporterBuilder = DynamicReports.export.htmlExporter(realPath).setHtmlHeader(htmlHeader).setHtmlFooter(htmlFooter);

			String jrxmlFilePath = report.getJrxmlFilePath();
			String isDefaultStyle = report.getIsDefaultStyle();
			DRDataSource drDataSource = (DRDataSource) report.getDRDataSource();
			List<ColumnBuilder> reportColumnInfos = (List<ColumnBuilder>) report.getReportColumnInfos();

			if (jrxmlFilePath == null || isDefaultStyle  == null /*|| drDataSource == null || reportColumnInfos == null */) {
				return null;
			}

			String jrxmlFileRealPath = env.getRealPath(jrxmlFilePath);
			File jrxmlFile = new File(jrxmlFileRealPath);
			InputStream jrxmlInputStream = new FileInputStream(jrxmlFile);

			// 使用默认样式显示
			if (isDefaultStyle.equals("1")) {
				JasperReportBuilder jasperReport = report();

				jasperReport.setTemplate(Templates.reportTemplate)
						.setTemplateDesign(jrxmlInputStream)
						.title(Templates.createTitleComponent(report.getName()));

				if (reportColumnInfos != null ) {
					jasperReport.columns(reportColumnInfos.toArray(new ColumnBuilder[reportColumnInfos.size()]));
				}

				if (drDataSource != null ) {
					jasperReport.setDataSource(drDataSource);
				}

				jasperReport.export(exporterBuilder);

				// 使用自定义样式显示
			} else {
				JasperReportBuilder jasperReport = report();
				jasperReport.setTemplateDesign(jrxmlInputStream)
						.setDataSource(drDataSource)
						.setParameter("REPORT_CONNECTION",dataSource.getConnection());
				if(!subReports.isEmpty()){
					for (Report rt : subReports) {
						DRDataSource subDrDataSource = (DRDataSource) rt.getDRDataSource();
						jasperReport.addParameter("REPORT_DATA"+rt.getId(), JRBeanCollectionDataSource.class)
								.setParameter("REPORT_DATA"+rt.getId(),subDrDataSource == null ? null : new JRBeanCollectionDataSource(subDrDataSource.getValues(),false));
					}
				}
				jasperReport.export(exporterBuilder);
			}

		}

		return path;

	}

	public String exportExcel(Report report, ParamsTable params, IUser user) throws DRException, Exception {
		Environment env = Environment.getInstance();
		String path = "/uploads/reports/" + report.getName() + ".xls";

		String realPath = env.getRealPath(path);
		DataSource dataSource = getDataSource(report);
		ReportDesignTimeService reportService = new ReportDesignTimeServiceImpl();
		//子报表数据源
		DRDataSource subDrDataSource = null;
		//Report subReport = reportService.doView("__jdsdYE5lltfGaGrLw3d");
		//subDrDataSource = subReport.getDRDataSource();
		//判断是否存在子报表
		if(!StringUtil.isBlank(report.getSubReportId())){
			Report subReport = reportService.doView(report.getSubReportId());
			subDrDataSource = (DRDataSource) subReport.getDRDataSource();
		}
		if (Report.TYPE_SCRIPT.equals(report.getTemplateType())) {
			JasperXlsExporterBuilder exporterBuilder = DynamicReports.export.xlsExporter(realPath).setRemoveEmptySpaceBetweenRows(true).setRemoveEmptySpaceBetweenColumns(true).setWhitePageBackground(false);
			build(report, params, user).export(exporterBuilder);

		} else if (Report.TYPE_JRXML.equals(report.getTemplateType())) {
			JasperXlsExporterBuilder exporterBuilder = DynamicReports.export.xlsExporter(realPath).setRemoveEmptySpaceBetweenRows(true).setRemoveEmptySpaceBetweenColumns(true).setWhitePageBackground(false);

			String jrxmlFilePath = report.getJrxmlFilePath();
			String isDefaultStyle = report.getIsDefaultStyle();
			DRDataSource drDataSource = (DRDataSource) report.getDRDataSource();
			List<ColumnBuilder> reportColumnInfos = (List<ColumnBuilder>) report.getReportColumnInfos();

			if (jrxmlFilePath == null || isDefaultStyle  == null /*|| drDataSource == null || reportColumnInfos == null */) {
				return null;
			}

			String jrxmlFileRealPath = env.getRealPath(jrxmlFilePath);
			File jrxmlFile = new File(jrxmlFileRealPath);
			InputStream jrxmlInputStream = new FileInputStream(jrxmlFile);

			// 使用默认样式显示
			if (isDefaultStyle.equals("1")) {
				JasperReportBuilder jasperReport = report();

				jasperReport.setTemplate(Templates.reportTemplate)
						.setTemplateDesign(jrxmlInputStream)
						.title(Templates.createTitleComponent(report.getName()));

				if (reportColumnInfos != null ) {
					jasperReport.columns(reportColumnInfos.toArray(new ColumnBuilder[reportColumnInfos.size()]));
				}

				if (drDataSource != null ) {
					jasperReport.setDataSource(drDataSource);
				}

				jasperReport.export(exporterBuilder);

				// 使用自定义样式显示
			} else {
				JasperReportBuilder jasperReport = report();

				jasperReport.setTemplateDesign(jrxmlInputStream)
						.setDataSource(drDataSource)
						.setParameter("REPORT_CONNECTION",dataSource.getConnection())
						.addParameter("REPORT_DATA", JRBeanCollectionDataSource.class)
						.setParameter("REPORT_DATA",subDrDataSource == null ? null : new JRBeanCollectionDataSource(subDrDataSource.getValues(),false))
						.export(exporterBuilder);

			}

		}

		return path;

	}

	//获取报表数据源
	private DataSource getDataSource(Report report) throws Exception{
		String applicationId = report.getApplicationid();
		//获取软件
		ApplicationDesignTimeService appService = DesignTimeServiceManager.applicationDesignTimeService();
		Application application = appService.findById(applicationId);

		DataSourceDesignTimeService dataSourceService = DesignTimeServiceManager.dataSourceDesignTimeService();
		//获取数据源
		DataSource dataSource;
		if(report.getDataSourceType().equals(Report.DATASOURCE_TYPE_VIEW) || report.getIsPrint() == 1){
			//获取视图的数据源或者作为打印模板时
			dataSource = dataSourceService.findById(application.getDatasourceId());
		}else{
			//其他类型的数据源
			dataSource = dataSourceService.getDataSourceByName(report.getDataSourceName(), applicationId );
		}
		return dataSource;
	}
}
