package page.example;


import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;

import org.wikiwebserver.core.WareHouse;
import org.wikiwebserver.handler.http.FormData;
import org.wikiwebserver.handler.http.HTTPException;
import org.wikiwebserver.handler.http.interfaces.HTTPResponder;
import page.config.SiteTemplatedPage;
import page.image.Fractal;

import org.wikiwebserver.util.comparator.FileModifiedComparator;

import static org.wikiwebserver.html.HTMLHelper.*;


import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class FractalGallery extends SiteTemplatedPage implements HTTPResponder {
    
    private String storeLocation = "image/.fractals/";
    private static final int THUMBNAIL_WIDTH = 150;
    private static final double START_X = -1.85f;
    private static final double START_Y = -1.25f; 
    private static final double START_S = 0.004f;      
	
    public void generate() throws HTTPException {
        
        setTitle("Fractal Gallery - WikiWebServer.org");
        addResourceRoot("/templates/default/fractal/");
        addCSSLink("fractal.css");
        
        int w = 700;
        int h = 600;
        boolean home = true;
        double x = START_X;
        double y = START_Y; 
        double s = START_S;      

        // Obtain fractal properties
        FormData formData = getFormData();
        if (formData != null) {
            String action = formData.getFirst("action");
            if (action == null || !action.equals("Home")) {
                home = false;  
                w = (int) getDouble("w", w, formData); 
                h = (int) getDouble("h", h, formData);             
                x = getDouble("x", START_X, formData); 
                y = getDouble("y", START_Y, formData);  
                s = getDouble("s", START_S, formData);
                int idx = getRequest().getQuery().indexOf('?');
                if (idx > -1) {
                    // Zoom into clicked location
                    String coords = getRequest().getQuery().substring(idx+1);
                    String[] parts = coords.split(",");
                    int clickX = Integer.parseInt(parts[0]);
                    int clickY = Integer.parseInt(parts[1]);
                    x += (clickX - (w/4)) * s;
                    y += (clickY - (h/4)) * s;
                    s /= 2;
                }
            }
            
            if (action != null && action.equals("del")) {
                home = true;
                createFile(s, x, y).delete();
            }
            
            if (action != null && action.equals("Save snapshot")) {
                try {
                    Fractal fracGen = new Fractal();
                    BufferedImage frac = (BufferedImage) fracGen.respond(getFormData());
                    saveThumb(frac, createFile(s, x, y));
                } catch (Exception ex) {
                    throw new HTTPException(500, "Failed to save snapshot");
                }
            }            
        }
        
        if (home) {
            x = START_X;
            y = START_Y; 
            s = START_S;              
        }
        
        String params = "?w=" + w + "&h=" + h + "&s=" + s + "&x=" + x + "&y=" + y + "&";
        append(a(WareHouse.getUrlPathForClass(page.example.FractalGallery.class) + params,
               image(WareHouse.getUrlPathForClass(page.image.Fractal.class) + params, 
                     "FractalGallery Image, click to zoom",
                     "width='" + w + "' height='" + h + "' ismap='true'")));
        
        if (!home) {
            append("<h2>Options</h2>");
            String action = getRequest().getUrl();  
            append("<form action='" + action + "' method='get'>");
            append("<input type='hidden' name='w' value='" + w + "'/>");
            append("<input type='hidden' name='h' value='" + h + "'/>");            
            append("<input type='hidden' name='x' value='" + x + "'/>");
            append("<input type='hidden' name='y' value='" + y + "'/>");
            append("<input type='hidden' name='s' value='" + s + "'/>");
            append("<input class='submit' type='button' value='Back' onclick='history.go(-1)'/>");
            append("<input class='submit' type='submit' name='action' value='Home'/>");
            append("<input class='submit' type='submit' name='action' value='Save snapshot'/>");
            append("</form>");
            
        } else {
            append("<p>Click the fractal to zoom in.</p>");            
        }

        append("<h2><a name='snapshots'></a>Snapshots</h2>");
        append(createGallery());        
        
        append("<div class='sourceOptions'>");
        append("<h2>View Source Code</h2>");
        String gallerySource = "/page/example/FractalGallery.java";
        String imgSource = "/image/Fractal.java";
        String editUrl = WareHouse.SOURCE_EDITOR_URL + "?path=";
        append("<ul>");
        append("<li><a href='" + editUrl + imgSource + "'>Fractal.java</a></li>");
        append("<li><a href='" + editUrl + gallerySource + "'>FractalGallery.java</a></li>");
        append("</ul>");
        append("</div>");
    }
    
    private double getDouble(String name, double def, FormData formData) {
        try {
            return Double.parseDouble(formData.getFirst(name));
        } catch (Exception ex) {
            return def;
        }
    }
    
    private File createFile(double s, double x, double y) {
        File dir = new File(storeLocation);
        dir.mkdir();
        return new File(dir, getFileName(s, x, y));
    }
    
    private String getFileName(double s, double x, double y) {
        return s + "_" + x + "_" + y + ".jpg";
    }    
    
    private String createGallery() {
        StringBuilder gallery = new StringBuilder();
        File dir = new File(storeLocation);
        if (dir.exists() && dir.isDirectory()) {
            File[] files = dir.listFiles();
            Arrays.sort(files, new FileModifiedComparator());
            for (File file : files) {
                try {
                    String filename = file.getName();
                    if (!filename.endsWith(".jpg")) continue;
                    int idx = filename.indexOf(".jpg");
                    String s = filename.substring(0, idx);
                    String[] args = s.split("_");
                    if (args.length == 3) {
                        String params = "?s=" + args[0] + "&amp;x=" + args[1] + "&amp;y=" + args[2];
                        String url = "FractalGallery.class" + params;
                        gallery.append("<div class='thumbBox'>");
                        gallery.append("<a href='" + url + "'>");
                        gallery.append(image("/" + storeLocation + filename, "Fractal snapshot"));
                        gallery.append("</a><br/>[ ");
                        gallery.append("<a href='" + url + "'>view</a> | ");
                        gallery.append("<a href='" + url + "&amp;action=del#snapshots'>");
                        gallery.append("delete</a> ]");                    
                        gallery.append("</div>");
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                
            }
        }
        return gallery.toString();
    }
    
    private void saveThumb(BufferedImage image, File file) throws IOException {
        int w = THUMBNAIL_WIDTH;
        int h = (int) (w * ((double) image.getHeight() / image.getWidth()));
        BufferedImage thumb = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = thumb.createGraphics();
        g.drawImage(image, 0, 0, w, h, null);
        saveImage(thumb, file);     
    }    
    
    private void saveImage(BufferedImage image, File file) throws IOException {    

        file.getParentFile().mkdirs();
        FileOutputStream fout = null;
        try {
            fout = new FileOutputStream(file);
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(fout);
            JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(image);
            param.setQuality(0.95f, false);
            encoder.setJPEGEncodeParam(param);
            encoder.encode(image);
        } finally {
            fout.close();   
            image.flush();
        }
      
    }    
}