/*
* Copyright 2003-2014 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.smodel.persistence.def.v9;
import jetbrains.mps.persistence.IndexAwareModelFactory.Callback;
import jetbrains.mps.persistence.xml.XMLPersistence.Indexer;
import jetbrains.mps.smodel.adapter.ids.SLanguageId;
import jetbrains.mps.smodel.persistence.def.XmlFastScanner;
import jetbrains.mps.util.JDOMUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.model.SNodeId;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.Reader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Indexer9 implements Indexer{
private final Callback myConsumer;
private final IdEncoder myIdEncoder = new IdEncoder();
public Indexer9(@NotNull Callback consumer) {
myConsumer = consumer;
}
public void index(@NotNull Reader input) throws IOException {
char[] data = getChars(input);
XmlFastScanner s = new XmlFastScanner(data);
int token;
boolean insideRegistry = false, insideImports = false, underNode = false;
// <language id="">
// <concept id="">
// <import ref="">
// <ref to="external node" | node="local node">
final Matcher attrMatcher = Pattern.compile(String.format("\\s(%s|%s|%s|%s)\\s*=\\s*\"([^\"]+)\"", ModelPersistence9.ID, ModelPersistence9.REF, ModelPersistence9.TO, ModelPersistence9.NODE)).matcher("");
SLanguageId currentLanguage = null;
while ((token = s.next()) != XmlFastScanner.EOI) {
if (token != XmlFastScanner.OPEN_TAG && token != XmlFastScanner.SIMPLE_TAG) {
continue;
}
final String tokenName = s.getName();
if (insideRegistry) {
if (ModelPersistence9.REGISTRY_LANGUAGE.equals(tokenName) && attrMatcher.reset(s.token()).find()) {
currentLanguage = myIdEncoder.parseLanguageId(attrMatcher.group(2));
} else if (ModelPersistence9.REGISTRY_CONCEPT.equals(tokenName) && attrMatcher.reset(s.token()).find()) {
handleConceptId(currentLanguage, attrMatcher.group(2));
}
} else if (insideImports) {
if (ModelPersistence9.IMPORT.equals(tokenName) && attrMatcher.reset(s.token()).find()) {
handleModelImportRef(JDOMUtil.unescapeText(attrMatcher.group(2)));
}
} else if (underNode) {
if (ModelPersistence9.NODE_REFERENCE.equals(tokenName) && attrMatcher.reset(s.token()).find()) {
final String attrValue = JDOMUtil.unescapeText(attrMatcher.group(2));
final String attr = attrMatcher.group(1);
if (ModelPersistence9.TO.equals(attr)) {
handleExternalReference(attrValue);
} else {
assert ModelPersistence9.NODE.equals(attr);
handleLocalReference(attrValue);
}
}
}
if (s.tagDepth() == 1) {
if (ModelPersistence9.REGISTRY.equals(tokenName)) {
insideRegistry = true;
insideImports = underNode = false;
} else if (ModelPersistence9.IMPORTS.equals(tokenName)) {
insideImports = true;
insideRegistry = underNode = false;
} else if (ModelPersistence9.NODE.equals(tokenName)) {
underNode = true;
insideRegistry = insideImports = false;
}
}
}
}
public static char[] getChars(@NotNull Reader input) throws IOException {
char buf[] = new char[8196];
CharArrayWriter w = new CharArrayWriter(buf.length * 10);
int x;
while ((x = input.read(buf, 0, buf.length)) != -1) {
w.write(buf, 0, x);
}
w.flush();
w.close();
return w.toCharArray();
}
private void handleConceptId(SLanguageId lang, String conceptId) {
myConsumer.instances(myIdEncoder.parseConceptId(lang, conceptId));
}
private void handleModelImportRef(String modelRef) {
myConsumer.imports(myIdEncoder.parseModelReference(modelRef));
}
private void handleExternalReference(String outerRef) {
SNodeId nodeId = myIdEncoder.parseExternalNodeReference(outerRef);
if (nodeId != null) {
myConsumer.externalNodeRef(nodeId);
}
}
private void handleLocalReference(String localRef) {
SNodeId nodeId = myIdEncoder.parseLocalNodeReference(localRef);
if (nodeId != null) {
myConsumer.localNodeRef(nodeId);
}
}
}