package com.uas.report.controller;

import com.uas.report.SystemProperties;
import com.uas.report.model.ExportType;
import com.uas.report.model.Platform;
import com.uas.report.model.PrintType;
import com.uas.report.service.FileService;
import com.uas.report.service.PrintService;
import com.uas.report.util.ReportUtils;
import com.uas.report.util.StringUtils;
import net.sf.jasperreports.engine.JRException;
import org.dom4j.DocumentException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * 报表打印
 *
 * @author sunyj
 * @since 2016年8月16日 下午3:49:02
 */

@Controller
@RequestMapping("/print")
public class PrintController {

	@Autowired
	private SystemProperties systemProperties;

	@Autowired
	private PrintService printService;

	@Autowired
	private FileService fileService;

	@Autowired
	private PdfController pdfController;

	/**
	 * 为UAS系统打印提供服务， 根据printType进行预览、打印、下载pdf、下载纯数据excel等操作
	 *
	 * @param userName
	 *            不为null；当前账套名称
	 * @param profile
	 *            可选（UAS等系统不必传递该参数），用于标识请求源（B2C、B2B）是正式、测试还是开发版本：prod、test、dev
	 * @param reportName
	 *            不为null；需要导出的报表的名称，不带任何后缀（如导出采购单，即为"Purchase"）
	 * @param whereCondition
	 *            可为null；where之后的条件（包括where）
	 * @param otherParameters
	 *            若模板已指定需要的参数，则不可为null；其他参数，区别于whereCondition，报表某些字段的值取决于这些参数；
	 *            JSON格式，数据为键值对
	 * @param printType
	 *            打印类型，可为PREVIEW_PRINT_TYPE、PRINT_PRINT_TYPE、PDF_PRINT_TYPE、
	 *            EXCEL_PRINT_TYPE
	 * @param title
	 *            导出为文件时的名称
	 * @param request
	 * @param response
	 * @throws SQLException
	 * @throws DocumentException
	 * @throws IOException
	 * @throws JRException
	 * @throws ServletException
	 */
	@RequestMapping()
	public void print(String userName, String profile, String reportName, String whereCondition, String otherParameters,
			String printType, String title, HttpServletRequest request, HttpServletResponse response)
			throws JRException, IOException, DocumentException, SQLException, ServletException {
		userName = userName == null ? null : userName.toUpperCase();
		// printType为空，默认进入预览页
		PrintType type = StringUtils.isEmpty(printType) ? PrintType.PREVIEW : PrintType.checkType(printType);

		switch (type) {
		// 预览或打印
		case PREVIEW:
		case PRINT:
			request.getRequestDispatcher("preview").forward(request, response);
			break;
		case PDF:
			export(userName, profile, reportName, whereCondition, otherParameters, ExportType.PDF.name(), true, title,
					request, response);
			break;
		// 该下载接口供 UAS 系统使用，应其要求，printType 为{@link PrintType.EXCEL}时，下载纯数据的 excel
		case EXCEL:
			if (systemProperties.isUseXlsx()) {
				export(userName, profile, reportName, whereCondition, otherParameters, ExportType.XLSX_DATA.name(),
						true, title, request, response);
			} else {
				export(userName, profile, reportName, whereCondition, otherParameters, ExportType.XLS_DATA.name(), true,
						title, request, response);
			}
			break;
		case WORD:
			export(userName, profile, reportName, whereCondition, otherParameters, ExportType.DOC.name(), true, title,
					request, response);
			break;
		case TEXT:
			export(userName, profile, reportName, whereCondition, otherParameters, ExportType.TXT.name(), true, title,
					request, response);
			break;
		}
	}

