package org.col.img;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.IllegalFormatException;
import java.util.function.Function;
import javax.imageio.ImageIO;

import org.col.api.exception.NotFoundException;
import org.col.api.model.Dataset;
import org.imgscalr.Scalr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ImageService {
  public static final String IMAGE_FORMAT = "png";
  private static final Logger LOG = LoggerFactory.getLogger(ImageService.class);
  
  private final ImgConfig cfg;
  
  public ImageService(ImgConfig cfg) {
    this.cfg = cfg;
  }
  
  public static BufferedImage read(InputStream img) throws IOException {
    if (img == null) {
      throw new IllegalArgumentException("No image content");
    }
    BufferedImage bi = ImageIO.read(img);
    if (bi == null) {
      throw new UnsupportedFormatException("Image format not supported");
    }
    return bi;
  }
  
  public void putDatasetLogo(Dataset dataset, BufferedImage img) throws IOException {
    // is it allowed?
    if (dataset.getLogo() != null) {
      throw new IllegalArgumentException("Dataset is already configured with an external logo URL "+dataset.getLogo());
    }
    storeAllImageSizes(img, s -> cfg.datasetLogo(dataset.getKey(), s));
  }
  
  public void putColSourceLogo(int colSourceKey, BufferedImage img) throws IOException {
    storeAllImageSizes(img, s -> cfg.sourceLogo(colSourceKey, s));
  }
  
  
  private void storeAllImageSizes(BufferedImage img, Function<ImgConfig.Scale, Path> locator) throws IOException {
    if (img == null) {
      LOG.debug("Delete all sizes for image {}", locator.apply(ImgConfig.Scale.ORIGINAL));
      for (ImgConfig.Scale scale : ImgConfig.Scale.values()) {
        Path p = locator.apply(scale);
        Files.delete(p);
      }
    } else {
      writeImage(locator.apply(ImgConfig.Scale.ORIGINAL), img);
      writeImage(locator.apply(ImgConfig.Scale.LARGE), scale(img, ImgConfig.Scale.LARGE));
      writeImage(locator.apply(ImgConfig.Scale.SMALL), scale(img, ImgConfig.Scale.SMALL));
    }
  }
  
  private BufferedImage scale(BufferedImage raw, ImgConfig.Scale scale) {
    final Size size = cfg.size(scale);
    return Scalr.resize(raw, Scalr.Method.ULTRA_QUALITY , size.getWidth(), size.getHeight());
  }

  private void writeImage(Path p, BufferedImage img) throws IOException {
    LOG.debug("Writing new image {}", p);
    ImageIO.write(img, IMAGE_FORMAT, p.toFile());
  }

  
  public BufferedImage datasetLogo(int datasetKey, ImgConfig.Scale scale) {
    Path p = cfg.datasetLogo(datasetKey, scale);
    return readImage(p, "Dataset "+datasetKey+" has no logo");
  }
  
  public BufferedImage colSourceLogo(int colSourceKey, ImgConfig.Scale scale) {
    Path p = cfg.sourceLogo(colSourceKey, scale);
    return readImage(p, "Source "+colSourceKey+" has no logo");
  }
  
  private BufferedImage readImage(Path p, String notFoundMsg) throws NotFoundException {
    try {
      if (!Files.exists(p)) {
        throw new NotFoundException(notFoundMsg);
      }
      return ImageIO.read(p.toFile());
    } catch (IOException e) {
      throw new RuntimeException("Failed to read image "+p, e);
    }
  }
}

@@ -167,49 +167,8 @@
 th;%0A
-import java.util.IllegalFormatException;%0A
 impo
@@ -1613,32 +1613,44 @@
 s IOException %7B%0A
+    try %7B%0A  
     if (img == n
@@ -1652,24 +1652,26 @@
  == null) %7B%0A
+  
       LOG.de
@@ -1755,16 +1755,18 @@
 ;%0A      
+  
 for (Img
@@ -1818,24 +1818,26 @@
 ) %7B%0A        
+ 
+ 
 Path p = loc
@@ -1863,16 +1863,18 @@
         
+  
 Files.de
@@ -1878,24 +1878,26 @@
 .delete(p);%0A
+  
       %7D%0A    
@@ -1896,16 +1896,18 @@
   %7D%0A    
+  
 %7D else %7B
@@ -1907,16 +1907,188 @@
  else %7B%0A
+        Path parent = locator.apply(ImgConfig.Scale.ORIGINAL).getParent();%0A        if (!Files.isDirectory(parent)) %7B%0A          Files.createDirectories(parent);%0A        %7D%0A  
       wr
@@ -2141,32 +2141,34 @@
 L), img);%0A      
+ 
+ 
 writeImage(locat
@@ -2238,24 +2238,26 @@
 GE));%0A      
+  
 writeImage(l
@@ -2325,24 +2325,174 @@
 le.SMALL));%0A
+      %7D%0A    %7D catch (IOException e) %7B%0A      LOG.error(%22Failed to update all sizes for image %7B%7D %7B%7D%22, locator.apply(ImgConfig.Scale.ORIGINAL), img, e);%0A
     %7D%0A  %7D%0A  

Create missing img dirs