package org.openlca.app.cloud.index;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.mapdb.DB;
import org.mapdb.DBMaker;
import org.openlca.cloud.api.RepositoryClient;
import org.openlca.cloud.api.RepositoryConfig;
import org.openlca.cloud.model.data.Dataset;
import org.openlca.core.model.ModelType;
// NOT SYNCHRONIZED //
public class DiffIndex {
private File file;
private DB db;
private Map<String, Diff> index;
private Map<String, Set<String>> changedTopLevelElements;
public static DiffIndex getFor(RepositoryClient client) {
RepositoryConfig config = client.getConfig();
return new DiffIndex(new File(config.getDatabase()
.getFileStorageLocation(), "cloud/" + config.getRepositoryId()));
}
private DiffIndex(File indexDirectory) {
if (!indexDirectory.exists())
indexDirectory.mkdirs();
file = new File(indexDirectory, "indexfile");
createDb(file);
}
private void createDb(File file) {
db = DBMaker.fileDB(file).lockDisable().closeOnJvmShutdown().make();
index = db.hashMap("diffIndex");
changedTopLevelElements = db.hashMap("changedTopLevelElements");
}
public void close() {
if (!db.isClosed())
db.close();
}
public void clear() {
index.clear();
changedTopLevelElements.clear();
commit();
}
public void add(Dataset dataset, long localId) {
Diff diff = index.get(dataset.refId);
if (diff != null)
return;
diff = new Diff(dataset, DiffType.NO_DIFF);
diff.localId = localId;
index.put(dataset.refId, diff);
}
public void update(Dataset dataset, DiffType newType) {
Diff diff = index.get(dataset.refId);
if (diff.type == DiffType.NEW && newType == DiffType.DELETED) {
// user added something and then deleted it again
remove(dataset.refId);
return;
}
updateDiff(diff, dataset, newType);
}
private void updateDiff(Diff diff, Dataset dataset, DiffType newType) {
diff.type = newType;
if (newType == DiffType.NO_DIFF) {
updateParents(diff, false);
diff.dataset = dataset;
diff.changed = null;
} else {
diff.changed = dataset;
updateParents(diff, true);
}
if (dataset.categoryRefId == null)
updateChangedTopLevelElements(dataset, newType);
index.put(dataset.refId, diff);
}
private void updateChangedTopLevelElements(Dataset dataset, DiffType newType) {
String type = dataset.categoryType.name();
Set<String> elements = changedTopLevelElements.get(type);
if (elements == null)
elements = new HashSet<>();
if (newType == DiffType.NO_DIFF)
elements.remove(dataset.refId);
else
elements.add(dataset.refId);
if (elements.isEmpty())
changedTopLevelElements.remove(type);
else
changedTopLevelElements.put(type, elements);
}
public Diff get(String key) {
return index.get(key);
}
public List<Diff> getChanged() {
List<Diff> changed = new ArrayList<>();
for (Diff diff : index.values())
if (diff.hasChanged())
changed.add(diff);
return changed;
}
public List<Diff> getAll() {
return new ArrayList<>(index.values());
}
public boolean hasChanged(ModelType type) {
Set<String> elements = changedTopLevelElements.get(type.name());
return elements != null && !elements.isEmpty();
}
public void remove(String key) {
Diff diff = index.remove(key);
if (diff == null)
return;
updateChangedTopLevelElements(diff.getDataset(), DiffType.NO_DIFF);
updateParents(diff, false);
}
private void updateParents(Diff diff, boolean add) {
if (diff.changed != null) // case 1)
updateParents(diff.changed, add);
if (diff.dataset != null) // case 2)
updateParents(diff.dataset, add);
}
private void updateParents(Dataset dataset, boolean add) {
String parentId = dataset.categoryRefId;
while (parentId != null) {
Diff parent = index.get(parentId);
if (add)
parent.changedChildren.add(dataset.refId);
else
parent.changedChildren.remove(dataset.refId);
index.put(parentId, parent);
parentId = parent.dataset.categoryRefId;
}
if (add)
updateChangedTopLevelElements(dataset, DiffType.CHANGED);
else
updateChangedTopLevelElements(dataset, DiffType.NO_DIFF);
}
public void commit() {
db.commit();
}
}