/*
 * JGrapes Event Driven Framework
 * Copyright (C) 2016  Michael N. Lipp
 * 
 * This program is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 3 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License along 
 * with this program; if not, see <http://www.gnu.org/licenses/>.
 */
package org.jgrapes.http;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.text.ParseException;

import org.jdrupes.httpcodec.HttpResponse;
import org.jdrupes.httpcodec.HttpCodec.HttpStatus;
import org.jdrupes.httpcodec.fields.HttpField;
import org.jdrupes.httpcodec.fields.HttpMediaTypeField;
import org.jgrapes.core.Channel;
import org.jgrapes.core.Component;
import org.jgrapes.core.annotation.Handler;
import org.jgrapes.http.events.EndOfResponse;
import org.jgrapes.http.events.GetRequest;
import org.jgrapes.http.events.Response;
import org.jgrapes.io.Connection;
import org.jgrapes.io.FileStorage;
import org.jgrapes.io.events.Eof;
import org.jgrapes.io.events.OpenFile;

/**
 * @author Michael N. Lipp
 */
public class StaticContentDispatcher extends Component {

	private Path prefix;
	private Path contentDirectory;
	
	/**
	 * @see Component#Component()
	 */
	public StaticContentDispatcher(Path prefix, Path contentDirectory) {
		this(Channel.SELF, prefix, contentDirectory);
	}

	/**
	 * @see Component#Component(Channel)
	 */
	public StaticContentDispatcher(Channel componentChannel, Path prefix,
	        Path contentDirectory) {
		super(componentChannel);
		this.prefix = prefix;
		this.contentDirectory = contentDirectory;
	}

	@Handler
	public void onGet(GetRequest event) throws ParseException, IOException {
		Path requestPath = Paths
		        .get(event.getRequest().getRequestUri().getPath());
		if (!requestPath.startsWith(prefix)) {
			return;
		}
		Path resourcePath = contentDirectory
		        .resolve(prefix.relativize(requestPath));
		if (Files.isDirectory(resourcePath)) {
			Path indexPath = resourcePath.resolve("index.html");
			if (Files.isReadable(indexPath)) {
				resourcePath = indexPath;
			} else {
				return;
			}
		}
		if (!Files.isReadable(resourcePath)) {
			return;
		}
		String mimeTypeName = Files.probeContentType(resourcePath);
		if (mimeTypeName == null) {
			mimeTypeName = "application/octet-stream";
		}
		HttpMediaTypeField contentType = HttpMediaTypeField
		        .fromString(HttpField.CONTENT_TYPE, mimeTypeName);
		if (contentType.getBaseType().equals("text")) {
			contentType.setParameter("charset",
			        System.getProperty("file.encoding", "UTF-8"));
		}
		final HttpResponse response = event.getRequest().getResponse();
		final Connection connection = event.getConnection();
		response.setStatus(HttpStatus.OK);
		response.setMessageHasBody(true);
		response.setField(contentType);
		(new Response(connection, response)).fire();
		fire(new OpenFile(connection, resourcePath, StandardOpenOption.READ));
		event.stop();
	}

	@Handler
	public void onEof(Eof event) {
		(new EndOfResponse(event.getConnection())).fire();		
	}
	
}

@@ -940,16 +940,98 @@
 ception;
+%0Aimport java.util.Collections;%0Aimport java.util.Map;%0Aimport java.util.WeakHashMap;
 %0A%0Aimport
@@ -1501,43 +1501,8 @@
 on;%0A
-import org.jgrapes.io.FileStorage;%0A
 impo
@@ -1718,16 +1718,59 @@
 ectory;%0A
+%09private Map%3CConnection, Object%3E handling;%0A
 %09%0A%09/**%0A%09
@@ -2174,16 +2174,79 @@
 ectory;%0A
+%09%09handling = Collections.synchronizedMap(new WeakHashMap%3C%3E());%0A
 %09%7D%0A%0A%09@Ha
@@ -2815,16 +2815,61 @@
 rn;%0A%09%09%7D%0A
+%09%09handling.put(event.getConnection(), null);%0A
 %09%09String
@@ -3678,16 +3678,85 @@
 vent) %7B%0A
+%09%09if (!handling.containsKey(event.getConnection())) %7B%0A%09%09%09return;%0A%09%09%7D%0A
 %09%09(new E
@@ -3799,18 +3799,58 @@
 .fire();
+%0A
 %09%09
+handling.remove(event.getConnection());
 %0A%09%7D%0A%09%0A%7D%0A

Send end of response only once.