	/**
	 * 导出报表
	 *
	 * @param userName
	 *            不为null；当前账套名称
	 * @param profile
	 *            可选（UAS等系统不必传递该参数），用于标识请求源（B2C、B2B）是正式、测试还是开发版本：prod、test、dev
	 * @param reportName
	 *            不为null；需要导出的报表的名称，不带任何后缀（如导出采购单，即为"Purchase"）
	 * @param whereCondition
	 *            可为null；where之后的条件（包括where）
	 * @param otherParameters
	 *            若模板已指定需要的参数，则不可为null；其他参数，区别于whereCondition，报表某些字段的值取决于这些参数；
	 *            JSON格式，数据为键值对
	 * @param exportFileType
	 *            报表导出的格式，默认为pdf
	 * @param flush
	 *            是否强制刷新pdf、xls
	 * @param title
	 *            导出为文件时的名称
	 * @param request
	 * @param response
	 * @throws SQLException
	 * @throws DocumentException
	 * @throws IOException
	 * @throws JRException
	 */
	@RequestMapping("/export")
	@ResponseBody
	public void export(String userName, String profile, String reportName, String whereCondition,
			String otherParameters, String exportFileType, Boolean flush, String title, HttpServletRequest request,
			HttpServletResponse response) throws JRException, IOException, DocumentException, SQLException {
		// TODO show download process
		userName = userName == null ? null : userName.toUpperCase();
		ReportUtils.checkParameters(userName, reportName);
		String masterOfJrxml = printService.getMasterOfJrxml(userName, reportName);
		ExportType exportType = StringUtils.isEmpty(exportFileType) ? ExportType.PDF
				: ExportType.checkType(exportFileType);

		String filePath = reportName + "/"
				+ fileService.generateFileName(userName, profile, whereCondition, otherParameters, exportFileType)
                + "." + exportType.getQualifier();
		File file = new File(ReportUtils.getDocumentsDir(), filePath);
		// 指定flush为true（强制刷新pdf、xls）
		// 文件无效（不存在或过期），创建
		if ((flush != null && flush)
				|| !fileService.isFileValid(file.getPath(), fileService.getJrxmlFilePath(masterOfJrxml, reportName))) {
			if (printService.overload(userName, profile, reportName, whereCondition, otherParameters, Platform.PC)) {
				throw new IllegalStateException("数据量过大，无法提供服务");
			}
			printService.export(userName, profile, reportName, whereCondition, otherParameters, exportType, file, null, true);
		}

		String exportFileName = (!StringUtils.isEmpty(title) ? title : reportName) + "." + exportType.getQualifier();
		fileService.rangeDownload(file, exportFileName, request, response);
	}

	/**
	 * 报表预览时获取pdf相对路径
	 *
	 * @param userName
	 *            不为null；当前账套名称
	 * @param profile
	 *            可选（UAS等系统不必传递该参数），用于标识请求源（B2C、B2B）是正式、测试还是开发版本：prod、test、dev
	 * @param reportName
	 *            不为null；需要预览的报表的名称，不带任何后缀（如预览采购单，即为"Purchase"）
	 * @param whereCondition
	 *            可为null；where之后的条件（包括where）
	 * @param otherParameters
	 *            若模板已指定需要的参数，则不可为null；其他参数，区别于whereCondition，报表某些字段的值取决于这些参数；
	 *            JSON格式，数据为键值对
	 * @param flush
	 *            是否强制刷新pdf、xls
	 * @param request
	 * @param response
	 * @return pdf相对路径
	 * @throws SQLException
	 * @throws DocumentException
	 * @throws IOException
	 * @throws JRException
	 */
	@RequestMapping(value = "/pdfPath")
	@ResponseBody
	public String getPdfPath(String userName, final String profile, final String reportName,
			final String whereCondition, final String otherParameters, Boolean flush, HttpServletRequest request,
			HttpServletResponse response) throws JRException, IOException, DocumentException, SQLException {
		userName = userName == null ? null : userName.toUpperCase();
		ReportUtils.checkParameters(userName, reportName);
		String masterOfJrxml = printService.getMasterOfJrxml(userName, reportName);

        String pdfPath = reportName + "/"
                + fileService.generateFileName(userName, profile, whereCondition, otherParameters, ExportType.PDF.getQualifier())
                + "." + ExportType.PDF.getQualifier();
        File file = new File(ReportUtils.getDocumentsDir(), pdfPath);
        // 指定flush为true（强制刷新pdf）
		// 文件无效（不存在或过期），重新创建pdf文件
		if ((flush != null && flush)
				|| !fileService.isFileValid(file.getPath(), fileService.getJrxmlFilePath(masterOfJrxml, reportName))) {
			if (printService.overload(userName, profile, reportName, whereCondition, otherParameters, Platform.PC)) {
				throw new IllegalStateException("数据量过大，无法提供服务");
			}
			printService.export(userName, profile, reportName, whereCondition, otherParameters, ExportType.PDF, file, null, true);
		}
		return "pdf/preview?p=" + pdfPath;
	}

