package fi.otavanopisto.muikku.plugins.material;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.DeserializationConfig;
import org.cyberneko.html.parsers.DOMParser;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import fi.otavanopisto.muikku.plugins.material.fieldmeta.FieldMeta;
public class MaterialFieldCollection {
public MaterialFieldCollection() {
}
public MaterialFieldCollection(String html) {
parseFields(html);
}
public void parseFields(String html) {
if (!materialFields.isEmpty()) {
materialFields.clear();
}
if (StringUtils.isNotBlank(html)) {
StringReader htmlReader = new StringReader(html);
try {
DOMParser parser = new DOMParser();
InputSource inputSource = new InputSource(htmlReader);
parser.parse(inputSource);
Document document = parser.getDocument();
NodeList objectNodeList = document.getElementsByTagName("object");
for (int i = 0, l = objectNodeList.getLength(); i < l; i++) {
Node objectNode = objectNodeList.item(i);
if (objectNode instanceof Element) {
Element objectElement = (Element) objectNode;
if (isMuikkuField(objectElement)) {
String fieldType = objectElement.getAttribute("type");
NodeList paramNodes = objectElement.getElementsByTagName("param");
String content = null;
for (int j = 0, jl = paramNodes.getLength(); j < jl; j++) {
Node paramNode = paramNodes.item(j);
if (paramNode instanceof Element) {
Element paramElement = (Element) paramNode;
if ("content".equals(paramElement.getAttribute("name"))) {
content = paramElement.getAttribute("value");
break;
}
}
}
if (StringUtils.isNotBlank(content)) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
FieldMeta fieldMeta = objectMapper.readValue(content, FieldMeta.class);
materialFields.put(fieldMeta.getName(), new MaterialField(fieldMeta.getName(), fieldType, content));
}
}
}
}
}
catch (Exception e) {
// TODO Proper exception handling
throw new IllegalArgumentException("Malformed document structure: " + html);
}
finally {
htmlReader.close();
}
}
}
public boolean hasField(String name) {
return materialFields.containsKey(name);
}
public MaterialField getField(String name) {
return materialFields.get(name);
}
public Set<String> getFieldNames() {
return materialFields.keySet();
}
public List<MaterialField> getFields() {
return Collections.unmodifiableList(new ArrayList<>(materialFields.values()));
}
public List<MaterialField> getNewFields(MaterialFieldCollection collection) {
List<MaterialField> fields = new ArrayList<MaterialField>();
Set<String> names = materialFields.keySet();
for (String name : names) {
if (!collection.hasField(name)) {
fields.add(getField(name));
}
}
return Collections.unmodifiableList(fields);
}
public List<MaterialField> getUpdatedFields(MaterialFieldCollection collection) {
List<MaterialField> fields = new ArrayList<MaterialField>();
Set<String> names = materialFields.keySet();
for (String name : names) {
if (collection.hasField(name)) {
MaterialField myField = getField(name);
MaterialField referenceField = collection.getField(name);
if (!myField.equals(referenceField)) {
fields.add(myField);
}
}
}
return Collections.unmodifiableList(fields);
}
public List<MaterialField> getRemovedFields(MaterialFieldCollection collection) {
List<MaterialField> fields = new ArrayList<MaterialField>();
Set<String> names = collection.getFieldNames();
for (String name : names) {
if (!hasField(name)) {
fields.add(collection.getField(name));
}
}
return Collections.unmodifiableList(fields);
}
private boolean isMuikkuField(Element element) {
String type = element.getAttribute("type");
return StringUtils.startsWith(type, "application/vnd.muikku.field.");
}
private HashMap<String, MaterialField> materialFields = new HashMap<String, MaterialField>();
}