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;

public class SwingFavorites implements PreferenceChangeListener {

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

	public SwingFavorites(Consumer<LinkedHashMap<String, String>> changeListener) {
		Objects.nonNull(changeListener);
		this.changeListener = changeListener;
	}

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

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

		changeListener.accept(getFavorites());
	}

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

	public LinkedHashMap<String, String> getFavorites() {
		if (preferences == null) {
			return new LinkedHashMap<>();
		}
		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);
		}
	}

}

@@ -469,16 +469,173 @@
 ion;%0D%0A%0D%0A
+// for: java.util.prefs Could not open/create prefs root node Software%5CJavaSoft%5CPrefs%0D%0A// see: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8139507%0D%0A
 public c
@@ -922,16 +922,40 @@
 ener);%0D%0A
+%09%09%0D%0A%09%09setUser(null);%0D%0A%0D%0A
 %09%09this.c
@@ -1118,32 +1118,8 @@
 );%0D%0A
-%09%09%09preferences = null;%0D%0A
 %09%09%7D%0D
@@ -1245,16 +1245,22 @@
 avorites
+ByUser
 %22).node(
@@ -1268,16 +1268,143 @@
 ser);%0D%0A%09
+%09%7D else %7B%0D%0A%09%09%09preferences = Preferences.userNodeForPackage(Application.getInstance().getClass()).node(%22favorites%22);%0D%0A%09%09%7D%09%09%09%0D%0A%0D%0A
 %09%09prefer
@@ -1447,21 +1447,52 @@
 is);%0D%0A%09%09
-%7D
 %0D%0A
+%09%09if (changeListener != null) %7B
 %0D%0A
+%09
 %09%09change
@@ -1521,24 +1521,29 @@
 orites());%0D%0A
+%09%09%7D%0D%0A
 %09%7D%0D%0A%0D%0A%09@Over
@@ -1716,77 +1716,8 @@
  %7B%0D%0A
-%09%09if (preferences == null) %7B%0D%0A%09%09%09return new LinkedHashMap%3C%3E();%0D%0A%09%09%7D%0D%0A
 %09%09tr

support for not authenticated applications