package de.faustedition.facsimile;

import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import eu.interedition.image.ImageFile;
import eu.interedition.image.transform.Rotate;
import eu.interedition.image.transform.Scale;
import eu.interedition.image.transform.TransformList;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.representation.OutputRepresentation;
import org.restlet.representation.Representation;
import org.restlet.resource.Finder;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

/**
 * @author <a href="http://gregor.middell.net/" title="Homepage">Gregor Middell</a>
 */
@Component
public class FacsimileFinder extends Finder implements InitializingBean {

    @Autowired
    private Environment environment;
    private File home;
    private String fileExtension;

    @Override
    public void afterPropertiesSet() throws Exception {
        this.home = environment.getRequiredProperty("facsimile.home", File.class);
        this.fileExtension = environment.getRequiredProperty("facsimile.extension", String.class);
        Assert.isTrue(home.isDirectory(), home + " is not a directory");
    }

    @Override
    public ServerResource find(Request request, Response response) {
        try {
            final ImageFile facsimile = findFacsimile(request.getResourceRef().getRelativeRef().getPath());
            final Form query = request.getResourceRef().getQueryAsForm();
            final float zoom = Float.parseFloat(query.getFirstValue("zoom", "1"));
            final int rotate = Integer.parseInt(query.getFirstValue("rotate", "0"));
            return new FacsimileResource(facsimile, 1 / zoom, rotate);
        } catch (IOException e) {
            throw Throwables.propagate(e);
        } catch (IllegalArgumentException e) {
            return null;
        }
    }

    public ImageFile findFacsimile(String path) throws IOException, IllegalArgumentException {
        final File facsimile = new File(home, path + "." + fileExtension);
        if (facsimile.isFile() && isInHome(facsimile)) {
            return new ImageFile(facsimile);
        }
        throw new IllegalArgumentException(path);
    }

    public static class FacsimileResource extends ServerResource {

        private final ImageFile facsimile;
        private final float scale;
        private final int rotate;

        public FacsimileResource(ImageFile facsimile, float scale, int rotate) {
            this.facsimile = facsimile;
            this.scale = scale;
            this.rotate = rotate;
        }

        @Get("jpg")
        public Representation path() throws IOException {
            return new OutputRepresentation(MediaType.IMAGE_JPEG) {
                @Override
                public void write(OutputStream outputStream) throws IOException {
                    ImageFile.write(new TransformList(Lists.newArrayList(new Scale(2, scale), new Rotate(2, rotate))).apply(facsimile.read()), "JPEG", outputStream);
                }
            };
        }
    }

    private boolean isInHome(File file) {
        File parent = file.getParentFile();
        while (parent != null) {
            if (parent.equals(home)) {
                return true;
            }
            parent = parent.getParentFile();
        }
        return false;
    }

}

@@ -147,24 +147,69 @@
 .ImageFile;%0A
+import eu.interedition.image.transform.Crop;%0A
 import eu.in
@@ -684,16 +684,73 @@
 source;%0A
+import org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A
 import o
@@ -1002,16 +1002,35 @@
 ssert;%0A%0A
+import java.awt.*;%0A
 import j
@@ -1276,16 +1276,102 @@
 ngBean %7B
+%0A    private static final Logger LOG = LoggerFactory.getLogger(FacsimileFinder.class);
 %0A%0A    @A
@@ -2269,56 +2269,405 @@
     
-return new FacsimileResource(facsimile, 1 / zoom
+final Dimension facsimileSize = facsimile.getSize().getSize();%0A            final float tileSize = 256 / zoom;%0A            return new FacsimileResource(facsimile,%0A                    1 / zoom,%0A                    (((float) facsimileSize.getWidth()) / zoom - tileSize) / 2.0f,%0A                    (((float) facsimileSize.getHeight()) / zoom - tileSize) / 2.0f,%0A                    tileSize, tileSize
 , ro
@@ -3316,32 +3316,165 @@
 al float scale;%0A
+        private final float x;%0A        private final float y;%0A        private final float width;%0A        private final float height;%0A
         private 
@@ -3558,16 +3558,61 @@
 t scale,
+ float x, float y, float width, float height,
  int rot
@@ -3682,32 +3682,146 @@
 .scale = scale;%0A
+            this.x = x;%0A            this.y = y;%0A            this.width = width;%0A            this.height = height;%0A
             this
@@ -4095,32 +4095,177 @@
 s IOException %7B%0A
+                    LOG.debug(%22Writing %7B%7Dx%7B%7D+%7B%7D+%7B%7D of %7B%7D (scale %7B%7D, rotate %7B%7D)%22, new Object%5B%5D %7B width, height, x, y, facsimile, scale, rotate%7D);%0A
                 
@@ -4341,16 +4341,47 @@
  scale),
+ new Crop(x, y, width, height),
  new Rot

test image cropping