/*
* Copyright 2003-2016 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.util.io;
import jetbrains.mps.project.ModuleId;
import jetbrains.mps.smodel.SModelId.IntegerSModelId;
import jetbrains.mps.smodel.SModelReference;
import jetbrains.mps.smodel.SNodeId.Regular;
import jetbrains.mps.smodel.adapter.ids.MetaIdHelper;
import jetbrains.mps.smodel.adapter.ids.SContainmentLinkId;
import jetbrains.mps.smodel.adapter.ids.SPropertyId;
import jetbrains.mps.smodel.adapter.ids.SReferenceLinkId;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;
import org.jetbrains.mps.openapi.language.SConcept;
import org.jetbrains.mps.openapi.language.SContainmentLink;
import org.jetbrains.mps.openapi.language.SLanguage;
import org.jetbrains.mps.openapi.language.SProperty;
import org.jetbrains.mps.openapi.language.SReferenceLink;
import org.jetbrains.mps.openapi.model.SModelId;
import org.jetbrains.mps.openapi.model.SNodeId;
import org.jetbrains.mps.openapi.model.SNodeReference;
import org.jetbrains.mps.openapi.module.SModuleReference;
import org.jetbrains.mps.openapi.persistence.PersistenceFacade;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import static jetbrains.mps.util.io.ModelOutputStream.AGGREGATION;
import static jetbrains.mps.util.io.ModelOutputStream.AGGREGATION_INDEX;
import static jetbrains.mps.util.io.ModelOutputStream.ASSOCIATION;
import static jetbrains.mps.util.io.ModelOutputStream.ASSOCIATION_INDEX;
import static jetbrains.mps.util.io.ModelOutputStream.CONCEPT;
import static jetbrains.mps.util.io.ModelOutputStream.CONCEPT_INDEX;
import static jetbrains.mps.util.io.ModelOutputStream.LANGUAGE;
import static jetbrains.mps.util.io.ModelOutputStream.LANGUAGE_INDEX;
import static jetbrains.mps.util.io.ModelOutputStream.MODELID_FOREIGN;
import static jetbrains.mps.util.io.ModelOutputStream.MODELID_INTEGER;
import static jetbrains.mps.util.io.ModelOutputStream.MODELID_REGULAR;
import static jetbrains.mps.util.io.ModelOutputStream.MODELID_STRING;
import static jetbrains.mps.util.io.ModelOutputStream.MODELREF_INDEX;
import static jetbrains.mps.util.io.ModelOutputStream.MODULEID_FOREIGN;
import static jetbrains.mps.util.io.ModelOutputStream.MODULEID_REGULAR;
import static jetbrains.mps.util.io.ModelOutputStream.MODULEREF_INDEX;
import static jetbrains.mps.util.io.ModelOutputStream.MODULEREF_MODULEID;
import static jetbrains.mps.util.io.ModelOutputStream.NODEID_LONG;
import static jetbrains.mps.util.io.ModelOutputStream.NODEID_STRING;
import static jetbrains.mps.util.io.ModelOutputStream.NULL;
import static jetbrains.mps.util.io.ModelOutputStream.PROPERTY;
import static jetbrains.mps.util.io.ModelOutputStream.PROPERTY_INDEX;
/**
* Evgeny Gryaznov, Sep 27, 2010
*/
public class ModelInputStream extends DataInputStream {
private final List<String> myStrings = new ArrayList<String>(2048);
private final List<SModelReference> myModelRefs = new ArrayList<SModelReference>(1024);
private final List<SModuleReference> myModuleRefs = new ArrayList<SModuleReference>(128);
private final List<SLanguage> myLanguages = new ArrayList<SLanguage>(128);
private final List<SConcept> myConcepts = new ArrayList<SConcept>(128);
private final List<SProperty> myProperties = new ArrayList<SProperty>(128);
private final List<SReferenceLink> myAssociations = new ArrayList<SReferenceLink>(128);
private final List<SContainmentLink> myAggregations = new ArrayList<SContainmentLink>(128);
public ModelInputStream(InputStream in) {
super(new BufferedInputStream(in, 65536));
}
public Collection<String> readStrings() throws IOException {
int size = readInt();
if (size == -1) {
return null;
}
List<String> result = new ArrayList<String>(size);
for (; size > 0; size--) {
result.add(readString());
}
return result;
}
public String readString() throws IOException {
int c = readByte();
if (c == NULL) {
return null;
} else if (c == 1) {
int index = readInt();
return myStrings.get(index);
}
StringBuilder sb = null;
while (c == 42) {
String prefix = readUTF();
if (sb == null) {
sb = new StringBuilder(prefix);
} else {
sb.append(prefix);
}
c = readByte();
}
String res;
if (sb == null) {
res = readUTF();
} else {
res = sb.append(readUTF()).toString();
}
myStrings.add(res);
return res;
}
public SModuleReference readModuleReference() throws IOException {
int c = readByte();
if (c == NULL) {
return null;
} else if (c == MODULEREF_INDEX) {
int index = readInt();
return myModuleRefs.get(index);
}
ModuleId id = null;
if (c == MODULEREF_MODULEID) {
id = readModuleID();
}
SModuleReference ref = new jetbrains.mps.project.structure.modules.ModuleReference(readString(), id);
myModuleRefs.add(ref);
return ref;
}
public ModuleId readModuleID() throws IOException {
int c = readByte();
if (c == NULL) {
return null;
} else if (c == MODULEID_REGULAR) {
UUID uuid = new UUID(readLong(), readLong());
return ModuleId.regular(uuid);
} else if (c == MODULEID_FOREIGN) {
return ModuleId.foreign(readString());
} else {
throw new IOException("unknown id");
}
}
public SModelReference readModelReference() throws IOException {
int c = readByte();
if (c == NULL) {
return null;
} else if (c == MODELREF_INDEX) {
int index = readInt();
return myModelRefs.get(index);
}
SModelId id = readModelID();
String modelName = readString();
SModuleReference moduleRef = readModuleReference();
SModelReference ref = new SModelReference(moduleRef, id, modelName);
myModelRefs.add(ref);
return ref;
}
public SModelId readModelID() throws IOException {
int c = readByte();
if (c == NULL) {
return null;
} else if (c == MODELID_REGULAR) {
return jetbrains.mps.smodel.SModelId.regular(readUUID());
} else if (c == MODELID_FOREIGN) {
return jetbrains.mps.smodel.SModelId.foreign(readString());
} else if (c == MODELID_STRING) {
return PersistenceFacade.getInstance().createModelId(readString());
} else if (c == MODELID_INTEGER) {
return new IntegerSModelId(readInt());
} else {
throw new IOException("unknown id");
}
}
public SNodeId readNodeId() throws IOException {
int c = readByte();
if (c == NULL) {
return null;
} else if (c == NODEID_LONG) {
return new Regular(readLong());
} else if (c == NODEID_STRING) {
return PersistenceFacade.getInstance().createNodeId(readString());
}
throw new IOException("no id");
}
public SNodeReference readNodePointer() throws IOException {
int b = readByte();
if (b == NULL) {
return null;
} else {
return new jetbrains.mps.smodel.SNodePointer(readModelReference(), readNodeId());
}
}
public UUID readUUID() throws IOException {
long headBits = readLong();
long tailBits = readLong();
return new UUID(headBits, tailBits);
}
public SLanguage readLanguage() throws IOException {
byte b = readByte();
if (b == NULL) {
return null;
}
if (b == LANGUAGE_INDEX) {
return myLanguages.get(readShort());
}
if (b != LANGUAGE) {
throw new IOException(Integer.toHexString(b));
}
SLanguage l = MetaAdapterFactory.getLanguage(readLong(), readLong(), readString());
myLanguages.add(l);
return l;
}
public SConcept readConcept() throws IOException {
byte b = readByte();
if (b == NULL) {
return null;
}
if (b == CONCEPT_INDEX) {
return myConcepts.get(readShort());
}
if (b != CONCEPT) {
throw new IOException(Integer.toHexString(b));
}
SConcept c = MetaAdapterFactory.getConcept(readLong(), readLong(), readLong(), readString());
myConcepts.add(c);
return c;
}
public SProperty readProperty() throws IOException {
byte b = readByte();
if (b == NULL) {
return null;
}
if (b == PROPERTY_INDEX) {
return myProperties.get(readShort());
}
if (b != PROPERTY) {
throw new IOException(Integer.toHexString(b));
}
final SConcept c = readConcept();
SProperty p = MetaAdapterFactory.getProperty(new SPropertyId(MetaIdHelper.getConcept(c), readLong()), readString());
myProperties.add(p);
return p;
}
public SReferenceLink readReferenceLink() throws IOException {
byte b = readByte();
if (b == NULL) {
return null;
}
if (b == ASSOCIATION_INDEX) {
return myAssociations.get(readShort());
}
if (b != ASSOCIATION) {
throw new IOException(Integer.toHexString(b));
}
final SConcept c = readConcept();
SReferenceLink l = MetaAdapterFactory.getReferenceLink(new SReferenceLinkId(MetaIdHelper.getConcept(c), readLong()), readString());
myAssociations.add(l);
return l;
}
public SContainmentLink readContainmentLink() throws IOException {
byte b = readByte();
if (b == NULL) {
return null;
}
if (b == AGGREGATION_INDEX) {
return myAggregations.get(readShort());
}
if (b != AGGREGATION) {
throw new IOException(Integer.toHexString(b));
}
final SConcept c = readConcept();
SContainmentLink l = MetaAdapterFactory.getContainmentLink(new SContainmentLinkId(MetaIdHelper.getConcept(c), readLong()), readString());
myAggregations.add(l);
return l;
}
}