package org.atlasapi.persistence.media.entity;
import java.util.Comparator;
import java.util.List;
import org.atlasapi.media.entity.Brand;
import org.atlasapi.media.entity.ChildRef;
import org.atlasapi.media.entity.Container;
import org.atlasapi.media.entity.EntityType;
import org.atlasapi.media.entity.ParentRef;
import org.atlasapi.media.entity.Series;
import org.atlasapi.media.entity.SeriesRef;
import org.atlasapi.media.entity.SortKey;
import org.atlasapi.persistence.content.mongo.DbObjectHashCodeDebugger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Ordering;
import com.metabroadcast.common.ids.NumberToShortStringCodec;
import com.metabroadcast.common.persistence.translator.TranslatorUtils;
import com.mongodb.DBObject;
public class ContainerTranslator {
private static final Logger log = LoggerFactory.getLogger(ContainerTranslator.class);
public static final String CONTAINER = "container";
public static final String CONTAINER_ID = "containerId";
public static final String CHILDREN_KEY = "childRefs";
private static final String SERIES_NUMBER_KEY = "seriesNumber";
private static final String TOTAL_EPISODES = "totalEpisodes";
public static final String FULL_SERIES_KEY = "series";
private final ContentTranslator contentTranslator;
private final ChildRefTranslator childRefTranslator;
private final SeriesRefTranslator seriesRefTranslator;
private final DbObjectHashCodeDebugger dboHashCodeDebugger = new DbObjectHashCodeDebugger();
private static final Ordering<ChildRef> CHILD_REF_OUTPUT_SORT = Ordering.from(new Comparator<ChildRef>() {
private Comparator<String> sortKeyComparator = new SortKey.SortKeyOutputComparator();
@Override
public int compare(ChildRef o1, ChildRef o2) {
return sortKeyComparator.compare(o1.getSortKey(), o2.getSortKey());
}
});
public ContainerTranslator(NumberToShortStringCodec idCodec) {
this.contentTranslator = new ContentTranslator(idCodec);
this.childRefTranslator = new ChildRefTranslator();
this.seriesRefTranslator = new SeriesRefTranslator();
}
public List<Container> fromDBObjects(Iterable<DBObject> dbObjects) {
ImmutableList.Builder<Container> containers = ImmutableList.builder();
if (dbObjects != null) {
for (DBObject dbObject : dbObjects) {
containers.add(fromDB(dbObject, false));
}
}
return containers.build();
}
public Container fromDB(DBObject dbObject) {
return fromDBObject(dbObject, null, false);
}
/**
*
* @param dbObject
* @param includeChildrenInHashCode should references to children be included in hash calculations.
* Generally this should be false, except where ChildRefs need to be maintained.
* @return
*/
public Container fromDB(DBObject dbObject, boolean includeChildrenInHashCode) {
return fromDBObject(dbObject, null, includeChildrenInHashCode);
}
public Container fromDBObject(DBObject dbObject, Container entity) {
return fromDBObject(dbObject, entity, false);
}
@SuppressWarnings("unchecked")
public Container fromDBObject(DBObject dbObject, Container entity, boolean includeChildrenInHashCode) {
if (entity == null) {
entity = (Container) DescribedTranslator.newModel(dbObject);
}
contentTranslator.fromDBObject(dbObject, entity);
Iterable<ChildRef> childRefs;
if (dbObject.containsField(CHILDREN_KEY)) {
childRefs = childRefTranslator.fromDBObjects((Iterable<DBObject>) dbObject.get(CHILDREN_KEY));
} else {
childRefs = ImmutableList.of();
}
entity.setChildRefs(CHILD_REF_OUTPUT_SORT.immutableSortedCopy(childRefs));
if (entity instanceof Series) {
Series series = (Series) entity;
series.withSeriesNumber((Integer) dbObject.get(SERIES_NUMBER_KEY));
Long containerId = TranslatorUtils.toLong(dbObject, CONTAINER_ID);
if(dbObject.containsField(CONTAINER)) {
series.setParentRef(new ParentRef((String)dbObject.get(CONTAINER), containerId));
}
series.setTotalEpisodes(TranslatorUtils.toInteger(dbObject, TOTAL_EPISODES));
}
if (entity instanceof Brand) {
((Brand) entity).setSeriesRefs(series((Iterable<DBObject>) dbObject.get(FULL_SERIES_KEY)));
}
entity.setReadHash(generateHashByRemovingFieldsFromTheDbo(dbObject, includeChildrenInHashCode));
return entity;
}
private String generateHashByRemovingFieldsFromTheDbo(DBObject dbObject, boolean includeChildren) {
contentTranslator.removeFieldsForHash(dbObject);
if (!includeChildren) {
dbObject.removeField(CHILDREN_KEY);
dbObject.removeField(FULL_SERIES_KEY);
}
if (log.isTraceEnabled()) {
dboHashCodeDebugger.logHashCodes(dbObject, log);
}
return String.valueOf(dbObject.hashCode());
}
public String hashCodeOf(Container container) {
return hashCodeOf(container, false);
}
public String hashCodeOf(Container container, boolean includeChildren) {
return generateHashByRemovingFieldsFromTheDbo(toDBO(container, true), includeChildren);
}
private List<SeriesRef> series(Iterable<DBObject> seriesDbos) {
if (seriesDbos != null) {
return SeriesRef.dedupeAndSort(seriesRefTranslator.fromDBObjects(seriesDbos));
}
return ImmutableList.of();
}
public DBObject toDB(Container entity) {
return toDBO(entity, false);
}
public DBObject toDBO(Container entity, boolean includeChildren) {
DBObject dbObject = toDBObject(null, entity);
if(includeChildren) {
dbObject.put(CHILDREN_KEY, childRefTranslator.toDBList(entity.getChildRefs()));
if (entity instanceof Brand) {
Brand brand = (Brand) entity;
if (!brand.getSeriesRefs().isEmpty()) {
dbObject.put(FULL_SERIES_KEY, seriesRefTranslator.toDBList(brand.getSeriesRefs()));
}
}
}
return dbObject;
}
public DBObject toDBObject(DBObject dbObject, Container entity) {
dbObject = toDboNotIncludingContents(dbObject, entity);
return dbObject;
}
private DBObject toDboNotIncludingContents(DBObject dbObject, Container entity) {
dbObject = contentTranslator.toDBObject(dbObject, entity);
dbObject.put(DescribedTranslator.TYPE_KEY, EntityType.from(entity).toString());
if (entity instanceof Series) {
Series series = (Series) entity;
if (series.getSeriesNumber() != null) {
dbObject.put(SERIES_NUMBER_KEY, series.getSeriesNumber());
}
if (series.getParent() != null) {
dbObject.put(CONTAINER, series.getParent().getUri());
dbObject.put(CONTAINER_ID, series.getParent().getId());
}
if(series.getTotalEpisodes() != null) {
TranslatorUtils.from(dbObject, TOTAL_EPISODES, series.getTotalEpisodes());
}
}
return dbObject;
}
}