package page.image;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.Semaphore;

import org.wikiwebserver.handler.http.FormData;
import org.wikiwebserver.handler.http.HTTPException;
import org.wikiwebserver.handler.http.HTTPHandler;
import org.wikiwebserver.handler.http.interfaces.*;

public class Fractal implements HTTPResponder {
    
    private static final int MAX_ITERATIONS = 200;
    private static final int CONCURRENCY_LEVEL = 4;
    private static final Semaphore cpuTime = new Semaphore(CONCURRENCY_LEVEL, true);
    
    
    private static BufferedImage mandelbrot(double wx, double wy, double s, 
                                 int width, int height) throws HTTPException {
        try {
            cpuTime.acquire();
            if (width > 2000) width = 2000;
            if (height > 2000) height = 2000;         
            
            BufferedImage i = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    double h = getHue(wx + s * x, wy + s * y);
                    double b = 1.0f - h*h;   
                    i.setRGB(x, y, Color.HSBtoRGB((float)h, 0.8f, (float)b));
                }
            }
            
            return i;
            
        } catch (InterruptedException ex) {
            throw new HTTPException(500, "Image generation interrupted.", ex);
        } finally {
            cpuTime.release();
        }
    }  
    
    private static double getHue(double wx, double wy) {
        double r = 0.0, i = 0.0, m = 0.0;
        int j;
        
        for (j=0; (j < MAX_ITERATIONS) && (m < 4.0); j++) {
            m = r*r - i*i + wx;
            i = 2.0 * r*i + wy;
            r = m;
        }
        return (double)j / MAX_ITERATIONS;
    }   
    
    public Object respond(HTTPHandler conn) throws IOException {  
        return respond(conn.getRequest().getFormData());
    }
    
    public Object respond(FormData formData) throws IOException {
        
        int width = 500;
        int height = 500;
        double x = -1.85f;
        double y = -1.25f; 
        double s = 0.005f;        
        
        if (formData != null) {
            width = (int) getDouble("w", width, formData); 
            height = (int) getDouble("h", height, formData);       
            x = getDouble("x", x, formData); 
            y = getDouble("y", y, formData);  
            s = getDouble("s", s, formData);
        }

        return mandelbrot(x, y, s, width, height);
    }
    
    private double getDouble(String name, double def, FormData formData) {
        try {
            return Double.parseDouble((String)formData.getFirst(name));
        } catch (Exception ex) {
            return def;
        }
    }    
}
