package de.faustedition.template;

import com.google.common.base.Functions;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import de.faustedition.FaustURI;
import de.faustedition.text.TextManager;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.restlet.data.*;
import org.restlet.engine.util.ConnegUtils;
import org.restlet.ext.freemarker.TemplateRepresentation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.*;

@Component
public class TemplateRepresentationFactory {
	private static final Logger LOG = LoggerFactory.getLogger(TemplateRepresentationFactory.class);

	private static final List<Language> SUPPORTED_LANGUAGES = Collections.unmodifiableList(//
			Lists.newArrayList(new Language("de"), new Language("en")));

	@Autowired
	private Configuration configuration;

	@Autowired
	private TextManager textManager;

	public TemplateRepresentation create(String path, ClientInfo client) throws IOException {
		return create(path, client, new HashMap<String, Object>());
	}

	public TemplateRepresentation create(String path, ClientInfo client, Map<String, Object> model) {
		final Language language = getPreferredMetadata(SUPPORTED_LANGUAGES, client.getAcceptedLanguages());
		final Locale locale = (language == null ? Locale.GERMAN : new Locale(language.getName()));

		Template template;
		try {
			if (LOG.isDebugEnabled()) {
				LOG.debug("Getting template for {} (locale: {})", path, locale);
			}
			template = configuration.getTemplate(path + ".ftl", locale);
			Preconditions.checkNotNull(template, "Cannot find template for " + path);
		} catch (IOException e) {
			throw Throwables.propagate(e);
		}

		model.put("roles", Lists.transform(client.getRoles(), Functions.toStringFunction()));
		
		final ResourceBundle messages = ResourceBundle.getBundle("messages", locale);
		if (LOG.isTraceEnabled()) {
			LOG.trace("Putting message resource bundle '" + messages.getLocale() + "' into model (requested locale " + locale + ")");
		}
		model.put("message", messages);

		final SortedMap<String, String> textTableOfContents = new TreeMap<String, String>();
		for (Map.Entry<FaustURI, String> tocEntry : textManager.tableOfContents().entrySet()) {
			final String textUriPath = tocEntry.getKey().getPath();
			final String textName = textUriPath.substring("/text/".length(), textUriPath.length() - ".xml".length());
			textTableOfContents.put(textName, tocEntry.getValue());
		}
		model.put("textToc", textTableOfContents);

		TemplateRepresentation representation = new TemplateRepresentation(template, model, MediaType.TEXT_HTML);
		representation.setLanguages(Collections.singletonList(language));

		return representation;
	}

	public static class TextTableOfContentsEntry {
		private final String path;
		private final String title;

		public TextTableOfContentsEntry(String path, String title) {
			this.path = path;
			this.title = title;
		}

		public String getPath() {
			return path;
		}

		public String getTitle() {
			return title;
		}
	}

	/**
	 * Copied from {@link ConnegUtils#getPreferredMetadata(List, List)} and
	 * patched to correctly update <code>maxQuality</code>.
	 * 
	 * @see ConnegUtils#getPreferredMetadata(List, List)
	 */
	private static <T extends Metadata> T getPreferredMetadata(List<T> supported, List<Preference<T>> preferences) {
		T result = null;
		float maxQuality = 0;

		if (supported != null) {
			for (Preference<T> pref : preferences) {
				if (supported.contains(pref.getMetadata()) && (pref.getQuality() > maxQuality)) {
					result = pref.getMetadata();
					// was not updated in original method
					maxQuality = pref.getQuality();
				}
			}
		}

		return result;
	}
}

@@ -1389,16 +1389,23 @@
 guage = 
+client.
 getPrefe
@@ -1408,24 +1408,24 @@
 referred
-Metadata
+Language
 (SUPPORT
@@ -1440,39 +1440,8 @@
 AGES
-, client.getAcceptedLanguages()
 );%0A%09
@@ -1629,18 +1629,20 @@
 ate for 
+'
 %7B%7D
+'
  (locale
@@ -1643,18 +1643,20 @@
 locale: 
+'
 %7B%7D
+'
 )%22, path
@@ -2131,36 +2131,10 @@
 le '
-%22 + messages.getLocale() + %22
+%7B%7D
 ' in
@@ -2164,24 +2164,44 @@
 ale 
-%22 +
+'%7B%7D')%22, messages.getLocale(),
  locale
- + %22)%22
 );%0A%09
@@ -3217,678 +3217,13 @@
 le;%0A
+
 %09%09%7D%0A%09%7D
-%0A%0A%09/**%0A%09 * Copied from %7B@link ConnegUtils#getPreferredMetadata(List, List)%7D and%0A%09 * patched to correctly update %3Ccode%3EmaxQuality%3C/code%3E.%0A%09 * %0A%09 * @see ConnegUtils#getPreferredMetadata(List, List)%0A%09 */%0A%09private static %3CT extends Metadata%3E T getPreferredMetadata(List%3CT%3E supported, List%3CPreference%3CT%3E%3E preferences) %7B%0A%09%09T result = null;%0A%09%09float maxQuality = 0;%0A%0A%09%09if (supported != null) %7B%0A%09%09%09for (Preference%3CT%3E pref : preferences) %7B%0A%09%09%09%09if (supported.contains(pref.getMetadata()) && (pref.getQuality() %3E maxQuality)) %7B%0A%09%09%09%09%09result = pref.getMetadata();%0A%09%09%09%09%09// was not updated in original method%0A%09%09%09%09%09maxQuality = pref.getQuality();%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%0A%0A%09%09return result;%0A%09%7D
 %0A%7D%0A

remove superseded restlet patch