private void AddReferences(XElement parentElement, bool attributeReferences, XsdNodeTranslationInfo nodeInfo, bool inChoice)
        {
            #region SR
            if (nodeInfo.Node is PSMClass)
            {
                PSMClass psmClass = (PSMClass)nodeInfo.Node;
                // HACK: nodeInfos.ContainsKey(psmClass.RepresentedClass) -- this prevents references to cross-schema representatives,
                //       for now, but should be fixed in the future
                if (psmClass.IsStructuralRepresentative && nodeInfos.ContainsKey(psmClass.RepresentedClass))
                {
                    XsdNodeTranslationInfo srInfo = nodeInfos[psmClass.RepresentedClass];
                    if (srInfo.DefinesElements && !attributeReferences)
                    {
                        parentElement.XsdGroupRef(srInfo.ContentGroupName);
                    }
                    if (srInfo.DefinesAttributes && attributeReferences)
                    {
                        parentElement.XsdAttributeGroupRef(inChoice? srInfo.OptAttributeGroupName : srInfo.NonOptAttributeGroupName);
                    }
                }
            }

            #endregion

            #region attributes

            if (nodeInfo.Node is PSMClass)
            {
                PSMClass psmClass = (PSMClass)nodeInfo.Node;

                foreach (PSMAttribute psmAttribute in psmClass.PSMAttributes)
                {
                    string attributeName = NamingSupport.SuggestName(psmAttribute, attribute: true);
                    if (psmAttribute.Element && !attributeReferences)
                    {
                        parentElement.XsdAttributeAsElement(attributeName, psmAttribute);
                    }
                    if (!psmAttribute.Element && attributeReferences)
                    {
                        parentElement.XsdAttribute(attributeName, psmAttribute, inChoice);
                    }
                    if (psmAttribute.AttributeType == null)
                    {
                        Log.AddWarningFormat("Type of attribute '{0}' is not specified. ", psmAttribute);
                    }
                    else if (!psmAttribute.AttributeType.IsSealed)
                    {
                        if (psmAttribute.AttributeType.BaseType == Guid.Empty || string.IsNullOrEmpty(psmAttribute.AttributeType.XSDDefinition))
                        {
                            Log.AddWarningFormat("Can not translate type of attribute '{0}' - '{1}'. Define base type and XSD definition via Data Type Manager.", psmAttribute, psmAttribute.AttributeType);
                        }
                        else
                        {
                            usedNonDefaultAttributTypes.AddIfNotContained(psmAttribute.AttributeType);
                        }
                    }
                }
            }

            #endregion

            #region associations

            if (nodeInfo.Node is PSMAssociationMember)
            {
                PSMAssociationMember psmAssociationMember = (PSMAssociationMember)nodeInfo.Node;
                // associations
                XElement element = parentElement;
                foreach (PSMAssociation psmAssociation in psmAssociationMember.ChildPSMAssociations)
                {
                    XsdNodeTranslationInfo childInfo = nodeInfos[psmAssociation.Child];
                    if (!attributeReferences)
                    {
                        element = parentElement;
                        if (psmAssociation.IsNamed && childInfo.ComplexTypeRequired)
                        {
                            XElement wrappingLiteral = element.XsdElement(psmAssociation.Name);
                            if (childInfo.ComplexTypeRequired)
                            {
                                wrappingLiteral.TypeAttribute(childInfo.ComplexTypeName);
                            }
                            element = wrappingLiteral;
                        }

                        if (!psmAssociation.IsNamed && childInfo.GroupsRequired && childInfo.DefinesElements)
                        {
                            element = element.XsdGroupRef(childInfo.ContentGroupName);
                        }

                        if (childInfo.Node is PSMContentModel)
                        {
                            /*
                             * association name is ignored in this case,
                             * normalized schemas do not have content models
                             * with named parent associations
                             */
                            if (psmAssociation.IsNamed)
                            {
                                Log.AddErrorFormat("Name of '{0}' is ignored. Associations leading to content models should not have names (this violates rules for normalized schemas).", psmAssociation);
                            }
                            switch (((PSMContentModel)childInfo.Node).Type)
                            {
                            case PSMContentModelType.Sequence:
                                element = element.XsdSequence();
                                break;

                            case PSMContentModelType.Choice:
                                element = element.XsdChoice();
                                break;

                            case PSMContentModelType.Set:
                                // do nothing
                                break;
                            }
                            AddReferences(element, false, childInfo, false);
                        }

                        if (element != parentElement || ContentIsSet(nodeInfo.Node))
                        {
                            element.CardinalityAttributes(psmAssociation);
                        }
                    }
                    else
                    {
                        if (childInfo.GroupsRequired && childInfo.DefinesAttributes)
                        {
                            parentElement.XsdAttributeGroupRef(inChoice ? childInfo.OptAttributeGroupName : childInfo.NonOptAttributeGroupName);
                        }
                        if (childInfo.Node is PSMContentModel)
                        {
                            AddReferences(element, true, childInfo, ((PSMContentModel)childInfo.Node).Type.IsAmong(PSMContentModelType.Choice, PSMContentModelType.Set));
                        }
                    }
                }
            }

            #endregion
        }
        public void GenerateXSDStructure()
        {
            foreach (PSMAssociationMember node in PSMSchema.PSMNodes)
            {
                if (node is PSMSchemaClass)
                {
                    continue;
                }

                XsdNodeTranslationInfo nodeInfo = new XsdNodeTranslationInfo();
                nodeInfo.Node   = node;
                nodeInfos[node] = nodeInfo;

                if (node.DownCastSatisfies <PSMClass>(c => c.ParentAssociation == null) ||
                    node.DownCastSatisfies <PSMClass>(c => c.ParentAssociation != null && c.ParentAssociation.IsNamed) ||
                    node.DownCastSatisfies <PSMClass>(c => c.GeneralizationsAsGeneral.Count > 0) ||
                    node.DownCastSatisfies <PSMClass>(c => c.GetIncomingNonTreeAssociations().Count(a => a.IsNamed) > 0))
                {
                    nodeInfo.ComplexTypeRequired = true;
                    nodeInfo.ComplexTypeName     = NamingSupport.SuggestName(node, complexType: true);
                }

                if (node.DownCastSatisfies <PSMClass>(c => c.HasStructuralRepresentatives))
                {
                    nodeInfo.GroupsRequired = true;
                }

                if (node.DownCastSatisfies <PSMClass>(c => c.ParentAssociation != null && !c.ParentAssociation.IsNamed) ||
                    node.DownCastSatisfies <PSMClass>(c => c.GetIncomingNonTreeAssociations().Count(a => !a.IsNamed) > 0))
                {
                    nodeInfo.GroupsRequired = true;
                }

                nodeInfo.DefinesAttributes = TestNodeDefinesAttributes(node);
                nodeInfo.DefinesElements   = TestNodeDefinesElements(node);

                if (nodeInfo.DefinesElements && nodeInfo.GroupsRequired)
                {
                    nodeInfo.ContentGroupName = NamingSupport.SuggestName(node, contentGroup: true);
                }

                // find all structural representatives of a class
                if (node is PSMClass && nodeInfo.DefinesAttributes)
                {
                    IList <PSMClass> referencing = ((PSMClass)node).GetReferencingStructuralRepresentatives(true);
                    referencing.Add((PSMClass)node);

                    foreach (PSMClass psmClass in referencing)
                    {
                        if (psmClass.PropagatesToChoice())
                        {
                            nodeInfo.OptAttributeReference = true;
                            nodeInfo.OptAttributeGroupName = NamingSupport.SuggestName(node, optGroup: true);
                            Log.AddErrorFormat("Class '{0}' defines attributes which propagate to choice/set content model(s). Consider giving name to the parent association of the class or representing attributes of '{0}' as elements. ", node);
                        }
                        else
                        {
                            nodeInfo.NonOptAttributeReference = true;
                            nodeInfo.NonOptAttributeGroupName = NamingSupport.SuggestName(node, attributeGroup: true);
                        }
                    }
                }
            }
        }
        private void TranslateClass(XElement parentElement, PSMClass psmClass)
        {
            XsdNodeTranslationInfo nodeInfo = nodeInfos[psmClass];

            if (nodeInfo.ComplexTypeRequired)
            {
                XElement complexType = parentElement.XsdComplexType(nodeInfo.ComplexTypeName);

                XElement complexTypeContent;
                if (psmClass.SuperClass != null)
                {
                    XsdNodeTranslationInfo generalInfo = nodeInfos[psmClass.SuperClass];
                    XElement complexContent            = complexType.XsdComplexContent();
                    XElement extension = complexContent.XsdExtension(generalInfo.ComplexTypeName);
                    complexTypeContent = !ContentIsSet(psmClass) ? extension.XsdSequence() : extension.XsdAll();
                }
                else
                {
                    complexTypeContent = !ContentIsSet(psmClass) ? complexType.XsdSequence() : complexType.XsdAll();
                }



                if (ContentIsSet(psmClass) && CountContentForSet(psmClass) > 1)
                {
                    Log.AddErrorFormat("Class '{0}' has a content model of type 'set' in its content. Such classes can not have other content except this content model. ", psmClass);
                }

                if (nodeInfo.GroupsRequired)
                {
                    if (nodeInfo.DefinesAttributes)
                    {
                        complexTypeContent.XsdAttributeGroupRef(nodeInfo.NonOptAttributeGroupName);
                    }
                    if (nodeInfo.DefinesElements)
                    {
                        complexTypeContent.XsdGroupRef(nodeInfo.ContentGroupName);
                    }
                }
                else
                {
                    AddReferences(complexType, true, nodeInfo, false);
                    AddReferences(complexTypeContent, false, nodeInfo, false);
                }
            }

            if (nodeInfo.GroupsRequired)
            {
                if (nodeInfo.DefinesElements)
                {
                    XElement group         = parentElement.XsdGroup(nodeInfo.ContentGroupName);
                    XElement groupSequence = group.XsdSequence();
                    AddReferences(groupSequence, false, nodeInfo, false);
                }

                if (nodeInfo.DefinesAttributes)
                {
                    if (nodeInfo.NonOptAttributeReference)
                    {
                        XElement attributeGroup = parentElement.XsdAttributeGroup(nodeInfo.NonOptAttributeGroupName);
                        AddReferences(attributeGroup, true, nodeInfo, false);
                    }

                    if (nodeInfo.OptAttributeReference)
                    {
                        XElement attributeGroup = parentElement.XsdAttributeGroup(nodeInfo.OptAttributeGroupName);
                        AddReferences(attributeGroup, true, nodeInfo, true);
                    }
                }
            }
        }