package fi.otavanopisto.muikku.plugins.material;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.enterprise.context.Dependent;
import javax.enterprise.event.Event;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import fi.foyt.coops.CoOpsConflictException;
import fi.foyt.coops.CoOpsInternalErrorException;
import fi.otavanopisto.muikku.plugins.material.coops.CoOpsDiffAlgorithm;
import fi.otavanopisto.muikku.plugins.material.coops.dao.HtmlMaterialRevisionDAO;
import fi.otavanopisto.muikku.plugins.material.coops.dao.HtmlMaterialRevisionExtensionPropertyDAO;
import fi.otavanopisto.muikku.plugins.material.coops.dao.HtmlMaterialRevisionPropertyDAO;
import fi.otavanopisto.muikku.plugins.material.coops.model.HtmlMaterialRevision;
import fi.otavanopisto.muikku.plugins.material.coops.model.HtmlMaterialRevisionExtensionProperty;
import fi.otavanopisto.muikku.plugins.material.coops.model.HtmlMaterialRevisionProperty;
import fi.otavanopisto.muikku.plugins.material.dao.HtmlMaterialDAO;
import fi.otavanopisto.muikku.plugins.material.events.HtmlMaterialCreateEvent;
import fi.otavanopisto.muikku.plugins.material.events.HtmlMaterialDeleteEvent;
import fi.otavanopisto.muikku.plugins.material.events.HtmlMaterialUpdateEvent;
import fi.otavanopisto.muikku.plugins.material.model.HtmlMaterial;
import fi.otavanopisto.muikku.plugins.material.model.MaterialViewRestrict;
import fi.otavanopisto.muikku.plugins.workspace.WorkspaceMaterialContainsAnswersExeption;
@Dependent
public class HtmlMaterialController {
@Inject
private HtmlMaterialDAO htmlMaterialDAO;
@Inject
private HtmlMaterialRevisionDAO htmlMaterialRevisionDAO;
@Inject
private HtmlMaterialRevisionPropertyDAO htmlMaterialRevisionPropertyDAO;
@Inject
private HtmlMaterialRevisionExtensionPropertyDAO htmlMaterialRevisionExtensionPropertyDAO;
@Inject
@Any
private Instance<CoOpsDiffAlgorithm> algorithms;
@Inject
private Event<HtmlMaterialCreateEvent> materialCreateEvent;
@Inject
private Event<HtmlMaterialDeleteEvent> materialDeleteEvent;
@Inject
private Event<HtmlMaterialUpdateEvent> materialUpdateEvent;
public HtmlMaterial createHtmlMaterial(String title, String html, String contentType, Long revisionNumber, String license) {
return createHtmlMaterial(title, html, contentType, revisionNumber, null, license, MaterialViewRestrict.NONE);
}
public HtmlMaterial createHtmlMaterial(String title, String html, String contentType, Long revisionNumber, HtmlMaterial originMaterial, String license, MaterialViewRestrict visibility) {
HtmlMaterial material = htmlMaterialDAO.create(title, html, contentType, revisionNumber, originMaterial, license, visibility);
materialCreateEvent.fire(new HtmlMaterialCreateEvent(material));
return material;
}
public HtmlMaterial findHtmlMaterialById(Long id) {
return htmlMaterialDAO.findById(id);
}
public HtmlMaterial updateHtmlMaterialTitle(HtmlMaterial htmlMaterial, String title) {
return htmlMaterialDAO.updateTitle(htmlMaterial, title);
}
public void deleteHtmlMaterial(HtmlMaterial htmlMaterial) {
// TODO Logic for remove answers flag
materialDeleteEvent.fire(new HtmlMaterialDeleteEvent(htmlMaterial, false));
htmlMaterialDAO.delete(htmlMaterial);
}
public HtmlMaterial updateHtmlMaterialHtml(HtmlMaterial htmlMaterial, String html) {
return updateHtmlMaterialHtml(htmlMaterial, html, false);
}
public HtmlMaterial updateHtmlMaterialHtml(HtmlMaterial htmlMaterial, String html, boolean removeAnswers) {
HtmlMaterialUpdateEvent event = new HtmlMaterialUpdateEvent(htmlMaterial, htmlMaterial.getHtml(), html, removeAnswers);
materialUpdateEvent.fire(event);
return htmlMaterialDAO.updateData(htmlMaterial, html);
}
public HtmlMaterial updateHtmlMaterialToRevision(HtmlMaterial htmlMaterial, String html, Long revisionNumber, boolean removeNewerRevisions, boolean removeAnswers) throws WorkspaceMaterialContainsAnswersExeption {
// TODO: WorkspaceMaterialContainsAnswersExeption quick fix should be removed
try {
updateHtmlMaterialHtml(htmlMaterial, html, removeAnswers);
} catch (Exception e) {
Throwable cause = e;
while (cause != null) {
cause = cause.getCause();
if (cause instanceof WorkspaceMaterialContainsAnswersExeption) {
throw (WorkspaceMaterialContainsAnswersExeption) cause;
}
}
throw e;
}
htmlMaterialDAO.updateRevisionNumber(htmlMaterial, revisionNumber);
if (removeNewerRevisions) {
for (HtmlMaterialRevision revision : listRevisionsAfter(htmlMaterial, revisionNumber)) {
deleteRevision(revision);
}
}
return htmlMaterial;
}
public String getRevisionHtml(HtmlMaterial htmlMaterial, long revision) throws CoOpsInternalErrorException {
String result = htmlMaterial.getHtml();
if (result == null) {
result = "";
}
long baselineRevision = htmlMaterial.getRevisionNumber();
CoOpsDiffAlgorithm algorithm = findAlgorithm("dmp");
if (revision < baselineRevision) {
List<HtmlMaterialRevision> revisions = htmlMaterialRevisionDAO.listByFileAndRevisionGeAndRevisonLtOrderedByRevision(htmlMaterial, revision, baselineRevision);
for (int i = revisions.size() - 1; i >= 0; i--) {
HtmlMaterialRevision patchingRevision = revisions.get(i);
try {
if (patchingRevision.getData() != null) {
result = algorithm.unpatch(result, patchingRevision.getData());
}
} catch (CoOpsConflictException e) {
throw new CoOpsInternalErrorException("Patch failed when building material revision number " + revision);
}
}
} else {
List<HtmlMaterialRevision> revisions = htmlMaterialRevisionDAO.listByFileAndRevisionGtAndRevisonLeOrderedByRevision(htmlMaterial, baselineRevision, revision);
for (HtmlMaterialRevision patchingRevision : revisions) {
try {
if (patchingRevision.getData() != null) {
result = algorithm.patch(result, patchingRevision.getData());
}
} catch (CoOpsConflictException e) {
throw new CoOpsInternalErrorException("Patch failed when building material revision number " + revision);
}
}
}
return result;
}
public String getRevisionProperty(HtmlMaterial htmlMaterial, Long revisionNumber, String property) {
HtmlMaterialRevisionProperty revisionProperty = null;
if (revisionNumber > htmlMaterial.getRevisionNumber()) {
revisionProperty = htmlMaterialRevisionPropertyDAO.findByHtmlMaterialAndKeyMaxRevision(htmlMaterial, property);
} else {
revisionProperty = htmlMaterialRevisionPropertyDAO.findByHtmlMaterialAndKeyRevisionLeAndMaxRevision(htmlMaterial, property, htmlMaterial.getRevisionNumber());
}
if (revisionProperty == null) {
return null;
} else {
return revisionProperty.getValue();
}
}
public Map<String, String> getRevisionProperties(HtmlMaterial htmlMaterial, Long revisionNumber) {
Map<String, String> result = new HashMap<>();
for (String key : htmlMaterialRevisionPropertyDAO.listKeysByHtmlMaterial(htmlMaterial)) {
String value = getRevisionProperty(htmlMaterial, revisionNumber, key);
if (value != null) {
result.put(key, value);
}
}
return result;
}
public long lastHtmlMaterialRevision(HtmlMaterial htmlMaterial) {
Long maxRevision = htmlMaterialRevisionDAO.maxRevisionByHtmlMaterial(htmlMaterial);
if (maxRevision == null) {
maxRevision = 0l;
}
return maxRevision;
}
/* HtmlMaterialRevision */
public HtmlMaterialRevision createRevision(HtmlMaterial htmlMaterial, String sessionId, Long patchRevisionNumber, Date date, String patch, String checksum) {
return htmlMaterialRevisionDAO.create(htmlMaterial, sessionId, patchRevisionNumber, new Date(), patch, checksum);
}
public List<HtmlMaterialRevision> listRevisionsAfter(HtmlMaterial htmlMaterial, Long revisionNumber) {
return htmlMaterialRevisionDAO.listByFileAndRevisionGreaterThanOrderedByRevision(htmlMaterial, revisionNumber);
}
private void deleteRevision(HtmlMaterialRevision revision) {
List<HtmlMaterialRevisionExtensionProperty> extensionProperties = listRevisionExtensionProperties(revision);
List<HtmlMaterialRevisionProperty> properties = listRevisionProperties(revision);
for (HtmlMaterialRevisionExtensionProperty extensionProperty : extensionProperties) {
htmlMaterialRevisionExtensionPropertyDAO.delete(extensionProperty);
}
for (HtmlMaterialRevisionProperty property : properties) {
htmlMaterialRevisionPropertyDAO.delete(property);
}
htmlMaterialRevisionDAO.delete(revision);
}
/* HtmlMaterialRevisionProperty */
public HtmlMaterialRevisionProperty createRevisionProperty(HtmlMaterialRevision htmlMaterialRevision, String key, String value) {
return htmlMaterialRevisionPropertyDAO.create(htmlMaterialRevision, key, value);
}
public List<HtmlMaterialRevisionProperty> listRevisionProperties(HtmlMaterialRevision htmlMaterialRevision) {
return htmlMaterialRevisionPropertyDAO.listByHtmlMaterialRevision(htmlMaterialRevision);
}
/* HtmlMaterialRevisionExtensionProperty */
public HtmlMaterialRevisionExtensionProperty createRevisionExtensionProperty(HtmlMaterialRevision htmlMaterialRevision, String key, String value) {
return htmlMaterialRevisionExtensionPropertyDAO.create(htmlMaterialRevision, key, value);
}
public List<HtmlMaterialRevisionExtensionProperty> listRevisionExtensionProperties(HtmlMaterialRevision htmlMaterialRevision) {
return htmlMaterialRevisionExtensionPropertyDAO.listByHtmlMaterialRevision(htmlMaterialRevision);
}
/* CoOpsDiffAlgorithm */
public CoOpsDiffAlgorithm findAlgorithm(String algorithmName) {
return findAlgorithm(Arrays.asList(algorithmName));
}
public CoOpsDiffAlgorithm findAlgorithm(List<String> algorithmNames) {
Map<String, CoOpsDiffAlgorithm> algorithmMap = getAlgorithmMap();
for (String algorithmName : algorithmNames) {
if (algorithmMap.containsKey(algorithmName)) {
return algorithmMap.get(algorithmName);
}
}
return null;
}
private Map<String, CoOpsDiffAlgorithm> getAlgorithmMap() {
Map<String, CoOpsDiffAlgorithm> result = new HashMap<>();
Iterator<CoOpsDiffAlgorithm> iterator = this.algorithms.iterator();
while (iterator.hasNext()) {
CoOpsDiffAlgorithm algorithm = iterator.next();
result.put(algorithm.getName(), algorithm);
}
return result;
}
}