package org.minimalj.frontend.impl.swing;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.prefs.BackingStoreException;
import java.util.prefs.PreferenceChangeEvent;
import java.util.prefs.PreferenceChangeListener;
import java.util.prefs.Preferences;

import org.minimalj.application.Application;

// for: java.util.prefs Could not open/create prefs root node Software\JavaSoft\Prefs
// see: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8139507
public class SwingFavorites implements PreferenceChangeListener {

	private final Consumer<LinkedHashMap<String, String>> changeListener;
	private Preferences preferences;

	public SwingFavorites(Consumer<LinkedHashMap<String, String>> changeListener) {
		Objects.requireNonNull(changeListener);
		
		setUser(null);

		this.changeListener = changeListener;
	}

	public void setUser(String user) {
		if (preferences != null) {
			preferences.removePreferenceChangeListener(this);
		}

		if (user != null) {
			preferences = Preferences.userNodeForPackage(Application.getInstance().getClass()).node("favoritesByUser").node(user);
		} else {
			preferences = Preferences.userNodeForPackage(Application.getInstance().getClass()).node("favorites");
		}			

		preferences.addPreferenceChangeListener(this);
		
		if (changeListener != null) {
			changeListener.accept(getFavorites());
		}
	}

	@Override
	public void preferenceChange(PreferenceChangeEvent evt) {
		changeListener.accept(getFavorites());
	}

	public LinkedHashMap<String, String> getFavorites() {
		try {
			String[] keys = preferences.keys();
			Arrays.sort(keys);
			LinkedHashMap<String, String> favorites = new LinkedHashMap<>();
			for (String key : keys) {
				try {
					String route = key.substring(key.indexOf("@") + 1);
					favorites.put(route, preferences.get(key, "Page"));
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			return favorites;
		} catch (BackingStoreException e) {
			// do nothing, favorites not available
			return new LinkedHashMap<>();
		}
	}

	public boolean isFavorite(String route) {
		return findKey(route) != null;
	}

	private String findKey(String route) {
		route = "@" + route;
		String[] keys;
		try {
			keys = preferences.keys();
			for (String key : keys) {
				if (key.endsWith(route)) {
					return key;
				}
			}
		} catch (BackingStoreException e) {
			// do nothing, favorites not available
		}
		return null;
	}

	private void addFavorite(String route, String title) {
		LocalDateTime time = LocalDateTime.now();
		String timeString = time.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);

		String key = timeString + "@" + route;
		preferences.put(key, title);
	}

	private void removeFavorite(String route) {
		route = "@" + route;
		String[] keys;
		try {
			keys = preferences.keys();
			for (String key : keys) {
				if (key.endsWith(route)) {
					preferences.remove(key);
				}
			}
		} catch (BackingStoreException e) {
			// do nothing, favorites not available
		}
	}

	public void toggleFavorite(String route, String title) {
		String key = findKey(route);
		if (key != null) {
			removeFavorite(route);
		} else {
			addFavorite(route, title);
		}
	}

}

@@ -234,24 +234,91 @@
 .Consumer;%0D%0A
+import java.util.logging.Level;%0D%0Aimport java.util.logging.Logger;%0D%0A
 import java.
@@ -352,16 +352,16 @@
 ption;%0D%0A
-
 import j
@@ -533,16 +533,57 @@
 cation;%0D
+%0Aimport org.minimalj.frontend.page.Page;%0D
 %0A%0D%0A// fo
@@ -734,16 +734,16 @@
 139507%0D%0A
-
 public c
@@ -800,16 +800,102 @@
 tener %7B%0D
+%0A%09private static final Logger LOG = Logger.getLogger(SwingFavorites.class.getName());%0D
 %0A%0D%0A%09priv
@@ -2149,24 +2149,64 @@
 %22@%22) + 1);%0D%0A
+%09%09%09%09%09if (Page.validateRoute(route)) %7B%0D%0A%09
 %09%09%09%09%09favorit
@@ -2259,56 +2259,224 @@
 %09%09%09%09
-%7D catch (Exception e) %7B%0D%0A%09%09%09%09%09e.printStackTrace(
+%09%7D else %7B%0D%0A%09%09%09%09%09%09LOG.warning(%22Invalid favorite: %22 + key);%0D%0A%09%09%09%09%09%09preferences.remove(key);%0D%0A%09%09%09%09%09%7D%0D%0A%09%09%09%09%7D catch (Exception e) %7B%0D%0A%09%09%09%09%09LOG.log(Level.WARNING, %22Invalid favorite: %22 + key, e);%0D%0A%09%09%09%09%09preferences.remove(key
 );%0D%0A
@@ -2541,32 +2541,90 @@
 Exception e) %7B%0D%0A
+%09%09%09LOG.log(Level.WARNING, %22Favorites not available%22, e);%0D%0A
 %09%09%09// do nothing

check favorites for valid page