/*******************************************************************************
 * Copyright 2019 2Fi Business Solutions Ltd.
 *
 *
 *
 * This code is copyrighted. Under no circumstances should any party, people,
 * or organization should redistribute any portions of this code in any form,
 * either verbatim or through electronic media, to any third parties, unless
 * under explicit written permission by 2Fi Business Solutions Ltd.
 ******************************************************************************/
package com.ffii.tbms.file.web;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.ffii.core.utils.DateUtils;
import com.ffii.core.utils.NumberUtils;
import com.ffii.core.utils.Params;
import com.ffii.core.utils.StringUtils;
import com.ffii.core.web.AbstractController;
import com.ffii.tbms.file.File;
import com.ffii.tbms.file.FileBlob;
import com.ffii.tbms.file.service.FileService;
import java.awt.image.BufferedImage;

@Controller
@RequestMapping(value = "/file")
public class DownloadFileController extends AbstractController {

	private boolean ZIP_NUMBERER = false;

	@Autowired
	private FileService fileService;

	@RequestMapping(value = "/dl/{id}/{skey}/{filename}", method = RequestMethod.GET)
	public void download(HttpServletResponse response, @RequestParam(defaultValue = "false") boolean dl,
			@PathVariable int id, @PathVariable String skey) throws Exception {

		File file = fileService.findFileByIdAndKey(id, skey);

		if (file != null) {
			FileBlob fileBlob = fileService.findFileBlobByFileId(id);

			response.reset();
			response.setContentType(file.getMimetype());
			response.setContentLength((int) file.getFilesize());
			response.setHeader("Content-Transfer-Encoding", "binary");
			response.setHeader("Content-Disposition",
					String.format("%s; filename=\"%s\"", dl ? "attachment" : "inline", URLEncoder.encode(file.getFilename(), "UTF-8")));

			ServletOutputStream out = response.getOutputStream();

			try {
				out.write(fileBlob.getBytes());
				out.flush();
				out.close();
			} catch (IOException e) {
				logger.warn(e.getMessage());
			} finally {
				out.close();
			}
		} else {
			logger.info("*** 400 BAD REQUEST ***");
			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
		}
	}

	@RequestMapping(value = "/dlz", produces = "application/zip", method = RequestMethod.GET)
	public void downloadAsZip(HttpServletResponse response,
			@RequestParam String filename, @RequestParam String ids, @RequestParam String skeys) throws IOException {

		filename += DateUtils.formatDate(new Date(), "_yyyy_MM_dd_HHmm", "") + ".zip";

		response.setHeader("Content-Transfer-Encoding", "binary");
		response.setHeader("Content-Disposition",
				String.format("%s; filename=\"%s\"", "attachment", response.encodeURL(filename)));

		DecimalFormat df00 = new DecimalFormat("00");

		ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream());

		String[] idsA = StringUtils.split(ids, ',');
		String[] skeysA = StringUtils.split(skeys, ',');

		int filePrefixIdx = 1;

		for (int i = 0; i < idsA.length; i++) {
			int id = NumberUtils.intValue(idsA[i]);
			String skey = skeysA[i];

			File file = fileService.findFileByIdAndKey(id, skey);

			if (file == null) {
				logger.warn("*** file is null, id = " + id + ", skey = " + skey);
			} else {
				FileBlob fileBlob = fileService.findFileBlobByFileId(id);

				if (fileBlob == null) {
					logger.warn("*** fileBlob is null, id = " + id + ", skey = " + skey);
				} else {
					zipOutputStream.putNextEntry(new ZipEntry(ZIP_NUMBERER ? (df00.format(filePrefixIdx++) + "_" + file.getFilename())
							: file.getFilename()));
					zipOutputStream.write(fileBlob.getBytes());
					zipOutputStream.closeEntry();
				}
			}
		}
		zipOutputStream.flush();
		zipOutputStream.close();
	}

	@RequestMapping(value = "/thumbnail/{id}/{skey}/{filename}", method = RequestMethod.GET)
	public void thumbnail(HttpServletResponse response, Model model, @RequestParam(defaultValue = "false") boolean dl,
			@PathVariable int id, @PathVariable String skey) throws IOException {

		File file = fileService.findFileByIdAndKey(id, skey);

		if (file != null) {
			FileBlob fileBlob = fileService.findFileBlobByFileId(id);

			response.reset();
			response.setContentType(file.getMimetype());
			// response.setContentLength((int) file.getFilesize());
			response.setHeader("Content-Transfer-Encoding", "binary");
			response.setHeader("Content-Disposition", String.format("%s; filename=\"%s\"", dl ? "attachment" : "inline",
					response.encodeURL(file.getFilename())));

			int limit = 500;
			BufferedImage image = ImageIO.read(new ByteArrayInputStream(fileBlob.getBytes()));
			int width = image.getWidth();
			int height = image.getHeight();
			if (width > height) {
				if (width > limit) {
					height = height * limit / width;
					width = limit;
				}
			} else {
				if (height > limit) {
					width = width * limit / height;
					height = limit;
				}
			}
			image = scale(image, width, height);
			ByteArrayOutputStream tmp = new ByteArrayOutputStream();
			ImageIO.write(image, "jpg", tmp);
			tmp.close();
			response.setContentLength((int) tmp.size());

			ServletOutputStream out = response.getOutputStream();

			try {
				out.write(tmp.toByteArray());
				out.flush();
				out.close();
			} catch (IOException e) {
				logger.warn(e.getMessage());
			} finally {
				out.close();
				model.addAttribute(Params.SUCCESS, Boolean.TRUE);
			}
		} else {
			logger.info("*** 400 BAD REQUEST ***");
			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
			model.addAttribute(Params.SUCCESS, Boolean.FALSE);
		}
	}

	static BufferedImage scale(BufferedImage originalImage, int w, int h) {
		BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
		int x, y;
		int ww = originalImage.getWidth();
		int hh = originalImage.getHeight();
		for (x = 0; x < w; x++) {
			for (y = 0; y < h; y++) {
				int col = originalImage.getRGB(x * ww / w, y * hh / h);
				img.setRGB(x, y, col);
			}
		}
		return img;
	}

}
