package com.psddev.cms.db;
import java.io.Closeable;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import com.psddev.dari.db.DatabaseEnvironment;
import com.psddev.dari.db.ForwardingDatabase;
import com.psddev.dari.db.Query;
import com.psddev.dari.db.State;
import com.psddev.dari.util.PaginatedResult;
public class PreviewDatabase extends ForwardingDatabase {
private Date date;
private final Map<UUID, Map<String, Map<String, Object>>> differencesById = new HashMap<>();
private Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public void addChanges(Schedule schedule) {
for (Draft draft : Query
.from(Draft.class)
.where("schedule = ?", schedule)
.selectAll()) {
differencesById.put(draft.getObjectId(), draft.getDifferences());
}
}
// --- ForwardingDatabase support ---
public <T> T applyChanges(T object) {
if (object != null) {
State state = State.getInstance(object);
state.setResolveInvisible(true);
Date date = getDate();
DatabaseEnvironment environment = state.getDatabase().getEnvironment();
if (date != null) {
Draft draft = null;
Date draftDate = null;
for (Object dObject : Query
.fromAll()
.and("com.psddev.cms.db.Draft/schedule != missing")
.and("com.psddev.cms.db.Draft/objectId = ?", object)
.resolveInvisible()
.iterable(0)) {
if (!(dObject instanceof Draft)) {
continue;
}
Draft d = (Draft) dObject;
Schedule schedule = d.getSchedule();
Date triggerDate = schedule != null ? schedule.getTriggerDate() : null;
if (triggerDate != null
&& triggerDate.before(date)
&& (draftDate == null
|| triggerDate.after(draftDate))) {
draft = d;
draftDate = triggerDate;
}
}
if (draft != null) {
state.setValues(Draft.mergeDifferences(
environment,
state.getSimpleValues(),
draft.getDifferences()));
}
} else {
Map<String, Map<String, Object>> differences = differencesById.get(state.getId());
if (differences != null) {
state.setValues(Draft.mergeDifferences(
environment,
state.getSimpleValues(),
differences));
}
}
}
return object;
}
@Override
public <T> List<T> readAll(Query<T> query) {
query.setResolveInvisible(true);
List<T> all = super.readAll(query);
for (T item : all) {
applyChanges(item);
}
return all;
}
@Override
public <T> T readFirst(Query<T> query) {
query.setResolveInvisible(true);
return applyChanges(super.readFirst(query));
}
@Override
public <T> Iterable<T> readIterable(Query<T> query, int fetchSize) {
query.setResolveInvisible(true);
return new FilteringIterable<T>(super.readIterable(query, fetchSize));
}
private class FilteringIterable<E> implements Iterable<E> {
private final Iterable<E> delegate;
public FilteringIterable(Iterable<E> delegate) {
this.delegate = delegate;
}
@Override
public Iterator<E> iterator() {
return new FilteringIterator<E>(delegate.iterator());
}
}
private class FilteringIterator<E> implements Closeable, Iterator<E> {
private final Iterator<E> delegate;
public FilteringIterator(Iterator<E> delegate) {
this.delegate = delegate;
}
@Override
public void close() throws IOException {
if (delegate instanceof Closeable) {
((Closeable) delegate).close();
}
}
@Override
public boolean hasNext() {
return delegate.hasNext();
}
@Override
public E next() {
return applyChanges(delegate.next());
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
@Override
public <T> PaginatedResult<T> readPartial(Query<T> query, long offset, int limit) {
query.setResolveInvisible(true);
PaginatedResult<T> result = super.readPartial(query, offset, limit);
for (T item : result.getItems()) {
applyChanges(item);
}
return result;
}
// --- Deprecated ---
@Deprecated
@Override
public <T> List<T> readList(Query<T> query) {
return readAll(query);
}
}