package com.uas.report.controller;

import com.uas.report.model.ExportType;
import com.uas.report.model.Platform;
import com.uas.report.service.FileService;
import com.uas.report.service.PrintService;
import com.uas.report.util.FileUtils;
import com.uas.report.util.ReportUtils;
import net.sf.jasperreports.engine.JRException;
import org.dom4j.DocumentException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

/**
 * 获取pdf
 * 
 * @author sunyj
 * @since 2017年8月10日 下午7:17:38
 */
@Controller
@RequestMapping("/pdf")
public class PdfController {

	@Autowired
	private PrintService printService;

	@Autowired
	private FileService fileService;

	/**
	 * @param u
	 *            当前账套名称，不可为空
	 * @param pr
	 *            用于标识请求源（B2C、B2B）是正式、测试还是开发版本：prod、test、dev，可选（UAS等系统不必传递该参数）
	 * @param r
	 *            需要导出的报表的名称，不带任何后缀（如导出采购单，即为"Purchase"），不可为空
	 * @param w
	 *            where之后的条件（包括where），可为空
	 * @param o
	 *            其他参数，区别于w，报表某些字段的值取决于这些参数， JSON格式，数据为键值对，若模板已指定需要的参数，则不可为空
	 * @param pf
	 *            请求来自的平台，不可为空
	 * @param request
	 * @param response
	 * @return JSON格式
	 * 
	 *         <table border=1 cellpadding=5 cellspacing=0 summary= "result">
	 *         <tr>
	 *         <th>key</th>
	 *         <th>description</th>
	 *         </tr>
	 *         <tr>
	 *         <td>pdf</td>
	 *         <td>pdf相对路径</td>
	 *         </tr>
	 *         <tr>
	 *         <td>pageSize</td>
	 *         <td>pdf页数</td>
	 *         </tr>
	 *         <tr>
	 *         <td>overload</td>
	 *         <td>数据量是否过大</td>
	 *         </tr>
	 *         </table>
	 * @throws JRException
	 * @throws IOException
	 * @throws DocumentException
	 * @throws SQLException
	 */
	@RequestMapping(value = "/path")
	@ResponseBody
	public Map<String, Object> getPath(@RequestParam String u, String pr,
			@RequestParam String r, String w, String o, @RequestParam String pf,
			HttpServletRequest request, HttpServletResponse response)
			throws JRException, IOException, DocumentException, SQLException {
		u = u == null ? null : u.toUpperCase();
		ReportUtils.checkParameters(u, r);

		Map<String, Object> result = new HashMap<>();
		// 判断是否过载
		if (printService.overload(u, pr, r, w, o, Platform.checkPlatform(pf))) {
			result.put("path", "");
			result.put("pageSize", 0);
			result.put("overload", true);
		} else {
			// 相对路径
			String pdfPath = r + "/"
					+ fileService.generateFileName(u, pr, w, o, ExportType.PDF.getQualifier())
                    + "." + ExportType.PDF.getQualifier();
			File file = new File(ReportUtils.getDocumentsDir(), pdfPath);
			int pageSize = printService.export(u, pr, r, w, o, ExportType.PDF, file, null, true);
			result.put("path", "pdf/preview?p=" + pdfPath);
			// 页数为 0 时，实际为一页空白 pdf
			result.put("pageSize", pageSize == 0 ? 1 : pageSize);
			result.put("overload", false);
		}
		return result;
	}

	/**
	 * @param u
	 *            当前账套名称，不可为空
	 * @param pr
	 *            用于标识请求源（B2C、B2B）是正式、测试还是开发版本：prod、test、dev，可选（UAS等系统不必传递该参数）
	 * @param r
	 *            需要导出的报表的名称，不带任何后缀（如导出采购单，即为"Purchase"），不可为空
	 * @param w
	 *            where之后的条件（包括where），可为空
	 * @param o
	 *            其他参数，区别于w，报表某些字段的值取决于这些参数， JSON格式，数据为键值对，若模板已指定需要的参数，则不可为空
	 * @param pf
	 *            请求来自的平台，不可为空
	 * @param request
	 * @param response
	 * @return JSON格式
	 * 
	 *         <table border=1 cellpadding=5 cellspacing=0 summary= "result">
	 *         <tr>
	 *         <th>key</th>
	 *         <th>description</th>
	 *         </tr>
	 *         <tr>
	 *         <td>data</td>
	 *         <td>pdf的字节数据</td>
	 *         </tr>
	 *         <tr>
	 *         <td>pageSize</td>
	 *         <td>pdf页数</td>
	 *         </tr>
	 *         <tr>
	 *         <td>overload</td>
	 *         <td>数据量是否过大</td>
	 *         </tr>
	 *         </table>
	 * @throws JRException
	 * @throws IOException
	 * @throws DocumentException
	 * @throws SQLException
	 */
	@RequestMapping(value = "/data")
	@ResponseBody
	public Map<String, Object> getData(@RequestParam String u, String pr,
			@RequestParam String r, String w, String o, @RequestParam String pf,
			HttpServletRequest request, HttpServletResponse response)
			throws JRException, IOException, DocumentException, SQLException {
		u = u == null ? null : u.toUpperCase();
		ReportUtils.checkParameters(u, r);

		Map<String, Object> result = new HashMap<>();
		// 判断是否过载
		if (printService.overload(u, pr, r, w, o, Platform.checkPlatform(pf))) {
			result.put("data", "");
			result.put("pageSize", 0);
			result.put("overload", true);
		} else {
			String pdfPath = r + "/"
					+ fileService.generateFileName(u, pr, w, o, ExportType.PDF.getQualifier())
					+ "." + ExportType.PDF.getQualifier();
			File file = new File(ReportUtils.getDocumentsDir(), pdfPath);
			int pageSize = printService.export(u, pr, r, w, o, ExportType.PDF, file, null, true);
			result.put("data", FileUtils.readData(new FileInputStream(file)));
			result.put("pageSize", pageSize == 0 ? 1 : pageSize);
			result.put("overload", false);
		}
		return result;
	}

