/*
* Copyright 2003-2011 JetBrains s.r.o.
*
* 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 jetbrains.mps.generator.impl.cache;
import jetbrains.mps.generator.impl.GenerationFailureException;
import jetbrains.mps.generator.impl.dependencies.DependenciesBuilder;
import jetbrains.mps.util.io.ModelInputStream;
import jetbrains.mps.util.io.ModelOutputStream;
import org.jetbrains.mps.openapi.model.SModel;
import org.jetbrains.mps.openapi.model.SModelReference;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.model.SNodeId;
import org.jetbrains.mps.openapi.persistence.PersistenceFacade;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
/**
* Evgeny Gryaznov, Sep 23, 2010
*/
public class TransientModelWithMetainfo {
private static final int END_MARKER = '$' + ('M' << 24) + ('P' << 16) + ('S' << 8);
public static final String CONDITIONALS_ID = "";
private SModelReference myReference;
private List<SNode> myRoots;
private Map<SNodeId, SNodeId> myRootToOriginal;
private Map<SNodeId, MappingsMemento> myMappingsMemento;
public TransientModelWithMetainfo(SModelReference reference, List<SNode> roots) {
myReference = reference;
myRoots = roots;
myRootToOriginal = new HashMap<SNodeId, SNodeId>();
myMappingsMemento = new HashMap<SNodeId, MappingsMemento>();
}
public List<SNode> getRoots() {
return myRoots;
}
public MappingsMemento getMappingsMemento(String originalId) {
return myMappingsMemento.get(PersistenceFacade.getInstance().createNodeId(originalId));
}
public MappingsMemento getMappingsMemento(SNode originalRoot, boolean create) {
SNodeId key = originalRoot == null ? null : originalRoot.getNodeId();
MappingsMemento mappingsMemento = myMappingsMemento.get(key);
if(mappingsMemento == null && create) {
mappingsMemento = new MappingsMemento();
myMappingsMemento.put(key, mappingsMemento);
}
return mappingsMemento;
}
public void updateMappings(String originalId, MappingsMemento mappingsMemento) {
myMappingsMemento.put(PersistenceFacade.getInstance().createNodeId(originalId), mappingsMemento);
}
public String getOriginal(SNode root) {
SNodeId id = myRootToOriginal.get(root.getNodeId());
if(id == null) {
return CONDITIONALS_ID;
}
return id.toString();
}
public void setOriginal(SNodeId sNodeId, String originalId) {
myRootToOriginal.put(sNodeId, originalId.equals(CONDITIONALS_ID) ? null : PersistenceFacade.getInstance().createNodeId(originalId));
}
public void save(ModelOutputStream os) throws IOException {
new TransientModelPersistence(myReference).saveModel(myRoots, os);
saveMetainfo(os);
}
private void saveMetainfo(ModelOutputStream os) throws IOException {
os.writeInt(myRootToOriginal.size());
for (Entry<SNodeId, SNodeId> e : myRootToOriginal.entrySet()) {
os.writeNodeId(e.getKey());
os.writeNodeId(e.getValue());
}
os.writeInt(myMappingsMemento.size());
for(Entry<SNodeId, MappingsMemento> e : myMappingsMemento.entrySet()) {
os.writeNodeId(e.getKey());
e.getValue().save(os);
}
os.writeInt(END_MARKER);
}
private void loadMetainfo(ModelInputStream is) throws IOException {
int size = is.readInt();
for (; size > 0; size--) {
SNodeId key = is.readNodeId();
SNodeId value = is.readNodeId();
myRootToOriginal.put(key, value);
}
size = is.readInt();
for(; size > 0; size--) {
SNodeId key = is.readNodeId();
MappingsMemento mappingsMemento = MappingsMemento.load(is);
myMappingsMemento.put(key, mappingsMemento);
}
if(is.readInt() != END_MARKER) {
throw new IOException("corrupted file");
}
}
public static TransientModelWithMetainfo load(ModelInputStream is, SModelReference modelReference) throws IOException {
List<SNode> roots = new TransientModelPersistence(modelReference).loadModel(is);
TransientModelWithMetainfo result = new TransientModelWithMetainfo(modelReference, roots);
result.loadMetainfo(is);
return result;
}
public static TransientModelWithMetainfo create(SModel model, DependenciesBuilder builder) throws GenerationFailureException {
ArrayList<SNode> roots = new ArrayList<SNode>();
for (SNode root1 : model.getRootNodes()) {
roots.add(root1);
}
TransientModelWithMetainfo metainfo = new TransientModelWithMetainfo(model.getReference(), roots);
Iterator<SNode> it = model.getRootNodes().iterator();
while (it.hasNext()) {
SNode root = it.next();
SNode node = builder.getOriginalForOutput(root);
metainfo.myRootToOriginal.put(root.getNodeId(), node == null ? null: node.getNodeId());
}
builder.updateUnchanged(metainfo);
return metainfo;
}
}