<commit_before>package com.thaiopensource.relaxng.output.xsd;

import com.thaiopensource.relaxng.output.xsd.basic.SchemaTransformer;
import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeUnion;
import com.thaiopensource.relaxng.output.xsd.basic.SimpleType;
import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeRestriction;
import com.thaiopensource.relaxng.output.xsd.basic.Facet;
import com.thaiopensource.relaxng.output.xsd.basic.ParticleAll;
import com.thaiopensource.relaxng.output.xsd.basic.ParticleVisitor;
import com.thaiopensource.relaxng.output.xsd.basic.Element;
import com.thaiopensource.relaxng.output.xsd.basic.ParticleSequence;
import com.thaiopensource.relaxng.output.xsd.basic.GroupRef;
import com.thaiopensource.relaxng.output.xsd.basic.ParticleRepeat;
import com.thaiopensource.relaxng.output.xsd.basic.ParticleChoice;
import com.thaiopensource.relaxng.output.xsd.basic.Particle;
import com.thaiopensource.relaxng.output.xsd.basic.Occurs;
import com.thaiopensource.relaxng.output.xsd.basic.Schema;
import com.thaiopensource.relaxng.output.xsd.basic.AttributeUseChoice;
import com.thaiopensource.relaxng.output.xsd.basic.AttributeUse;
import com.thaiopensource.relaxng.output.xsd.basic.SingleAttributeUse;
import com.thaiopensource.relaxng.output.xsd.basic.Attribute;
import com.thaiopensource.relaxng.output.xsd.basic.OptionalAttribute;
import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroup;
import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroupRef;
import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroupDefinition;
import com.thaiopensource.relaxng.output.xsd.basic.AbstractAttributeUseVisitor;
import com.thaiopensource.relaxng.output.xsd.basic.WildcardAttribute;
import com.thaiopensource.relaxng.output.xsd.basic.Wildcard;
import com.thaiopensource.relaxng.output.xsd.basic.WildcardElement;
import com.thaiopensource.relaxng.output.xsd.basic.ComplexType;
import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeComplexContent;
import com.thaiopensource.relaxng.output.common.Name;
import com.thaiopensource.relaxng.output.common.ErrorReporter;

import java.util.List;
import java.util.Iterator;
import java.util.Vector;
import java.util.Map;
import java.util.Collections;
import java.util.Set;
import java.util.HashSet;
import java.util.HashMap;

class Transformer extends SchemaTransformer {
  private final AttributeMapper attributeMapper = new AttributeMapper();
  private final Set transformedAttributeGroups = new HashSet();
  private final ErrorReporter er;
  private boolean preserveAllGroup = false;

  Transformer(Schema schema, ErrorReporter er) {
    super(schema);
    this.er = er;
  }

  public Object visitUnion(SimpleTypeUnion t) {
    List list = transformSimpleTypeList(t.getChildren());
    SimpleType combined = combineEnumeration(t, list);
    if (combined != null)
      return combined;
    return new SimpleTypeUnion(t.getLocation(), t.getAnnotation(), list);
  }

  private static SimpleType combineEnumeration(SimpleTypeUnion orig, List transformedChildren) {
    if (transformedChildren.size() < 2)
      return null;
    Object first = transformedChildren.get(0);
    if (!(first instanceof SimpleTypeRestriction))
      return null;
    String builtinTypeName = ((SimpleTypeRestriction)first).getName();
    List facets = new Vector();
    for (Iterator iter = transformedChildren.iterator(); iter.hasNext();) {
      Object obj = iter.next();
      if (!(obj instanceof SimpleTypeRestriction))
        return null;
      SimpleTypeRestriction restriction = (SimpleTypeRestriction)obj;
      if (!restriction.getName().equals(builtinTypeName))
        return null;
      if (restriction.getFacets().isEmpty())
        return null;
      for (Iterator facetIter = restriction.getFacets().iterator(); facetIter.hasNext();) {
        Facet facet = (Facet)facetIter.next();
        if (!facet.getName().equals("enumeration"))
          return null;
        facets.add(facet);
      }
    }
    return new SimpleTypeRestriction(orig.getLocation(), orig.getAnnotation(), builtinTypeName, facets);
  }

