package simulator;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import models.algebra.Constant;
import models.algebra.Expression;
import models.algebra.Term;
import models.algebra.Type;
import models.dataConstraintModel.DataConstraintModel;
import models.dataConstraintModel.ResourceHierarchy;
import models.dataFlowModel.DataTransferChannel;
import simulator.states.CompositeResourceState;
import simulator.states.JsonResourceState;
import simulator.states.ListResourceState;
import simulator.states.MapResourceState;
import simulator.states.PrimitiveResourceState;
import simulator.states.ResourceState;
public class SystemState {
private Set<Resource> rootResources = new HashSet<>();
private Map<DataTransferChannel, ChannelState> channelStates = new HashMap<>();
private List<Event> events = new ArrayList<>();
public SystemState() {
}
public SystemState(SystemState prevState) {
for (Resource resource: prevState.getRootResources()) {
rootResources.add(new Resource(resource));
}
for (Map.Entry<DataTransferChannel, ChannelState> channelEnt: prevState.getChannelStates().entrySet()) {
if (channelEnt.getValue() != null) {
channelStates.put(channelEnt.getKey(), (ChannelState) channelEnt.getValue().clone());
} else {
channelStates.put(channelEnt.getKey(), null);
}
}
}
public Set<Resource> getRootResources() {
return rootResources;
}
public void addResource(Resource rootResource) {
rootResources.add(rootResource);
}
public Resource getResource(ResourceIdentifier resourceIdentifier) {
for (Resource root: rootResources) {
Resource descendant = root.getDescendant(resourceIdentifier);
if (descendant != null) return descendant;
}
return null;
}
public Resource getResource(String resourceIdentifier) {
for (Resource root: rootResources) {
Resource descendant = root.getDescendant(resourceIdentifier);
if (descendant != null) return descendant;
}
return null;
}
/**
* update the state of a specified resource
*
* @param resourceIdentifier a resource identifier to identify the resource
* @param resStateValue a new state of the resource
* @return
*/
public ResourceIdentifier updateResourceState(ResourceIdentifier resourceIdentifier, Expression resStateValue) {
Type resType = resourceIdentifier.getResourceStateType();
if (resType != null && DataConstraintModel.typeList.isAncestorOf(resType)) {
if (resStateValue instanceof Constant) {
} else if (resStateValue instanceof Term) {
Term listValue = (Term) resStateValue;
if (listValue.getSymbol().equals(DataConstraintModel.append)) {
Resource res = getResource(resourceIdentifier);
ResourceState state = res.getState();
Expression childExp = null;
if (state instanceof ListResourceState) {
childExp = new Constant(Integer.toString(((ListResourceState) state).getChildStates().size()));
} else if (state instanceof PrimitiveResourceState && ((PrimitiveResourceState) state).getValue().getSymbol().equals(DataConstraintModel.nil)) {
// If the value of state is nil.
childExp = new Constant("0");
ResourceState parentState = res.getParent().getState();
ResourceState newState = new ListResourceState();
if (parentState instanceof CompositeResourceState) {
((CompositeResourceState) parentState).replaceChildState(state, newState);
}
state = newState;
res.changeState(state);
}
ResourceHierarchy childResourceHierarchy = null;
if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) {
childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next();
} else {
childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1);
}
ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childExp, childResourceHierarchy);
Map.Entry<ResourceState, ResourceIdentifier> childInfo = createResourceState(childResourceIdentifier, listValue.getChild(1));
((ListResourceState) state).addChildState(childInfo.getKey());
return childInfo.getValue();
}
}
} else if (resType != null && DataConstraintModel.typeMap.isAncestorOf(resType)) {
if (resStateValue instanceof Constant) {
} else if (resStateValue instanceof Term) {
Term mapValue = (Term) resStateValue;
if (mapValue.getSymbol().equals(DataConstraintModel.insert)) {
Expression childExp = mapValue.getChild(1);
if (childExp instanceof Constant) {
Resource res = getResource(resourceIdentifier);
ResourceState state = res.getState();
if (state instanceof PrimitiveResourceState && ((PrimitiveResourceState) state).getValue().getSymbol().equals(DataConstraintModel.nil)) {
// If the value of state is nil.
ResourceState parentState = res.getParent().getState();
ResourceState newState = new MapResourceState();
if (parentState instanceof CompositeResourceState) {
((CompositeResourceState) parentState).replaceChildState(state, newState);
}
state = newState;
res.changeState(state);
}
ResourceHierarchy childResourceHierarchy = null;
if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) {
childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next();
} else {
childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1);
}
ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childExp, childResourceHierarchy);
String childId = ((Constant) childExp).toString();
Map.Entry<ResourceState, ResourceIdentifier> childInfo = createResourceState(childResourceIdentifier, mapValue.getChild(2));
((MapResourceState) state).addChildState(childId, childInfo.getKey());
return childInfo.getValue();
}
}
}
} else if (resType != null && DataConstraintModel.typeJson.isAncestorOf(resType)) {
if (resStateValue instanceof Constant) {
} else if (resStateValue instanceof Term) {
Term jsonValue = (Term) resStateValue;
Resource res = getResource(resourceIdentifier);
ResourceState state = res.getState();
ResourceIdentifier createdResource = null;
while (jsonValue.getSymbol().equals(DataConstraintModel.addMember)) {
Expression childExp = jsonValue.getChild(1);
if (childExp instanceof Constant) {
String memberName = ((Constant) childExp).getSymbol().getName().replace("\"", "");
ResourceHierarchy childResourceHierarchy = null;
for (ResourceHierarchy childRes: resourceIdentifier.getResourceHierarchy().getChildren()) {
if (childRes.getResourceName().equals(memberName)) {
childResourceHierarchy = childRes;
break;
}
}
if (childResourceHierarchy == null) {
childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), memberName);
}
ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, memberName, childResourceHierarchy);
String childId = ((Constant) childExp).toString();
Map.Entry<ResourceState, ResourceIdentifier> childInfo = createResourceState(childResourceIdentifier, jsonValue.getChild(2));
((JsonResourceState) state).addChildState(childId, childInfo.getKey());
createdResource = childInfo.getValue();
}
if (!(jsonValue.getChild(0) instanceof Term)) break;
jsonValue = (Term) jsonValue.getChild(0);
}
return createdResource;
}
} else {
if (resStateValue instanceof Constant) {
Resource res = getResource(resourceIdentifier);
ResourceState state = null;
if (res != null) {
state = res.getState();
((PrimitiveResourceState) state).setValue((Constant) resStateValue);
} else {
ResourceIdentifier parentResId = (ResourceIdentifier) resourceIdentifier.getParent();
Type parentResType = parentResId.getResourceStateType();
if (parentResType != null && DataConstraintModel.typeList.isAncestorOf(parentResType)) {
} else if (parentResType != null && DataConstraintModel.typeMap.isAncestorOf(parentResType)) {
JsonResourceState parentState = (JsonResourceState) getResource(parentResId).getState();
parentState.addChildState(((Constant) resourceIdentifier.getLastParam()).toString(), new PrimitiveResourceState((Constant) resStateValue));
} else if (parentResType != null && DataConstraintModel.typeJson.isAncestorOf(parentResType)) {
JsonResourceState parentState = (JsonResourceState) getResource(parentResId).getState();
parentState.addChildState("\"" + resourceIdentifier.getLeafResourceName() + "\"", new PrimitiveResourceState((Constant) resStateValue));
}
}
return resourceIdentifier;
}
}
return resourceIdentifier;
}
public Map.Entry<ResourceState, ResourceIdentifier> createResourceState(ResourceIdentifier resourceIdentifier, Expression resStateValue) {
Type resType = null;
if (resStateValue instanceof Term) {
resType = ((Term) resStateValue).getType();
resStateValue = ((Term) resStateValue).reduce();
}
if (resType != null) {
if (DataConstraintModel.typeList.isAncestorOf(resType)) {
if (resStateValue instanceof Constant) {
} else if (resStateValue instanceof Term) {
Term listValue = (Term) resStateValue;
if (listValue.getSymbol().equals(DataConstraintModel.append)) {
ListResourceState state = new ListResourceState();
Expression childExp = new Constant(Integer.toString(((ListResourceState) state).getChildStates().size()));
ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier,
childExp,
resourceIdentifier.getResourceHierarchy().getChildren().iterator().next());
Map.Entry<ResourceState, ResourceIdentifier> childInfo = createResourceState(childResourceIdentifier, listValue.getChild(1));
state.addChildState(childInfo.getKey());
return new AbstractMap.SimpleEntry<>(state, childInfo.getValue());
}
}
} else if (DataConstraintModel.typeMap.isAncestorOf(resType)) {
if (resStateValue instanceof Constant) {
} else if (resStateValue instanceof Term) {
Term mapValue = (Term) resStateValue;
if (mapValue.getSymbol().equals(DataConstraintModel.insert)) {
Expression childExp = mapValue.getChild(1);
if (childExp instanceof Constant) {
MapResourceState state = new MapResourceState();
ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier,
childExp,
resourceIdentifier.getResourceHierarchy().getChildren().iterator().next());
String childId = ((Constant) childExp).toString();
Map.Entry<ResourceState, ResourceIdentifier> childInfo = createResourceState(childResourceIdentifier, mapValue.getChild(2));
state.addChildState(childId, childInfo.getKey());
return new AbstractMap.SimpleEntry<>(state, childInfo.getValue());
}
}
}
} else if (DataConstraintModel.typeJson.isAncestorOf(resType)) {
if (resStateValue instanceof Constant) {
} else if (resStateValue instanceof Term) {
Term jsonValue = (Term) resStateValue;
JsonResourceState state = new JsonResourceState();
Map.Entry<ResourceState, ResourceIdentifier> createInfo = null;
while (jsonValue.getSymbol().equals(DataConstraintModel.addMember)) {
Expression childExp = jsonValue.getChild(1);
if (childExp instanceof Constant) {
String memberName = ((Constant) childExp).getSymbol().getName().replace("\"", "");
ResourceHierarchy childResourceHierarchy = null;
for (ResourceHierarchy childRes: resourceIdentifier.getResourceHierarchy().getChildren()) {
if (childRes.getResourceName().equals(memberName)) {
childResourceHierarchy = childRes;
break;
}
}
if (childResourceHierarchy == null) {
childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), memberName);
}
ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, memberName, childResourceHierarchy);
String childId = ((Constant) childExp).toString();
Map.Entry<ResourceState, ResourceIdentifier> childInfo = createResourceState(childResourceIdentifier, jsonValue.getChild(2));
state.addChildState(childId, childInfo.getKey());
createInfo = new AbstractMap.SimpleEntry<>(state, childInfo.getValue());
}
if (!(jsonValue.getChild(0) instanceof Term)) break;
jsonValue = (Term) jsonValue.getChild(0);
}
return createInfo;
}
}
}
if (resStateValue instanceof Constant) {
Resource res = getResource(resourceIdentifier);
ResourceState state = null;
if (res != null) {
state = res.getState();
((PrimitiveResourceState) state).setValue((Constant) resStateValue);
} else {
state = new PrimitiveResourceState((Constant) resStateValue);
}
return new AbstractMap.SimpleEntry<>(state, resourceIdentifier);
}
return null;
}
public Map<DataTransferChannel, ChannelState> getChannelStates() {
return channelStates;
}
public ChannelState getChannelState(DataTransferChannel channel) {
return channelStates.get(channel);
}
public void addChannel(DataTransferChannel channel) {
channelStates.put(channel, null);
}
public void updateChannelState(DataTransferChannel channel, ChannelState channelState) {
channelStates.put(channel, channelState);
}
public List<Event> getEvents() {
return events;
}
public void addEvent(Event event) {
events.add(event);
}
}