package org.openlca.app.db;

import org.openlca.core.database.EntityCache;
import org.openlca.core.database.IDatabase;
import org.openlca.core.matrix.cache.MatrixCache;
import org.openlca.core.model.ModelType;
import org.openlca.core.model.descriptors.Descriptor;
import org.openlca.util.Categories;
import org.openlca.util.Categories.PathBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Contains the cache management of the application.
 */
public final class Cache {

	private static Logger log = LoggerFactory.getLogger(Cache.class);
	private static AppCache appCache = new AppCache();
	private static EntityCache entityCache;
	private static MatrixCache matrixCache;
	private static PathBuilder pathCache;

	private Cache() {
	}

	public static EntityCache getEntityCache() {
		return entityCache;
	}

	public static MatrixCache getMatrixCache() {
		return matrixCache;
	}

	public static PathBuilder getPathCache() {
		return pathCache;
	}
	
	public static void close() {
		log.trace("close cache");
		evictAll();
		entityCache = null;
		matrixCache = null;
		appCache = null;
		pathCache = null;
	}

	/**
	 * Initializes the caches for the given database. Old cache instances are
	 * closed.
	 */
	public static void create(IDatabase database) {
		log.trace("create cache");
		close();
		entityCache = EntityCache.create(database);
		matrixCache = MatrixCache.createLazy(database);
		appCache = new AppCache();
		pathCache = Categories.pathsOf(database);
	}

	public static AppCache getAppCache() {
		return appCache;
	}

	public static void evict(Descriptor d) {
		if (d == null)
			return;
		log.trace("evict {} with ID {}", d.getClass(), d.id);
		if (d.type == null)
			evictAll(); // to be on the save side
		else if (shouldEvictAll(d.type)) {
			if (entityCache != null)
				entityCache.invalidateAll();
			evictFromMatrices(d);
		} else {
			evictEntity(d);
			evictFromMatrices(d);
		}
	}

	private static boolean shouldEvictAll(ModelType type) {
		return type != null && type.isOneOf(ModelType.UNIT, ModelType.UNIT_GROUP, ModelType.FLOW,
				ModelType.FLOW_PROPERTY, ModelType.CATEGORY);
	}

	public static void evictAll() {
		log.trace("evict all from caches");
		if (entityCache != null)
			entityCache.invalidateAll();
		if (matrixCache != null)
			matrixCache.evictAll();
		pathCache = Categories.pathsOf(Database.get());
	}

	private static void evictEntity(Descriptor d) {
		if (entityCache == null)
			return;
		long id = d.id;
		Class<?> clazz = d.getClass();
		log.trace("evict from entity cache {} with id={}", clazz, id);
		entityCache.invalidate(clazz, id);
		if (d.type == null)
			return;
		clazz = d.type.getModelClass();
		log.trace("evict from entity cache {} with id={}", clazz, id);
		entityCache.invalidate(clazz, id);
		if (d.type == ModelType.CATEGORY) {
			pathCache.remove(d.id);
		}
	}

	private static void evictFromMatrices(Descriptor d) {
		if (matrixCache == null)
			return;
		matrixCache.evict(d.type, d.id);
	}

	public static void registerNew(Descriptor descriptor) {
		if (matrixCache == null)
			return;
		log.trace("register new model {}", descriptor);
		matrixCache.registerNew(descriptor.type, descriptor.id);
	}

}

@@ -22,16 +22,43 @@
 pp.db;%0A%0A
+import java.util.Objects;%0A%0A
 import o
@@ -959,32 +959,154 @@
 etPathCache() %7B%0A
+%09%09if (pathCache == null) %7B%0A%09%09%09var db = Objects.requireNonNull(Database.get());%0A%09%09%09pathCache = Categories.pathsOf(db);%0A%09%09%7D%0A
 %09%09return pathCac
@@ -1112,17 +1112,16 @@
 che;%0A%09%7D%0A
-%09
 %0A%09public
@@ -1587,52 +1587,8 @@
 ();%0A
-%09%09pathCache = Categories.pathsOf(database);%0A
 %09%7D%0A%0A
@@ -2120,16 +2120,21 @@
 isOneOf(
+%0A%09%09%09%09
 ModelTyp
@@ -2140,17 +2140,21 @@
 pe.UNIT,
- 
+%0A%09%09%09%09
 ModelTyp
@@ -2166,17 +2166,21 @@
 T_GROUP,
- 
+%0A%09%09%09%09
 ModelTyp
@@ -2215,17 +2215,21 @@
 ROPERTY,
- 
+%0A%09%09%09%09
 ModelTyp
@@ -2338,24 +2338,26 @@
 che != null)
+ %7B
 %0A%09%09%09entityCa
@@ -2377,16 +2377,20 @@
 eAll();%0A
+%09%09%7D%0A
 %09%09if (ma
@@ -2403,24 +2403,26 @@
 che != null)
+ %7B
 %0A%09%09%09matrixCa
@@ -2437,16 +2437,20 @@
 tAll();%0A
+%09%09%7D%0A
 %09%09pathCa
@@ -2459,42 +2459,12 @@
 e = 
-Categories.pathsOf(Database.get())
+null
 ;%0A%09%7D
@@ -2872,32 +2872,53 @@
 azz, id);%0A%09%09if (
+pathCache != null && 
 d.type == ModelT

fix Cache.pathCache errors when updating a database