  class SequenceDetector implements ParticleVisitor {
    public Object visitElement(Element p) {
      return Boolean.FALSE;
    }

    public Object visitWildcardElement(WildcardElement p) {
      return Boolean.FALSE;
    }

    public Object visitSequence(ParticleSequence p) {
      return Boolean.TRUE;
    }

    public Object visitGroupRef(GroupRef p) {
      return getSchema().getGroup(p.getName()).getParticle().accept(this);
    }

    public Object visitAll(ParticleAll p) {
      return Boolean.FALSE;
    }

    public Object visitRepeat(ParticleRepeat p) {
      return p.getChild().accept(this);
    }

    public Object visitChoice(ParticleChoice p) {
      for (Iterator iter = p.getChildren().iterator(); iter.hasNext();)
        if (((Particle)iter.next()).accept(this) == Boolean.TRUE)
          return Boolean.TRUE;
      return Boolean.FALSE;
    }
  }

  class AllBodyTransformer extends SchemaTransformer {
    public AllBodyTransformer(Schema schema) {
      super(schema);
    }

    public Object visitGroupRef(GroupRef p) {
      if (new SequenceDetector().visitGroupRef(p) == Boolean.FALSE)
        return p;
      return getSchema().getGroup(p.getName()).getParticle().accept(this);
    }

    public Object visitSequence(ParticleSequence p) {
      return new ParticleChoice(p.getLocation(), p.getAnnotation(), transformParticleList(p.getChildren()));
    }

    public Object visitRepeat(ParticleRepeat p) {
      return p.getChild().accept(this);
    }

    public Object visitElement(Element p) {
      return Transformer.this.visitElement(p);
    }
  }


  public Object visitAll(ParticleAll p) {
    if (preserveAllGroup) {
      preserveAllGroup = false;
      return super.visitAll(p);
    }
    return new ParticleRepeat(p.getLocation(),
                              p.getAnnotation(),
                              new ParticleChoice(p.getLocation(),
                                                 null,
                                                 new AllBodyTransformer(getSchema()).transformParticleList(transformParticleList(p.getChildren()))),
                              Occurs.ZERO_OR_MORE);

  }

  public Object visitAttributeGroup(AttributeGroup a) {
    List children = transformAttributeUseList(a.getChildren());
    Wildcard wildcard = null;
    boolean[] removeWildcard = new boolean[children.size()];
    boolean multipleWildcards = false;
    int wildcardUseIndex = -1;
    for (int i = 0; i < removeWildcard.length; i++) {
      Wildcard wc = attributeMapper.getAttributeWildcard((AttributeUse)children.get(i));
      if (wc != null) {
        if (wildcard == null) {
          wildcard = wc;
          wildcardUseIndex = i;
        }
        else {
          multipleWildcards = true;
          Wildcard union = Wildcard.union(wildcard, wc);
          if (union.equals(wildcard))
            removeWildcard[i] = true;
          else if (union.equals(wc)) {
            if (wildcardUseIndex >= 0)
              removeWildcard[wildcardUseIndex] = true;
            wildcardUseIndex = i;
            wildcard = wc;
          }
          else {
            removeWildcard[i] = true;
            if (wildcardUseIndex >= 0)
              removeWildcard[wildcardUseIndex] = true;
            wildcard = union;
            wildcardUseIndex = -1;
          }
        }
      }
    }
    if (!multipleWildcards) {
      if (children == a.getChildren())
        return a;
      return new AttributeGroup(a.getLocation(), a.getAnnotation(), children);
    }
    List newChildren = new Vector();
    for (int i = 0; i < removeWildcard.length; i++) {
      AttributeUse att = (AttributeUse)children.get(i);
      if (removeWildcard[i])
        att = (AttributeUse)att.accept(new AttributeTransformer(null, null, false));
      newChildren.add(att);
    }
    if (wildcardUseIndex == -1)
      newChildren.add(new WildcardAttribute(a.getLocation(), null, wildcard));
    return new AttributeGroup(a.getLocation(), a.getAnnotation(), newChildren);
  }

