content: /*
   *  This file is part of AndroidIDE.
   *
   *  AndroidIDE is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  AndroidIDE is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *   along with AndroidIDE.  If not, see <https://www.gnu.org/licenses/>.
   */
  
  /*
   * reserved comment block
   * DO NOT REMOVE OR ALTER!
   */
  /*
   * Copyright 2001, 2002,2004 The Apache Software Foundation.
   *
   * 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 jaxp.sun.org.apache.xerces.internal.impl.xs;
  
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Vector;
  
  /**
   * A class used to hold the internal schema grammar set for the current instance
   *
   * @xerces.internal
   *
   * @author Sandy Gao, IBM
   * @version $Id: XSGrammarBucket.java,v 1.7 2010-11-01 04:39:55 joehw Exp $
   */
  public class XSGrammarBucket {
  
      // Data
  
      /**
       * Hashtable that maps between Namespace and a Grammar
       */
      Map<String, SchemaGrammar> fGrammarRegistry = new HashMap();
      SchemaGrammar fNoNSGrammar = null;
  
      /**
       * Get the schema grammar for the specified namespace
       *
       * @param namespace
       * @return SchemaGrammar associated with the namespace
       */
      public SchemaGrammar getGrammar(String namespace) {
          if (namespace == null)
              return fNoNSGrammar;
          return (SchemaGrammar)fGrammarRegistry.get(namespace);
      }
  
      /**
       * Put a schema grammar into the registry
       * This method is for internal use only: it assumes that a grammar with
       * the same target namespace is not already in the bucket.
       *
       * @param grammar   the grammar to put in the registry
       */
      public void putGrammar(SchemaGrammar grammar) {
          if (grammar.getTargetNamespace() == null)
              fNoNSGrammar = grammar;
          else
              fGrammarRegistry.put(grammar.getTargetNamespace(), grammar);
      }
  
      /**
       * put a schema grammar and any grammars imported by it (directly or
       * inderectly) into the registry. when a grammar with the same target
       * namespace is already in the bucket, and different from the one being
       * added, it's an error, and no grammar will be added into the bucket.
       *
       * @param grammar   the grammar to put in the registry
       * @param deep      whether to add imported grammars
       * @return          whether the process succeeded
       */
      public boolean putGrammar(SchemaGrammar grammar, boolean deep) {
          // whether there is one with the same tns
          SchemaGrammar sg = getGrammar(grammar.fTargetNamespace);
          if (sg != null) {
              // if the one we have is different from the one passed, it's an error
              return sg == grammar;
          }
          // not deep import, then just add this one grammar
          if (!deep) {
              putGrammar(grammar);
              return true;
          }
  
          // get all imported grammars, and make a copy of the Vector, so that
          // we can recursively process the grammars, and add distinct ones
          // to the same vector
          Vector currGrammars = (Vector)grammar.getImportedGrammars();
          if (currGrammars == null) {
              putGrammar(grammar);
              return true;
          }
  
          Vector grammars = ((Vector)currGrammars.clone());
          SchemaGrammar sg1, sg2;
          Vector gs;
          // for all (recursively) imported grammars
          for (int i = 0; i < grammars.size(); i++) {
              // get the grammar
              sg1 = (SchemaGrammar)grammars.elementAt(i);
              // check whether the bucket has one with the same tns
              sg2 = getGrammar(sg1.fTargetNamespace);
              if (sg2 == null) {
                  // we need to add grammars imported by sg1 too
                  gs = sg1.getImportedGrammars();
                  // for all grammars imported by sg2, but not in the vector
                  // we add them to the vector
                  if(gs == null) continue;
                  for (int j = gs.size() - 1; j >= 0; j--) {
                      sg2 = (SchemaGrammar)gs.elementAt(j);
                      if (!grammars.contains(sg2))
                          grammars.addElement(sg2);
                  }
              }
              // we found one with the same target namespace
              // if the two grammars are not the same object, then it's an error
              else if (sg2 != sg1) {
                  return false;
              }
          }
  
          // now we have all imported grammars stored in the vector. add them
          putGrammar(grammar);
          for (int i = grammars.size() - 1; i >= 0; i--)
              putGrammar((SchemaGrammar)grammars.elementAt(i));
  
          return true;
      }
  
      /**
       * put a schema grammar and any grammars imported by it (directly or
       * inderectly) into the registry. when a grammar with the same target
       * namespace is already in the bucket, and different from the one being
       * added, no grammar will be added into the bucket.
       *
       * @param grammar        the grammar to put in the registry
       * @param deep           whether to add imported grammars
       * @param ignoreConflict whether to ignore grammars that already exist in the grammar
       *                       bucket or not - including 'grammar' parameter.
       * @return               whether the process succeeded
       */
      public boolean putGrammar(SchemaGrammar grammar, boolean deep, boolean ignoreConflict) {
          if (!ignoreConflict) {
              return putGrammar(grammar, deep);
          }
  
          // if grammar already exist in the bucket, we ignore the request
          SchemaGrammar sg = getGrammar(grammar.fTargetNamespace);
          if (sg == null) {
              putGrammar(grammar);
          }
  
          // not adding the imported grammars
          if (!deep) {
              return true;
          }
  
          // get all imported grammars, and make a copy of the Vector, so that
          // we can recursively process the grammars, and add distinct ones
          // to the same vector
          Vector currGrammars = (Vector)grammar.getImportedGrammars();
          if (currGrammars == null) {
              return true;
          }
  
          Vector grammars = ((Vector)currGrammars.clone());
          SchemaGrammar sg1, sg2;
          Vector gs;
          // for all (recursively) imported grammars
          for (int i = 0; i < grammars.size(); i++) {
              // get the grammar
              sg1 = (SchemaGrammar)grammars.elementAt(i);
              // check whether the bucket has one with the same tns
              sg2 = getGrammar(sg1.fTargetNamespace);
              if (sg2 == null) {
                  // we need to add grammars imported by sg1 too
                  gs = sg1.getImportedGrammars();
                  // for all grammars imported by sg2, but not in the vector
                  // we add them to the vector
                  if(gs == null) continue;
                  for (int j = gs.size() - 1; j >= 0; j--) {
                      sg2 = (SchemaGrammar)gs.elementAt(j);
                      if (!grammars.contains(sg2))
                          grammars.addElement(sg2);
                  }
              }
              // we found one with the same target namespace, ignore it
              else  {
                  grammars.remove(sg1);
              }
          }
  
          // now we have all imported grammars stored in the vector. add them
          for (int i = grammars.size() - 1; i >= 0; i--) {
              putGrammar((SchemaGrammar)grammars.elementAt(i));
          }
  
          return true;
      }
  
      /**
       * get all grammars in the registry
       *
       * @return an array of SchemaGrammars.
       */
      public SchemaGrammar[] getGrammars() {
          // get the number of grammars
          int count = fGrammarRegistry.size() + (fNoNSGrammar==null ? 0 : 1);
          SchemaGrammar[] grammars = new SchemaGrammar[count];
          // get grammars with target namespace
          int i = 0;
          for(Map.Entry<String, SchemaGrammar> entry : fGrammarRegistry.entrySet()){
              grammars[i++] = entry.getValue();
          }
  
          // add the grammar without target namespace, if any
          if (fNoNSGrammar != null)
              grammars[count-1] = fNoNSGrammar;
          return grammars;
      }
  
      /**
       * Clear the registry.
       * REVISIT: update to use another XSGrammarBucket
       */
      public void reset() {
          fNoNSGrammar = null;
          fGrammarRegistry.clear();
      }
  
  } // class XSGrammarBucket
  