	/**
	 * 获取pdf数据（该接口暂时供手机端访问）
	 *
	 * @param userName
	 *            不为null；当前账套名称
	 * @param profile
	 *            可选（UAS等系统不必传递该参数），用于标识请求源（B2C、B2B）是正式、测试还是开发版本：prod、test、dev
	 * @param reportName
	 *            不为null；需要预览的报表的名称，不带任何后缀（如预览采购单，即为"Purchase"）
	 * @param whereCondition
	 *            可为null；where之后的条件（包括where）
	 * @param otherParameters
	 *            若模板已指定需要的参数，则不可为null；其他参数，区别于whereCondition，报表某些字段的值取决于这些参数；
	 *            JSON格式，数据为键值对
	 * @param request
	 * @param response
	 * @return 包括pageSize、data（或overload）
	 * @throws SQLException
	 * @throws DocumentException
	 * @throws IOException
	 * @throws JRException
	 */
	@RequestMapping(value = "/pdfData")
	@ResponseBody
	public Map<String, Object> getPdfData(String userName, String profile, String reportName, String whereCondition,
			String otherParameters, HttpServletRequest request, HttpServletResponse response)
			throws JRException, IOException, DocumentException, SQLException {
		return pdfController.getData(userName, profile, reportName, whereCondition, otherParameters, Platform.PHONE.name(), request, response);
	}

	/**
	 * 获取该模板在当前条件下的结果数目
	 *
	 * @param userName
     *            不为null；当前账套用户名
	 * @param profile
	 *            用于标识请求源（B2C、B2B）是正式、测试还是开发版本：prod、test、dev
	 * @param reportName
	 *            不为null；需要导出的报表的名称，不带任何后缀（如导出采购单，即为"Purchase"）
	 * @param whereCondition
	 *            可为null；where之后的条件（包括where）
	 * @param otherParameters
	 *            若模板已指定需要的参数，则不可为null；其他参数，区别于whereCondition，报表某些字段的值取决于这些参数；
	 *            JSON格式，数据为键值对
	 * @param request
	 * @param response
	 * @return 结果数目
	 * @throws SQLException
	 * @throws IOException
	 * @throws DocumentException
	 */
	@RequestMapping(value = "/count")
	@ResponseBody
	public int getCount(String userName, String profile, String reportName, String whereCondition,
			String otherParameters, HttpServletRequest request, HttpServletResponse response)
			throws SQLException, IOException, DocumentException {
		userName = userName == null ? null : userName.toUpperCase();
		ReportUtils.checkParameters(userName, reportName);
		return printService.getCount(userName, profile, reportName, whereCondition, otherParameters);
	}

	/**
	 * 预览页面所显示的导出按钮
	 *
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "/exportButtons")
	@ResponseBody
	public List<ExportType> getPagePreviewShowExportButtons(HttpServletRequest request, HttpServletResponse response) {
		return systemProperties.getPagePreviewShowExportButtons();
	}
}