	/**
	 * 下载 pdf （断点续传）
	 * 
	 * @param u
	 *            当前账套名称，不可为空
	 * @param pr
	 *            用于标识请求源（B2C、B2B）是正式、测试还是开发版本：prod、test、dev，可选（UAS等系统不必传递该参数）
	 * @param r
	 *            需要导出的报表的名称，不带任何后缀（如导出采购单，即为"Purchase"），不可为空
	 * @param w
	 *            where之后的条件（包括where），可为空
	 * @param o
	 *            其他参数，区别于w，报表某些字段的值取决于这些参数， JSON格式，数据为键值对，若模板已指定需要的参数，则不可为空
	 * @param pf
	 *            请求来自的平台，不可为空
	 * @param n
	 *            下载后的文件名称，可为空
	 * @param request
	 * @param response
	 * @throws JRException
	 * @throws IOException
	 * @throws DocumentException
	 * @throws SQLException
	 * @throws IllegalStateException
	 */
	@RequestMapping(value = "/download")
	@ResponseBody
	public void download(@RequestParam String u, String pr, @RequestParam String r,
			String w, String o, @RequestParam String pf, String n, HttpServletRequest request,
			HttpServletResponse response)
			throws JRException, IOException, DocumentException, SQLException, IllegalStateException {
		u = u == null ? null : u.toUpperCase();
		ReportUtils.checkParameters(u, r);

		// 相对路径
		String pdfPath = r + "/"
				+ fileService.generateFileName(u, pr, w, o, ExportType.PDF.getQualifier())
                + "." + ExportType.PDF.getQualifier();
		File file = new File(ReportUtils.getDocumentsDir(), pdfPath);
		String masterOfJrxml = printService.getMasterOfJrxml(u, r);
		String jrxmlFilePath = fileService.getJrxmlFilePath(masterOfJrxml, r);
		if (!fileService.isFileValid(file.getPath(), jrxmlFilePath)) {
			Map<String, Object> map = getPath(u, pr, r, w, o, pf, request, response);
			Boolean overload = (Boolean) map.get("overload");
			if (overload) {
				throw new IllegalStateException("数据量过大，无法提供服务");
			}
		}
		fileService.rangeDownload(file, n == null ? null : n + "."+ExportType.PDF.getQualifier(), request, response);
	}

	private Logger logger= LoggerFactory.getLogger(PdfController.class);

	/**
	 * 预览 pdf （Content Type 为 application/pdf）
	 *
	 * @param p
	 *            pdf 相对路径
	 * @param request
	 * @param response
	 */
	@RequestMapping(value = "/preview")
	@ResponseBody
	public void preview(@RequestParam String p, HttpServletRequest request, HttpServletResponse response)
			throws JRException, IOException, DocumentException, SQLException, IllegalStateException {
		File file = new File(ReportUtils.getDocumentsDir(), p);
		if(!file.getName().toLowerCase().endsWith(".pdf")){
			throw new IOException("并非 pdf 文件：" + p);
		}

        try (FileInputStream fis = new FileInputStream(file)) {
            response.setHeader("Content-Length", file.length() + "");
            response.setContentType("application/pdf");

            ServletOutputStream outputStream = response.getOutputStream();
            byte[] data = new byte[1024];
            int i;
            try {
                while ((i = fis.read(data)) != -1) {
                    outputStream.write(data, 0, i);
                }
                outputStream.flush();
            } catch (IOException e) {
                logger.error(e.getMessage());
            }
        }
	}
}
