package jetbrains.mps.smodel.persistence.def.v8;

/*Generated by MPS */

import jetbrains.mps.annotations.GeneratedClass;
import jetbrains.mps.util.xml.XMLSAXHandler;
import jetbrains.mps.smodel.loading.ModelLoadResult;
import jetbrains.mps.logging.Logger;
import java.util.Stack;
import org.xml.sax.Locator;
import jetbrains.mps.smodel.SModelHeader;
import jetbrains.mps.smodel.DefaultSModel;
import jetbrains.mps.smodel.persistence.def.ReadHelper;
import org.xml.sax.SAXException;
import org.xml.sax.Attributes;
import org.xml.sax.SAXParseException;
import org.jetbrains.mps.openapi.persistence.PersistenceFacade;
import jetbrains.mps.smodel.SModel;
import jetbrains.mps.smodel.loading.ModelLoadingState;
import jetbrains.mps.extapi.model.GeneratableSModel;
import org.jetbrains.mps.openapi.module.SModuleReference;
import jetbrains.mps.smodel.SModelLegacy;
import org.jetbrains.mps.openapi.model.SNode;
import jetbrains.mps.baseLanguage.tuples.runtime.Tuples;
import jetbrains.mps.vcspersistence.SNodeFactory;
import jetbrains.mps.smodel.runtime.ConceptKind;
import jetbrains.mps.smodel.runtime.StaticScope;
import org.jetbrains.mps.openapi.model.SNodeId;
import jetbrains.mps.smodel.InterfaceSNode;
import jetbrains.mps.smodel.SNodeLegacy;
import jetbrains.mps.util.Pair;
import org.jetbrains.mps.openapi.model.SNodeReference;
import jetbrains.mps.baseLanguage.tuples.runtime.MultiTuple;

@GeneratedClass(node = "r:050eb90d-d917-47d4-8d74-cc37a63452a4(jetbrains.mps.smodel.persistence.def.v8)/286176397450364062", model = "r:050eb90d-d917-47d4-8d74-cc37a63452a4(jetbrains.mps.smodel.persistence.def.v8)")
public class ModelReader8Handler extends XMLSAXHandler<ModelLoadResult> {
  private static final Logger LOG = Logger.getLogger(ModelReader8Handler.class);
  private ModelElementHandler modelHandler = new ModelElementHandler();
  private PersistenceElementHandler persistenceHandler = new PersistenceElementHandler();
  private Module_referenceElementHandler module_referenceHandler = new Module_referenceElementHandler();
  private ImportElementHandler importHandler = new ImportElementHandler();
  private NodeElementHandler nodeHandler = new NodeElementHandler();
  private IgnoredNodeElementHandler ignoredNodeHandler = new IgnoredNodeElementHandler();
  private PropertyElementHandler propertyHandler = new PropertyElementHandler();
  private IgnoredPropertyElementHandler ignoredPropertyHandler = new IgnoredPropertyElementHandler();
  private LinkElementHandler linkHandler = new LinkElementHandler();
  private IgnoredLinkElementHandler ignoredLinkHandler = new IgnoredLinkElementHandler();
  private Stack<ElementHandler> myHandlersStack = new Stack<ElementHandler>();
  private Stack<ChildHandler> myChildHandlersStack = new Stack<ChildHandler>();
  private Stack<Object> myValues = new Stack<Object>();
  private Locator myLocator;
  private ModelLoadResult myResult;
  private boolean my_interfaceOnlyParam;
  private boolean my_stripImplementationParam;
  private SModelHeader my_headerParam;
  private DefaultSModel my_modelField;
  private ReadHelper my_helperField;
  private boolean my_hasSkippedNodesField;
  public ModelReader8Handler(boolean interfaceOnly, boolean stripImplementation, SModelHeader header) {
    my_interfaceOnlyParam = interfaceOnly;
    my_stripImplementationParam = stripImplementation;
    my_headerParam = header;
  }
  public ModelLoadResult getResult() {
    return myResult;
  }
  @Override
  public void setDocumentLocator(Locator locator) {
    myLocator = locator;
  }
  @Override
  public void characters(char[] array, int start, int len) throws SAXException {
    ElementHandler current = (myHandlersStack.empty() ? (ElementHandler) null : myHandlersStack.peek());
    if (current != null) {
      current.handleText(myValues.peek(), new String(array, start, len));
    }
  }
  @Override
  public void endElement(String uri, String localName, String qName) throws SAXException {
    ElementHandler current = myHandlersStack.pop();
    Object childValue = myValues.pop();
    current.validate(childValue);
    if (myChildHandlersStack.empty()) {
      myResult = (ModelLoadResult) childValue;
    } else {
      ChildHandler ch = myChildHandlersStack.pop();
      if (ch != null) {
        ch.apply(myValues.peek(), childValue);
      }
    }
  }
  @Override
  public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
    ElementHandler current = (myHandlersStack.empty() ? (ElementHandler) null : myHandlersStack.peek());
    if (current == null) {
      // root
      current = modelHandler;
    } else {
      current = current.createChild(myValues.peek(), qName, attributes);
    }

