/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.strolch.model.xml;
import static li.strolch.model.StrolchModelConstants.INTERPRETATION_NONE;
import static li.strolch.model.StrolchModelConstants.UOM_NONE;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import li.strolch.model.GroupedParameterizedElement;
import li.strolch.model.Order;
import li.strolch.model.ParameterBag;
import li.strolch.model.ParameterizedElement;
import li.strolch.model.Resource;
import li.strolch.model.StrolchElement;
import li.strolch.model.Tags;
import li.strolch.model.activity.Action;
import li.strolch.model.activity.Activity;
import li.strolch.model.activity.IActivityElement;
import li.strolch.model.parameter.Parameter;
import li.strolch.model.policy.PolicyDef;
import li.strolch.model.policy.PolicyDefs;
import li.strolch.model.timedstate.StrolchTimedState;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.ITimeVariable;
import li.strolch.model.timevalue.IValue;
import li.strolch.model.timevalue.IValueChange;
import li.strolch.utils.iso8601.ISO8601FormatFactory;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public abstract class StrolchElementToSaxWriterVisitor {
protected XMLStreamWriter writer;
public StrolchElementToSaxWriterVisitor(XMLStreamWriter writer) {
this.writer = writer;
}
protected void writeElement(Resource resource) throws XMLStreamException {
boolean empty = !resource.hasParameterBags() && !resource.hasTimedStates() && !resource.hasPolicyDefs();
writeStartStrolchElement(Tags.RESOURCE, empty, resource);
if (resource.hasParameterBags())
writeParameterBags(resource);
if (resource.hasTimedStates())
writeTimedStates(resource);
if (resource.hasPolicyDefs())
writePolicyDefs(resource.getPolicyDefs());
if (!empty)
this.writer.writeEndElement();
}
protected void writeElement(Order order) throws XMLStreamException {
boolean empty = !order.hasParameterBags() && !order.hasPolicyDefs();
writeStartStrolchElement(Tags.ORDER, empty, order);
this.writer.writeAttribute(Tags.DATE, ISO8601FormatFactory.getInstance().formatDate(order.getDate()));
this.writer.writeAttribute(Tags.STATE, order.getState().name());
if (order.hasParameterBags()) {
writeParameterBags(order);
}
if (order.hasPolicyDefs())
writePolicyDefs(order.getPolicyDefs());
if (!empty)
this.writer.writeEndElement();
}
protected void writeElement(Activity activity) throws XMLStreamException {
boolean empty = !activity.hasParameterBags() && !activity.hasElements() && !activity.hasPolicyDefs();
writeStartStrolchElement(Tags.ACTIVITY, empty, activity);
if (activity.hasParameterBags()) {
writeParameterBags(activity);
}
if (activity.hasElements()) {
Iterator<Entry<String, IActivityElement>> iter = activity.elementIterator();
while (iter.hasNext()) {
IActivityElement element = iter.next().getValue();
if (element instanceof Activity)
writeElement((Activity) element);
else if (element instanceof Action)
writeElement((Action) element);
else
throw new IllegalArgumentException("Unhandled Element class " + element.getClass());
}
}
if (activity.hasPolicyDefs())
writePolicyDefs(activity.getPolicyDefs());
if (!empty)
this.writer.writeEndElement();
}
protected <T> void writeElement(Action action) throws XMLStreamException {
boolean empty = !action.hasParameterBags() && !action.hasChanges() && !action.hasPolicyDefs();
writeStartStrolchElement(Tags.ACTION, empty, action);
this.writer.writeAttribute(Tags.STATE, action.getState().name());
this.writer.writeAttribute(Tags.RESOURCE_ID, action.getResourceId());
this.writer.writeAttribute(Tags.RESOURCE_TYPE, action.getResourceType());
if (action.hasParameterBags()) {
writeParameterBags(action);
}
if (action.hasChanges()) {
for (IValueChange<? extends IValue<?>> change : action.getChanges()) {
this.writer.writeEmptyElement(Tags.VALUE_CHANGE);
this.writer.writeAttribute(Tags.STATE_ID, change.getStateId());
this.writer.writeAttribute(Tags.TIME, ISO8601FormatFactory.getInstance().formatDate(change.getTime()));
this.writer.writeAttribute(Tags.VALUE, change.getValue().getValueAsString());
this.writer.writeAttribute(Tags.TYPE, change.getValue().getClass().getName());
}
}
if (action.hasPolicyDefs())
writePolicyDefs(action.getPolicyDefs());
if (!empty)
this.writer.writeEndElement();
}
protected void writePolicyDefs(PolicyDefs policyDefs) throws XMLStreamException {
if (!policyDefs.hasPolicyDefs())
return;
this.writer.writeStartElement(Tags.POLICIES);
for (String type : policyDefs.getPolicyTypes()) {
PolicyDef policyDef = policyDefs.getPolicyDef(type);
this.writer.writeEmptyElement(Tags.POLICY);
this.writer.writeAttribute(Tags.TYPE, policyDef.getType());
this.writer.writeAttribute(Tags.VALUE, policyDef.getValueForXml());
}
this.writer.writeEndElement();
}
protected void writeTimedStates(Resource resource) throws XMLStreamException {
List<StrolchTimedState<IValue<?>>> timedStates = resource.getTimedStates();
for (StrolchTimedState<IValue<?>> timedState : timedStates) {
ITimeVariable<IValue<?>> timeEvolution = timedState.getTimeEvolution();
SortedSet<ITimeValue<IValue<?>>> values = timeEvolution.getValues();
writeStartStrolchElement(Tags.TIMED_STATE, values.isEmpty(), timedState);
for (ITimeValue<IValue<?>> timeValue : values) {
this.writer.writeEmptyElement(Tags.VALUE);
this.writer.writeAttribute(Tags.TIME,
ISO8601FormatFactory.getInstance().formatDate(timeValue.getTime()));
this.writer.writeAttribute(Tags.VALUE, timeValue.getValue().getValueAsString());
}
if (!values.isEmpty())
this.writer.writeEndElement();
}
}
protected void writeStartStrolchElement(String tag, boolean empty, StrolchElement element)
throws XMLStreamException {
if (empty) {
this.writer.writeEmptyElement(tag);
} else {
this.writer.writeStartElement(tag);
}
this.writer.writeAttribute(Tags.ID, element.getId());
this.writer.writeAttribute(Tags.NAME, element.getName());
this.writer.writeAttribute(Tags.TYPE, element.getType());
}
protected void writeParameterBags(GroupedParameterizedElement element) throws XMLStreamException {
Set<String> bagKeySet = new TreeSet<>(element.getParameterBagKeySet());
for (String bagKey : bagKeySet) {
ParameterBag parameterBag = element.getParameterBag(bagKey);
boolean isEmpty = !parameterBag.hasParameters();
writeStartStrolchElement(Tags.PARAMETER_BAG, isEmpty, parameterBag);
if (!isEmpty) {
writeParameters(parameterBag);
this.writer.writeEndElement();
}
}
}
protected void writeParameters(ParameterizedElement element) throws XMLStreamException {
List<Parameter<?>> parameters = new ArrayList<>(element.getParameters());
Collections.sort(parameters, (o1, o2) -> Integer.valueOf(o1.getIndex()).compareTo(o2.getIndex()));
for (Parameter<?> parameter : parameters) {
writeStartStrolchElement(Tags.PARAMETER, true, parameter);
if (!INTERPRETATION_NONE.equals(parameter.getInterpretation())) {
this.writer.writeAttribute(Tags.INTERPRETATION, parameter.getInterpretation());
}
if (!UOM_NONE.equals(parameter.getUom())) {
this.writer.writeAttribute(Tags.UOM, parameter.getUom());
}
if (parameter.isHidden()) {
this.writer.writeAttribute(Tags.HIDDEN, Boolean.toString(parameter.isHidden()));
}
if (parameter.getIndex() != 0) {
this.writer.writeAttribute(Tags.INDEX, Integer.toString(parameter.getIndex()));
}
this.writer.writeAttribute(Tags.VALUE, parameter.getValueAsString());
}
}
}