package com.ffii.core.common.file.web;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLEncoder;

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

import org.apache.commons.lang3.tuple.Pair;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.ffii.core.common.file.entity.File;
import com.ffii.core.common.file.entity.FileBlob;
import com.ffii.core.common.file.service.FileService;
import com.ffii.core.exception.NotFoundException;
import com.ffii.core.support.AbstractController;

/** @author Fung */
@RestController
@RequestMapping("/protected/file/dl")
public class FileDownloadController extends AbstractController {

  private FileService service;

  public FileDownloadController(FileService service) {
    this.service = service;
  }

  @GetMapping("/{id}/{skey}/{filename}")
  public void download(
      HttpServletResponse response,
      @RequestParam(defaultValue = "false") boolean dl,
      @PathVariable int id,
      @PathVariable String skey,
      @PathVariable String filename) throws IOException {

    Pair<File, FileBlob> pair = service.loadFile(id, skey, filename);
    if (pair.getLeft() == null || pair.getRight() == null) {
      throw new NotFoundException();
    }

    File file = pair.getLeft();
    FileBlob blob = pair.getRight();

    response.setContentType(file.getMimetype());
    response.setContentLengthLong(file.getFilesize());
    response.setHeader("content-disposition",
        String.format("%s; filename=\"%s\"", dl ? "attachment" : "inline",
            URLEncoder.encode(filename, "UTF-8")));

    try (final ServletOutputStream out = response.getOutputStream()) {
      out.write(blob.getBytes());
    }
  }

  @GetMapping("/thumbnail/{id}/{skey}/{filename}")
  public void thumbnail(HttpServletResponse response, @RequestParam(defaultValue = "false") boolean dl,
      @PathVariable int id, @PathVariable String skey,
      @PathVariable String filename) throws IOException {

    Pair<File, FileBlob> pair = service.loadFile(id, skey, filename);
    if (pair.getLeft() == null || pair.getRight() == null) {
      throw new NotFoundException();
    }

    File file = pair.getLeft();
    FileBlob blob = pair.getRight();

    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() + "." + file.getExtension())));

    int limit = 100;
    BufferedImage image = ImageIO.read(new ByteArrayInputStream(blob.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);
    try (ByteArrayOutputStream tmp = new ByteArrayOutputStream()) {
      ImageIO.write(image, file.getExtension(), tmp);
      response.setContentLength((int) tmp.size());

      try (ServletOutputStream out = response.getOutputStream()) {
        out.write(tmp.toByteArray());
      } catch (IOException e) {
        logger.warn(e.getMessage());
      }
    }
  }

  public 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;
  }
}