  public Object visitAttributeUseChoice(AttributeUseChoice a) {
    List children = transformAttributeUseList(a.getChildren());
    Map[] maps = new Map[children.size()];
    int wildcardUseIndex = -1;
    Wildcard wildcard = null;
    for (int i = 0; i < maps.length; i++) {
      maps[i] = attributeMapper.getAttributeMap((AttributeUse)children.get(i));
      Wildcard wc = attributeMapper.getAttributeWildcard((AttributeUse)children.get(i));
      if (wc != null) {
        if (wildcard == null) {
          wildcard = wc;
          wildcardUseIndex = i;
        }
        else {
          Wildcard union = Wildcard.union(wildcard, wc);
          if (!union.equals(wildcard)) {
            if (union.equals(wc))
              wildcardUseIndex = i;
            else
              wildcardUseIndex = -1;
            wildcard = union;
          }
        }
      }
    }
    Set common = new HashSet(maps[0].keySet());
    Set union = new HashSet(maps[0].keySet());
    for (int i = 1; i < maps.length; i++) {
      common.retainAll(maps[i].keySet());
      union.addAll(maps[i].keySet());
    }
    Set[] retainAttributeNames = new Set[children.size()];
    for (int i = 0; i < retainAttributeNames.length; i++)
      retainAttributeNames[i] = new HashSet();
    List newChildren = new Vector();
    for (Iterator iter = union.iterator(); iter.hasNext();) {
      Name name = (Name)iter.next();
      if (wildcard == null || !wildcard.contains(name)) {
        SingleAttributeUse[] uses = new SingleAttributeUse[maps.length];
        int useIndex = -1;
        for (int i = 0; i < maps.length; i++) {
          uses[i] = (SingleAttributeUse)maps[i].get(name);
          if (uses[i] != null) {
            if (useIndex >= 0)
              useIndex = -2;
            else if (useIndex == -1)
              useIndex = i;
          }
        }
        if (useIndex < 0)
          useIndex = chooseUseIndex(uses);
        if (useIndex >= 0)
          retainAttributeNames[useIndex].add(name);
        else {
          List choices = new Vector();
          for (int i = 0; i < uses.length; i++)
            choices.add(uses[i].getType());
          Attribute tem = new Attribute(a.getLocation(),
                                        null,
                                        name,
                                        (SimpleType)new SimpleTypeUnion(a.getLocation(), null, choices).accept(this));
          if (common.contains(name))
            newChildren.add(tem);
          else
            newChildren.add(new OptionalAttribute(a.getLocation(), null, tem, null));
        }
      }
    }
    for (int i = 0; i < retainAttributeNames.length; i++) {
      Object tem = ((AttributeUse)children.get(i)).accept(new AttributeTransformer(retainAttributeNames[i],
                                                                                   common,
                                                                                   i == wildcardUseIndex));
      if (!tem.equals(AttributeGroup.EMPTY))
        newChildren.add(tem);
    }
    if (wildcard != null && wildcardUseIndex == -1)
      newChildren.add(new WildcardAttribute(a.getLocation(), null, wildcard));
    return new AttributeGroup(a.getLocation(), a.getAnnotation(), newChildren);
  }