    // check required
    for (String attr : current.requiredAttributes()) {
      if (attributes.getValue(attr) == null) {
        throw new SAXParseException("attribute " + attr + " is absent", null);
      }
    }

    Object result = current.createObject(attributes);
    if (myHandlersStack.empty()) {
      myResult = (ModelLoadResult) result;
    }

    // handle attributes
    for (int i = 0; i < attributes.getLength(); i++) {
      String name = attributes.getQName(i);
      String value = attributes.getValue(i);
      current.handleAttribute(result, name, value);
    }
    myHandlersStack.push(current);
    myValues.push(result);
  }
  private interface ChildHandler {
    void apply(Object resultObject, Object value) throws SAXException;
  }
  private class ElementHandler {
    private String[] requiredAttributes = new String[0];

    private ElementHandler() {
    }
    protected Object createObject(Attributes attrs) throws SAXException {
      return null;
    }
    protected void handleAttribute(Object resultObject, String name, String value) throws SAXException {
    }
    protected ElementHandler createChild(Object resultObject, String tagName, Attributes attrs) throws SAXException {
      throw new SAXParseException("unknown tag: " + tagName, null);
    }
    protected void handleText(Object resultObject, String value) throws SAXException {
      if (value.trim().length() == 0) {
        return;
      }
      throw new SAXParseException("text is not accepted: '" + value + "'", null);
    }
    protected String[] requiredAttributes() {
      return requiredAttributes;
    }
    protected void setRequiredAttributes(String... required) {
      requiredAttributes = required;
    }
    protected void validate(Object resultObject) throws SAXException {
    }
  }
  public class ModelElementHandler extends ElementHandler {
    public ModelElementHandler() {
      setRequiredAttributes("modelUID");
    }
    @Override
    protected ModelLoadResult createObject(Attributes attrs) throws SAXException {
      my_modelField = new DefaultSModel(PersistenceFacade.getInstance().createModelReference(attrs.getValue("modelUID")), my_headerParam);
      my_hasSkippedNodesField = false;
      my_helperField = new ReadHelper(my_modelField.getReference());
      return new ModelLoadResult((SModel) my_modelField, ModelLoadingState.NOT_LOADED);
    }
    @Override
    protected void handleAttribute(Object resultObject, String name, String value) throws SAXException {
      ModelLoadResult result = (ModelLoadResult) resultObject;
      if ("content".equals(name)) {
        if ("header".equals(value)) {
          result.setContentKind(ModelLoadResult.ContentKind.MODEL_HEADER);
        } else if ("root".equals(value)) {
          result.setContentKind(ModelLoadResult.ContentKind.MODEL_ROOT);
        } else {
          throw new SAXException("unknown content attribute value: " + value);
        }
        return;
      }
      if ("version".equals(name)) {
        // do nothing
        return;
      }
      if ("doNotGenerate".equals(name)) {
        my_headerParam.setOptionalProperty(GeneratableSModel.DO_NOT_GENERATE, value);
        return;
      }
      super.handleAttribute(resultObject, name, value);
    }
    @Override
    protected ElementHandler createChild(Object resultObject, String tagName, Attributes attrs) throws SAXException {
      if ("persistence".equals(tagName)) {
        myChildHandlersStack.push(null);
        return persistenceHandler;
      }
      if ("language".equals(tagName)) {
        myChildHandlersStack.push(new ChildHandler() {
          @Override
          public void apply(Object resultObject, Object value) throws SAXException {
            handleChild_286176397450364079(resultObject, value);
          }
        });
        return module_referenceHandler;
      }
      if ("language-engaged-on-generation".equals(tagName)) {
        myChildHandlersStack.push(new ChildHandler() {
          @Override
          public void apply(Object resultObject, Object value) throws SAXException {
            handleChild_286176397450364090(resultObject, value);
          }
        });
        return module_referenceHandler;
      }
      if ("devkit".equals(tagName)) {
        myChildHandlersStack.push(new ChildHandler() {
          @Override
          public void apply(Object resultObject, Object value) throws SAXException {
            handleChild_286176397450364101(resultObject, value);
          }
        });
        return module_referenceHandler;
      }
      if ("import".equals(tagName)) {
        myChildHandlersStack.push(new ChildHandler() {
          @Override
          public void apply(Object resultObject, Object value) throws SAXException {
            handleChild_286176397450364112(resultObject, value);
          }
        });
        return importHandler;
      }
      if ("root".equals(tagName) && checkroot_1768088633166530069(resultObject, attrs)) {
        myChildHandlersStack.push(new ChildHandler() {
          @Override
          public void apply(Object resultObject, Object value) throws SAXException {
            handleChild_1361478912184551722(resultObject, value);
          }
        });
        return nodeHandler;
      }
      if ("root".equals(tagName)) {
        myChildHandlersStack.push(new ChildHandler() {
          @Override
          public void apply(Object resultObject, Object value) throws SAXException {
            handleChild_1768088633166523070(resultObject, value);
          }
        });
        return ignoredNodeHandler;
      }
      return super.createChild(resultObject, tagName, attrs);
    }
    private boolean checkroot_1768088633166530069(Object resultObject, Attributes attrs) {
      return !(my_stripImplementationParam && my_helperField.isImplementationNode(attrs.getValue("nodeInfo")));
    }
    private void handleChild_286176397450364079(Object resultObject, Object value) throws SAXException {
      SModuleReference child = (SModuleReference) value;
      new SModelLegacy(my_modelField).addLanguage(child);
    }
    private void handleChild_286176397450364090(Object resultObject, Object value) throws SAXException {
      SModuleReference child = (SModuleReference) value;
      new SModelLegacy(my_modelField).addEngagedOnGenerationLanguage(child);
    }
    private void handleChild_286176397450364101(Object resultObject, Object value) throws SAXException {
      SModuleReference child = (SModuleReference) value;
      my_modelField.addDevKit(child);
    }
    private void handleChild_286176397450364112(Object resultObject, Object value) throws SAXException {
      String[] child = (String[]) value;
      my_helperField.addImportToModel(my_modelField, child[0], child[1], (child[2] != null ? Integer.parseInt(child[2]) : -1), child[3] != null);
    }
    private void handleChild_1361478912184551722(Object resultObject, Object value) throws SAXException {
      SNode child = (SNode) value;
      if (child != null) {
        my_modelField.addRootNode(child);
      }
    }
    private void handleChild_1768088633166523070(Object resultObject, Object value) throws SAXException {
      Tuples._3<String, String, String> child = (Tuples._3<String, String, String>) value;
      if (my_helperField.isImplementationWithStubNode(child._1())) {
        String stubConcept = my_helperField.getStubConceptQualifiedName(child._2());
        if (stubConcept != null) {
          my_modelField.addRootNode(SNodeFactory.newRegular(stubConcept));
        }
      }
      my_hasSkippedNodesField = true;
    }
    @Override
    protected void validate(Object resultObject) throws SAXException {
      if (!(validateInternal((ModelLoadResult) resultObject))) {
        throw new SAXParseException("missing tags", null);
      }
    }
    private boolean validateInternal(ModelLoadResult result) throws SAXException {
      result.setState((my_hasSkippedNodesField ? ((my_interfaceOnlyParam ? ModelLoadingState.INTERFACE_LOADED : ModelLoadingState.NO_IMPLEMENTATION)) : ModelLoadingState.FULLY_LOADED));
      return true;
    }
  }
  public class PersistenceElementHandler extends ElementHandler {
    public PersistenceElementHandler() {
      setRequiredAttributes("version");
    }
    @Override
    protected Integer createObject(Attributes attrs) throws SAXException {
      return Integer.parseInt(attrs.getValue("version"));
    }
  }
  public class Module_referenceElementHandler extends ElementHandler {
    public Module_referenceElementHandler() {
      setRequiredAttributes("namespace");
    }
    @Override
    protected SModuleReference createObject(Attributes attrs) throws SAXException {
      return PersistenceFacade.getInstance().createModuleReference(attrs.getValue("namespace"));
    }
  }
  public class ImportElementHandler extends ElementHandler {
    public ImportElementHandler() {
      setRequiredAttributes("index", "modelUID");
    }
    @Override
    protected String[] createObject(Attributes attrs) throws SAXException {
      return new String[]{attrs.getValue("index"), attrs.getValue("modelUID"), attrs.getValue("version"), null};
    }
    @Override
    protected void handleAttribute(Object resultObject, String name, String value) throws SAXException {
      String[] result = (String[]) resultObject;
      if ("implicit".equals(name)) {
        result[3] = value;
        return;
      }
      super.handleAttribute(resultObject, name, value);
    }
  }
  public class NodeElementHandler extends ElementHandler {
    public NodeElementHandler() {
      setRequiredAttributes("type", "nodeInfo");
    }
    @Override
    protected SNode createObject(Attributes attrs) throws SAXException {
      Tuples._3<ConceptKind, StaticScope, Boolean> parsed = my_helperField.readNodeInfo(attrs.getValue("nodeInfo"));
      if (parsed == null) {
        throw new SAXParseException("bad typeInfo attribute", null);
      }
      boolean interfaceNode = false;
      if (my_interfaceOnlyParam) {
        interfaceNode = (parsed._0() == ConceptKind.INTERFACE || attrs.getValue("role") == null);
      }
      String conceptName = my_helperField.readType(attrs.getValue("type"));
      jetbrains.mps.smodel.SNode result = (interfaceNode ? SNodeFactory.newInterface(conceptName) : SNodeFactory.newRegular(conceptName));
      return result;
    }
    @Override
    protected void handleAttribute(Object resultObject, String name, String value) throws SAXException {
      SNode result = (SNode) resultObject;
      if ("role".equals(name)) {
        result.putUserObject("role", my_helperField.readRole(value));
        return;
      }
      if ("id".equals(name)) {
        SNodeId id = jetbrains.mps.smodel.SNodeId.fromString(value);
        if (id == null) {
          throw new SAXParseException("bad node ID", null);
        }
        ((jetbrains.mps.smodel.SNode) result).setId(id);
        return;
      }
      super.handleAttribute(resultObject, name, value);
    }
    @Override
    protected ElementHandler createChild(Object resultObject, String tagName, Attributes attrs) throws SAXException {
      if ("property".equals(tagName)) {
        myChildHandlersStack.push(new ChildHandler() {
          @Override
          public void apply(Object resultObject, Object value) throws SAXException {
            handleChild_286176397450364265(resultObject, value);
          }
        });
        return propertyHandler;
      }
      if ("link".equals(tagName)) {
        myChildHandlersStack.push(new ChildHandler() {
          @Override
          public void apply(Object resultObject, Object value) throws SAXException {
            handleChild_286176397450364288(resultObject, value);
          }
        });
        return linkHandler;
      }
      if ("node".equals(tagName) && checknode_1910945748547288250(resultObject, attrs)) {
        myChildHandlersStack.push(new ChildHandler() {
          @Override
          public void apply(Object resultObject, Object value) throws SAXException {
            handleChild_286176397450364333(resultObject, value);
          }
        });
        return nodeHandler;
      }
      if ("node".equals(tagName)) {
        myChildHandlersStack.push(new ChildHandler() {
          @Override
          public void apply(Object resultObject, Object value) throws SAXException {
            handleChild_1910945748545948896(resultObject, value);
          }
        });
        return ignoredNodeHandler;
      }
      return super.createChild(resultObject, tagName, attrs);
    }
    private boolean checknode_1910945748547288250(Object resultObject, Attributes attrs) {
      SNode result = (SNode) resultObject;
      if (my_stripImplementationParam && my_helperField.isImplementationNode(attrs.getValue("nodeInfo"))) {
        return false;
      }
      return !(result instanceof InterfaceSNode) || my_helperField.isInterfaceNode(attrs.getValue("nodeInfo"));
    }
    private void handleChild_286176397450364265(Object resultObject, Object value) throws SAXException {
      SNode result = (SNode) resultObject;
      String[] child = (String[]) value;
      if (child[1] != null) {
        String pname = my_helperField.readName(child[0]);
        new SNodeLegacy(result).setProperty(pname, child[1]);
      }
    }
    private void handleChild_286176397450364288(Object resultObject, Object value) throws SAXException {
      SNode result = (SNode) resultObject;
      String[] child = (String[]) value;
      Pair<Boolean, SNodeReference> pptr = my_helperField.readLink_internal(child[1]);
      SNodeReference ptr = pptr.o2;
      if (ptr == null || ptr.getModelReference() == null) {
        if (LOG.isErrorLevel()) {
          LOG.error("couldn't create reference '" + child[0] + "' from " + child[1]);
        }
        return;
      }
      new SNodeLegacy(result).setReference(my_helperField.readRole(child[0]), ptr.getModelReference(), ptr.getNodeId(), child[2]);
    }
    private void handleChild_286176397450364333(Object resultObject, Object value) throws SAXException {
      SNode result = (SNode) resultObject;
      SNode child = (SNode) value;
      if (child != null) {
        String role = (String) child.getUserObject("role");
        new SNodeLegacy(result).insertChildBefore(role, child, null);
        child.putUserObject("role", null);
      }
    }
    private void handleChild_1910945748545948896(Object resultObject, Object value) throws SAXException {
      SNode result = (SNode) resultObject;
      Tuples._3<String, String, String> child = (Tuples._3<String, String, String>) value;
      my_hasSkippedNodesField = true;
      if (my_stripImplementationParam && my_helperField.isImplementationWithStubNode(child._1())) {
        String stubConcept = my_helperField.getStubConceptQualifiedName(child._2());
        if (stubConcept != null) {
          jetbrains.mps.smodel.SNode childNode = SNodeFactory.newRegular(stubConcept);
          new SNodeLegacy(result).insertChildBefore(child._0(), childNode, null);
          return;
        }
      }
      if (result instanceof InterfaceSNode) {
        ((InterfaceSNode) result).skipRole(child._0());
      }
    }
  }
  public class IgnoredNodeElementHandler extends ElementHandler {
    public IgnoredNodeElementHandler() {
    }
    @Override
    protected Tuples._3<String, String, String> createObject(Attributes attrs) throws SAXException {
      return MultiTuple.<String,String,String>from(attrs.getValue("role"), attrs.getValue("nodeInfo"), attrs.getValue("type"));
    }
    @Override
    protected ElementHandler createChild(Object resultObject, String tagName, Attributes attrs) throws SAXException {
      if ("property".equals(tagName)) {
        myChildHandlersStack.push(null);
        return ignoredPropertyHandler;
      }
      if ("link".equals(tagName)) {
        myChildHandlersStack.push(null);
        return ignoredLinkHandler;
      }
      if ("node".equals(tagName)) {
        myChildHandlersStack.push(null);
        return ignoredNodeHandler;
      }
      return super.createChild(resultObject, tagName, attrs);
    }
  }
  public class PropertyElementHandler extends ElementHandler {
    public PropertyElementHandler() {
      setRequiredAttributes("name");
    }
    @Override
    protected String[] createObject(Attributes attrs) throws SAXException {
      return new String[]{attrs.getValue("name"), null, null};
    }
    @Override
    protected void handleAttribute(Object resultObject, String name, String value) throws SAXException {
      String[] result = (String[]) resultObject;
      if ("nameId".equals(name)) {
        result[2] = value;
        return;
      }
      if ("value".equals(name)) {
        result[1] = value;
        return;
      }
      super.handleAttribute(resultObject, name, value);
    }
  }
  public class IgnoredPropertyElementHandler extends ElementHandler {
    public IgnoredPropertyElementHandler() {
    }
  }
  public class LinkElementHandler extends ElementHandler {
    public LinkElementHandler() {
      setRequiredAttributes("role", "targetNodeId");
    }
    @Override
    protected String[] createObject(Attributes attrs) throws SAXException {
      return new String[]{attrs.getValue("role"), attrs.getValue("targetNodeId"), null, null};
    }
    @Override
    protected void handleAttribute(Object resultObject, String name, String value) throws SAXException {
      String[] result = (String[]) resultObject;
      if ("roleId".equals(name)) {
        result[3] = value;
        return;
      }
      if ("resolveInfo".equals(name)) {
        result[2] = value;
        return;
      }
      super.handleAttribute(resultObject, name, value);
    }
  }
  public class IgnoredLinkElementHandler extends ElementHandler {
    public IgnoredLinkElementHandler() {
    }
  }
}
