package freenet.clients.http;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.sql.Date;
import java.text.ParseException;

import javax.imageio.ImageIO;

import freenet.client.HighLevelSimpleClient;
import freenet.support.MultiValueTable;
import freenet.support.api.Bucket;
import freenet.support.api.HTTPRequest;

/** This toadlet creates a PNG image with the specified text. */
public class ImageCreatorToadlet extends Toadlet {

	/** The default width */
	public static final int		DEFAULT_WIDTH	= 100;

	/** The default height */
	public static final int		DEFAULT_HEIGHT	= 100;

	/**
	 * The last modification time of the class, it is required for the
	 * client-side cache.
	 * If anyone makes modifications to this class, this needs to be updated.
	 */
	public static final Date	LAST_MODIFIED	= new Date(1248256659000l);

	protected ImageCreatorToadlet(HighLevelSimpleClient client) {
		super(client);
	}

	public void handleMethodGET(URI uri, HTTPRequest req, ToadletContext ctx) throws ToadletContextClosedException, IOException, RedirectException {
		boolean needsGeneration = true;
		// If the browser has requested this image, then it will send this header
		if (ctx.getHeaders().containsKey("if-modified-since")) {
			try {
				// If the received date is equal to the last modification of this class, then it doesn't need regeneration
				if (ToadletContextImpl.parseHTTPDate(ctx.getHeaders().get("if-modified-since")).compareTo(LAST_MODIFIED) == 0) {
					// So we just send the NOT_MODIFIED response, and skip the generation
					ctx.sendReplyHeadersStatic(304, "Not Modified", null, "image/png", 0, LAST_MODIFIED);
					needsGeneration = false;
				}
			} catch (ParseException pe) {
				// If something goes wrong, we regenerate
			}
		}
		if (needsGeneration) {
			// The text that will be drawn
			String text = req.getParam("text");
			// If width or height is specified, we use it, if not, then we use the default
			int requiredWidth = req.getParam("width").compareTo("") != 0 ? Integer.parseInt(req.getParam("width").endsWith("px")?req.getParam("width").substring(0, req.getParam("width").length()-2):req.getParam("width")) : DEFAULT_WIDTH;
			int requiredHeight = req.getParam("height").compareTo("") != 0 ? Integer.parseInt(req.getParam("height").endsWith("px")?req.getParam("height").substring(0, req.getParam("height").length()-2):req.getParam("height")) : DEFAULT_HEIGHT;
			// This is the image we are making
			BufferedImage buffer = new BufferedImage(requiredWidth, requiredHeight, BufferedImage.TYPE_INT_RGB);
			Graphics2D g2 = buffer.createGraphics();
			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
			FontRenderContext fc = g2.getFontRenderContext();
			// We then specify the maximum font size that fits in the image
			// For this, we start at 1, and increase it, until it overflows. This-1 will be the font size
			float size = 1;
			g2.setFont(g2.getFont().deriveFont(size));
			int width = 0;
			int height = 0;
			while (width < requiredWidth && height < requiredHeight) {
				Rectangle2D bounds = g2.getFont().getStringBounds(text, fc);

				// calculate the size of the text
				width = (int) bounds.getWidth();
				height = (int) bounds.getHeight();
				g2.setFont(g2.getFont().deriveFont(++size));
			}
			g2.setFont(g2.getFont().deriveFont(size - 1));
			Rectangle2D bounds = g2.getFont().getStringBounds(text, fc);
			// actually do the drawing
			g2.setColor(new Color(0, 0, 0));
			g2.fillRect(0, 0, width, height);
			g2.setColor(new Color(255, 255, 255));
			// We position it to the center. Note that this is not the upper left corner
			g2.drawString(text, (int) (requiredWidth / 2 - bounds.getWidth() / 2), (int) (requiredHeight / 2 + bounds.getHeight() / 4));

			// Write the data, and send the modification data to let the client cache it
			Bucket data = ctx.getBucketFactory().makeBucket(-1);
			OutputStream os = data.getOutputStream();
			try {
				ImageIO.write(buffer, "png", os);
			} finally {
				os.close();
			}
			MultiValueTable<String, String> headers=new MultiValueTable<String, String>();
			ctx.sendReplyHeadersStatic(200, "OK", headers, "image/png", data.size(), LAST_MODIFIED);
			ctx.writeData(data);
		}
	}

	@Override
	public String path() {
		return "/imagecreator/";
	}

}