  private static int chooseUseIndex(SingleAttributeUse[] uses) {
    for (int i = 0; i < uses.length; i++)
      if (uses[i].getType() == null && uses[i].getDefaultValue() == null)
        return i;
    int firstIndex = -1;
    for (int i = 0; i < uses.length; i++) {
      if (uses[i] != null) {
        if (firstIndex == -1)
          firstIndex = i;
        else if (!uses[i].equals(uses[firstIndex]))
          return -1;<commit_msg>Avoid NPE with attribute choice<commit_after>package com.thaiopensource.relaxng.output.xsd;

import com.thaiopensource.relaxng.output.xsd.basic.SchemaTransformer;
import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeUnion;
import com.thaiopensource.relaxng.output.xsd.basic.SimpleType;
import com.thaiopensource.relaxng.output.xsd.basic.SimpleTypeRestriction;
import com.thaiopensource.relaxng.output.xsd.basic.Facet;
import com.thaiopensource.relaxng.output.xsd.basic.ParticleAll;
import com.thaiopensource.relaxng.output.xsd.basic.ParticleVisitor;
import com.thaiopensource.relaxng.output.xsd.basic.Element;
import com.thaiopensource.relaxng.output.xsd.basic.ParticleSequence;
import com.thaiopensource.relaxng.output.xsd.basic.GroupRef;
import com.thaiopensource.relaxng.output.xsd.basic.ParticleRepeat;
import com.thaiopensource.relaxng.output.xsd.basic.ParticleChoice;
import com.thaiopensource.relaxng.output.xsd.basic.Particle;
import com.thaiopensource.relaxng.output.xsd.basic.Occurs;
import com.thaiopensource.relaxng.output.xsd.basic.Schema;
import com.thaiopensource.relaxng.output.xsd.basic.AttributeUseChoice;
import com.thaiopensource.relaxng.output.xsd.basic.AttributeUse;
import com.thaiopensource.relaxng.output.xsd.basic.SingleAttributeUse;
import com.thaiopensource.relaxng.output.xsd.basic.Attribute;
import com.thaiopensource.relaxng.output.xsd.basic.OptionalAttribute;
import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroup;
import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroupRef;
import com.thaiopensource.relaxng.output.xsd.basic.AttributeGroupDefinition;
import com.thaiopensource.relaxng.output.xsd.basic.AbstractAttributeUseVisitor;
import com.thaiopensource.relaxng.output.xsd.basic.WildcardAttribute;
import com.thaiopensource.relaxng.output.xsd.basic.Wildcard;
import com.thaiopensource.relaxng.output.xsd.basic.WildcardElement;
import com.thaiopensource.relaxng.output.xsd.basic.ComplexType;
import com.thaiopensource.relaxng.output.xsd.basic.ComplexTypeComplexContent;
import com.thaiopensource.relaxng.output.common.Name;
import com.thaiopensource.relaxng.output.common.ErrorReporter;

import java.util.List;
import java.util.Iterator;
import java.util.Vector;
import java.util.Map;
import java.util.Collections;
import java.util.Set;
import java.util.HashSet;
import java.util.HashMap;

class Transformer extends SchemaTransformer {
  private final AttributeMapper attributeMapper = new AttributeMapper();
  private final Set transformedAttributeGroups = new HashSet();
  private final ErrorReporter er;
  private boolean preserveAllGroup = false;

  Transformer(Schema schema, ErrorReporter er) {
    super(schema);
    this.er = er;
  }

  public Object visitUnion(SimpleTypeUnion t) {
    List list = transformSimpleTypeList(t.getChildren());
    SimpleType combined = combineEnumeration(t, list);
    if (combined != null)
      return combined;
    return new SimpleTypeUnion(t.getLocation(), t.getAnnotation(), list);
  }

  private static SimpleType combineEnumeration(SimpleTypeUnion orig, List transformedChildren) {
    if (transformedChildren.size() < 2)
      return null;
    Object first = transformedChildren.get(0);
    if (!(first instanceof SimpleTypeRestriction))
      return null;
    String builtinTypeName = ((SimpleTypeRestriction)first).getName();
    List facets = new Vector();
    for (Iterator iter = transformedChildren.iterator(); iter.hasNext();) {
      Object obj = iter.next();
      if (!(obj instanceof SimpleTypeRestriction))
        return null;
      SimpleTypeRestriction restriction = (SimpleTypeRestriction)obj;
      if (!restriction.getName().equals(builtinTypeName))
        return null;
      if (restriction.getFacets().isEmpty())
        return null;
      for (Iterator facetIter = restriction.getFacets().iterator(); facetIter.hasNext();) {
        Facet facet = (Facet)facetIter.next();
        if (!facet.getName().equals("enumeration"))
          return null;
        facets.add(facet);
      }
    }
    return new SimpleTypeRestriction(orig.getLocation(), orig.getAnnotation(), builtinTypeName, facets);
  }

  class SequenceDetector implements ParticleVisitor {
    public Object visitElement(Element p) {
      return Boolean.FALSE;
    }

    public Object visitWildcardElement(WildcardElement p) {
      return Boolean.FALSE;
    }

    public Object visitSequence(ParticleSequence p) {
      return Boolean.TRUE;
    }

    public Object visitGroupRef(GroupRef p) {
      return getSchema().getGroup(p.getName()).getParticle().accept(this);
    }

    public Object visitAll(ParticleAll p) {
      return Boolean.FALSE;
    }

    public Object visitRepeat(ParticleRepeat p) {
      return p.getChild().accept(this);
    }

    public Object visitChoice(ParticleChoice p) {
      for (Iterator iter = p.getChildren().iterator(); iter.hasNext();)
        if (((Particle)iter.next()).accept(this) == Boolean.TRUE)
          return Boolean.TRUE;
      return Boolean.FALSE;
    }
  }

  class AllBodyTransformer extends SchemaTransformer {
    public AllBodyTransformer(Schema schema) {
      super(schema);
    }

    public Object visitGroupRef(GroupRef p) {
      if (new SequenceDetector().visitGroupRef(p) == Boolean.FALSE)
        return p;
      return getSchema().getGroup(p.getName()).getParticle().accept(this);
    }

    public Object visitSequence(ParticleSequence p) {
      return new ParticleChoice(p.getLocation(), p.getAnnotation(), transformParticleList(p.getChildren()));
    }

    public Object visitRepeat(ParticleRepeat p) {
      return p.getChild().accept(this);
    }

    public Object visitElement(Element p) {
      return Transformer.this.visitElement(p);
    }
  }


  public Object visitAll(ParticleAll p) {
    if (preserveAllGroup) {
      preserveAllGroup = false;
      return super.visitAll(p);
    }
    return new ParticleRepeat(p.getLocation(),
                              p.getAnnotation(),
                              new ParticleChoice(p.getLocation(),
                                                 null,
                                                 new AllBodyTransformer(getSchema()).transformParticleList(transformParticleList(p.getChildren()))),
                              Occurs.ZERO_OR_MORE);

  }

  public Object visitAttributeGroup(AttributeGroup a) {
    List children = transformAttributeUseList(a.getChildren());
    Wildcard wildcard = null;
    boolean[] removeWildcard = new boolean[children.size()];
    boolean multipleWildcards = false;
    int wildcardUseIndex = -1;
    for (int i = 0; i < removeWildcard.length; i++) {
      Wildcard wc = attributeMapper.getAttributeWildcard((AttributeUse)children.get(i));
      if (wc != null) {
        if (wildcard == null) {
          wildcard = wc;
          wildcardUseIndex = i;
        }
        else {
          multipleWildcards = true;
          Wildcard union = Wildcard.union(wildcard, wc);
          if (union.equals(wildcard))
            removeWildcard[i] = true;
          else if (union.equals(wc)) {
            if (wildcardUseIndex >= 0)
              removeWildcard[wildcardUseIndex] = true;
            wildcardUseIndex = i;
            wildcard = wc;
          }
          else {
            removeWildcard[i] = true;
            if (wildcardUseIndex >= 0)
              removeWildcard[wildcardUseIndex] = true;
            wildcard = union;
            wildcardUseIndex = -1;
          }
        }
      }
    }
    if (!multipleWildcards) {
      if (children == a.getChildren())
        return a;
      return new AttributeGroup(a.getLocation(), a.getAnnotation(), children);
    }
    List newChildren = new Vector();
    for (int i = 0; i < removeWildcard.length; i++) {
      AttributeUse att = (AttributeUse)children.get(i);
      if (removeWildcard[i])
        att = (AttributeUse)att.accept(new AttributeTransformer(null, null, false));
      newChildren.add(att);
    }
    if (wildcardUseIndex == -1)
      newChildren.add(new WildcardAttribute(a.getLocation(), null, wildcard));
    return new AttributeGroup(a.getLocation(), a.getAnnotation(), newChildren);
  }

  public Object visitAttributeUseChoice(AttributeUseChoice a) {
    List children = transformAttributeUseList(a.getChildren());
    Map[] maps = new Map[children.size()];
    int wildcardUseIndex = -1;
    Wildcard wildcard = null;
    for (int i = 0; i < maps.length; i++) {
      maps[i] = attributeMapper.getAttributeMap((AttributeUse)children.get(i));
      Wildcard wc = attributeMapper.getAttributeWildcard((AttributeUse)children.get(i));
      if (wc != null) {
        if (wildcard == null) {
          wildcard = wc;
          wildcardUseIndex = i;
        }
        else {
          Wildcard union = Wildcard.union(wildcard, wc);
          if (!union.equals(wildcard)) {
            if (union.equals(wc))
              wildcardUseIndex = i;
            else
              wildcardUseIndex = -1;
            wildcard = union;
          }
        }
      }
    }
    Set common = new HashSet(maps[0].keySet());
    Set union = new HashSet(maps[0].keySet());
    for (int i = 1; i < maps.length; i++) {
      common.retainAll(maps[i].keySet());
      union.addAll(maps[i].keySet());
    }
    Set[] retainAttributeNames = new Set[children.size()];
    for (int i = 0; i < retainAttributeNames.length; i++)
      retainAttributeNames[i] = new HashSet();
    List newChildren = new Vector();
    for (Iterator iter = union.iterator(); iter.hasNext();) {
      Name name = (Name)iter.next();
      if (wildcard == null || !wildcard.contains(name)) {
        SingleAttributeUse[] uses = new SingleAttributeUse[maps.length];
        int useIndex = -1;
        for (int i = 0; i < maps.length; i++) {
          uses[i] = (SingleAttributeUse)maps[i].get(name);
          if (uses[i] != null) {
            if (useIndex >= 0)
              useIndex = -2;
            else if (useIndex == -1)
              useIndex = i;
          }
        }
        if (useIndex < 0)
          useIndex = chooseUseIndex(uses);
        if (useIndex >= 0)
          retainAttributeNames[useIndex].add(name);
        else {
          List choices = new Vector();
          for (int i = 0; i < uses.length; i++)
            choices.add(uses[i].getType());
          Attribute tem = new Attribute(a.getLocation(),
                                        null,
                                        name,
                                        (SimpleType)new SimpleTypeUnion(a.getLocation(), null, choices).accept(this));
          if (common.contains(name))
            newChildren.add(tem);
          else
            newChildren.add(new OptionalAttribute(a.getLocation(), null, tem, null));
        }
      }
    }
    for (int i = 0; i < retainAttributeNames.length; i++) {
      Object tem = ((AttributeUse)children.get(i)).accept(new AttributeTransformer(retainAttributeNames[i],
                                                                                   common,
                                                                                   i == wildcardUseIndex));
      if (!tem.equals(AttributeGroup.EMPTY))
        newChildren.add(tem);
    }
    if (wildcard != null && wildcardUseIndex == -1)
      newChildren.add(new WildcardAttribute(a.getLocation(), null, wildcard));
    return new AttributeGroup(a.getLocation(), a.getAnnotation(), newChildren);
  }

  private static int chooseUseIndex(SingleAttributeUse[] uses) {
    for (int i = 0; i < uses.length; i++)
      if (uses[i] != null && uses[i].getType() == null && uses[i].getDefaultValue() == null)
        return i;
    int firstIndex = -1;
    for (int i = 0; i < uses.length; i++) {
      if (uses[i] != null) {
        if (firstIndex == -1)
          firstIndex = i;
        else if (!uses[i].equals(uses[firstIndex]))
          return -1;
{'fraction_non_alphanumeric': 0.1151553582752061, 'fraction_numerical': 0.002621010357218347, 'mean_word_length': 2.709581307824996, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 30, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6540770', 'n_tokens_mistral': 6956, 'n_tokens_neox': 6678, 'n_words': 1381}