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-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.
   */
  /*
   * $Id: MultiDOM.java,v 1.5 2005/09/28 13:48:36 pvedula Exp $
   */
  
  package jaxp.sun.org.apache.xalan.internal.xsltc.dom;
  
  import jaxp.sun.org.apache.xalan.internal.xsltc.DOM;
  import jaxp.sun.org.apache.xalan.internal.xsltc.StripFilter;
  import jaxp.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary;
  import jaxp.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable;
  import jaxp.sun.org.apache.xml.internal.serializer.SerializationHandler;
  import jaxp.sun.org.apache.xalan.internal.xsltc.TransletException;
  import jaxp.sun.org.apache.xml.internal.dtm.DTM;
  import jaxp.sun.org.apache.xml.internal.dtm.Axis;
  import jaxp.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
  import jaxp.sun.org.apache.xml.internal.dtm.DTMManager;
  import jaxp.sun.org.apache.xml.internal.dtm.ref.DTMAxisIteratorBase;
  import jaxp.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase;
  import jaxp.sun.org.apache.xml.internal.utils.SuballocatedIntVector;
  
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  
  /**
   * @author Jacek Ambroziak
   * @author Morten Jorgensen
   * @author Erwin Bolwidt <ejb@klomp.org>
   */
  public final class MultiDOM implements DOM {
  
      private static final int NO_TYPE = DOM.FIRST_TYPE - 2;
      private static final int INITIAL_SIZE = 4;
  
      private DOM[] _adapters;
      private DOMAdapter _main;
      private DTMManager _dtmManager;
      private int _free;
      private int _size;
  
      private Hashtable _documents = new Hashtable();
  
      private final class AxisIterator extends DTMAxisIteratorBase {
          // constitutive data
          private final int _axis;
          private final int _type;
          // implementation mechanism
          private DTMAxisIterator _source;
          private int _dtmId = -1;
  
          public AxisIterator(final int axis, final int type) {
              _axis = axis;
              _type = type;
          }
  
          public int next() {
              if (_source == null) {
                  return(DTMAxisIterator.END);
              }
              return _source.next();
          }
  
  
          public void setRestartable(boolean flag) {
              if (_source != null) {
                  _source.setRestartable(flag);
              }
          }
  
          public DTMAxisIterator setStartNode(final int node) {
              if (node == DTM.NULL) {
                  return this;
              }
  
              int dom = node >>> DTMManager.IDENT_DTM_NODE_BITS;
  
              // Get a new source first time and when mask changes
              if (_source == null || _dtmId != dom) {
                  if (_type == NO_TYPE) {
                      _source = _adapters[dom].getAxisIterator(_axis);
                  } else if (_axis == Axis.CHILD) {
                      _source = _adapters[dom].getTypedChildren(_type);
                  } else {
                      _source = _adapters[dom].getTypedAxisIterator(_axis, _type);
                  }
              }
  
              _dtmId = dom;
              _source.setStartNode(node);
              return this;
          }
  
          public DTMAxisIterator reset() {
              if (_source != null) {
                  _source.reset();
              }
              return this;
          }
  
          public int getLast() {
              if (_source != null) {
                  return _source.getLast();
              }
              else {
                  return DTMAxisIterator.END;
              }
          }
  
          public int getPosition() {
              if (_source != null) {
                  return _source.getPosition();
              }
              else {
                  return DTMAxisIterator.END;
              }
          }
  
          public boolean isReverse() {
              return Axis.isReverse(_axis);
          }
  
          public void setMark() {
              if (_source != null) {
                  _source.setMark();
              }
          }
  
          public void gotoMark() {
              if (_source != null) {
                  _source.gotoMark();
              }
          }
  
          public DTMAxisIterator cloneIterator() {
              final AxisIterator clone = new AxisIterator(_axis, _type);
              if (_source != null) {
                  clone._source = _source.cloneIterator();
              }
              clone._dtmId = _dtmId;
              return clone;
          }
      } // end of AxisIterator
  
  
      /**************************************************************
       * This is a specialised iterator for predicates comparing node or
       * attribute values to variable or parameter values.
       */
      private final class NodeValueIterator extends DTMAxisIteratorBase {
  
          private DTMAxisIterator _source;
          private String _value;
          private boolean _op;
          private final boolean _isReverse;
          private int _returnType = RETURN_PARENT;
  
          public NodeValueIterator(DTMAxisIterator source, int returnType,
                                   String value, boolean op) {
              _source = source;
              _returnType = returnType;
              _value = value;
              _op = op;
              _isReverse = source.isReverse();
          }
  
          public boolean isReverse() {
              return _isReverse;
          }
  
          public DTMAxisIterator cloneIterator() {
              try {
                  NodeValueIterator clone = (NodeValueIterator)super.clone();
                  clone._source = _source.cloneIterator();
                  clone.setRestartable(false);
                  return clone.reset();
              }
              catch (CloneNotSupportedException e) {
                  BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR,
                                            e.toString());
                  return null;
              }
          }
  
  
          public void setRestartable(boolean isRestartable) {
              _isRestartable = isRestartable;
              _source.setRestartable(isRestartable);
          }
  
          public DTMAxisIterator reset() {
              _source.reset();
              return resetPosition();
          }
  
          public int next() {
  
              int node;
              while ((node = _source.next()) != DTMAxisIterator.END) {
                  String val = getStringValueX(node);
                  if (_value.equals(val) == _op) {
                      if (_returnType == RETURN_CURRENT)
                          return returnNode(node);
                      else
                          return returnNode(getParent(node));
                  }
              }
              return DTMAxisIterator.END;
          }
  
          public DTMAxisIterator setStartNode(int node) {
              if (_isRestartable) {
                  _source.setStartNode(_startNode = node);
                  return resetPosition();
              }
              return this;
          }
  
          public void setMark() {
              _source.setMark();
          }
  
          public void gotoMark() {
              _source.gotoMark();
          }
      }
  
      public MultiDOM(DOM main) {
          _size = INITIAL_SIZE;
          _free = 1;
          _adapters = new DOM[INITIAL_SIZE];
          DOMAdapter adapter = (DOMAdapter)main;
          _adapters[0] = adapter;
          _main = adapter;
          DOM dom = adapter.getDOMImpl();
          if (dom instanceof DTMDefaultBase) {
              _dtmManager = ((DTMDefaultBase)dom).getManager();
          }
  
          // %HZ% %REVISIT% Is this the right thing to do here?  In the old
          // %HZ% %REVISIT% version, the main document did not get added through
          // %HZ% %REVISIT% a call to addDOMAdapter, which meant it couldn't be
          // %HZ% %REVISIT% found by a call to getDocumentMask.  The problem is
          // %HZ% %REVISIT% TransformerHandler is typically constructed with a
          // %HZ% %REVISIT% system ID equal to the stylesheet's URI; with SAX
          // %HZ% %REVISIT% input, it ends up giving that URI to the document.
          // %HZ% %REVISIT% Then, any references to document('') are resolved
          // %HZ% %REVISIT% using the stylesheet's URI.
          // %HZ% %REVISIT% MultiDOM.getDocumentMask is called to verify that
          // %HZ% %REVISIT% a document associated with that URI has not been
          // %HZ% %REVISIT% encountered, and that method ends up returning the
          // %HZ% %REVISIT% mask of the main document, when what we really what
          // %HZ% %REVISIT% is to read the stylesheet itself!
          addDOMAdapter(adapter, false);
      }
  
      public int nextMask() {
          return _free;
      }
  
      public void setupMapping(String[] names, String[] uris, int[] types, String[] namespaces) {
          // This method only has a function in DOM adapters
      }
  
      public int addDOMAdapter(DOMAdapter adapter) {
          return addDOMAdapter(adapter, true);
      }
  
      private int addDOMAdapter(DOMAdapter adapter, boolean indexByURI) {
          // Add the DOM adapter to the array of DOMs
          DOM dom = adapter.getDOMImpl();
  
          int domNo = 1;
          int dtmSize = 1;
          SuballocatedIntVector dtmIds = null;
          if (dom instanceof DTMDefaultBase) {
              DTMDefaultBase dtmdb = (DTMDefaultBase)dom;
              dtmIds = dtmdb.getDTMIDs();
              dtmSize = dtmIds.size();
              domNo = dtmIds.elementAt(dtmSize-1) >>> DTMManager.IDENT_DTM_NODE_BITS;
          }
          else if (dom instanceof SimpleResultTreeImpl) {
              SimpleResultTreeImpl simpleRTF = (SimpleResultTreeImpl)dom;
              domNo = simpleRTF.getDocument() >>> DTMManager.IDENT_DTM_NODE_BITS;
          }
  
          if (domNo >= _size) {
              int oldSize = _size;
              do {
                  _size *= 2;
              } while (_size <= domNo);
  
              final DOMAdapter[] newArray = new DOMAdapter[_size];
              System.arraycopy(_adapters, 0, newArray, 0, oldSize);
              _adapters = newArray;
          }
  
          _free = domNo + 1;
  
          if (dtmSize == 1) {
              _adapters[domNo] = adapter;
          }
          else if (dtmIds != null) {
              int domPos = 0;
              for (int i = dtmSize - 1; i >= 0; i--) {
                  domPos = dtmIds.elementAt(i) >>> DTMManager.IDENT_DTM_NODE_BITS;
                  _adapters[domPos] = adapter;
              }
              domNo = domPos;
          }
  
          // Store reference to document (URI) in hashtable
          if (indexByURI) {
              String uri = adapter.getDocumentURI(0);
              _documents.put(uri, new Integer(domNo));
          }
  
          // If the dom is an AdaptiveResultTreeImpl, we need to create a
          // DOMAdapter around its nested dom object (if it is non-null) and
          // add the DOMAdapter to the list.
          if (dom instanceof AdaptiveResultTreeImpl) {
              AdaptiveResultTreeImpl adaptiveRTF = (AdaptiveResultTreeImpl)dom;
              DOM nestedDom = adaptiveRTF.getNestedDOM();
              if (nestedDom != null) {
                  DOMAdapter newAdapter = new DOMAdapter(nestedDom,
                                                         adapter.getNamesArray(),
                                                         adapter.getUrisArray(),
                                                         adapter.getTypesArray(),
                                                         adapter.getNamespaceArray());
                  addDOMAdapter(newAdapter);
              }
          }
  
          return domNo;
      }
  
      public int getDocumentMask(String uri) {
          Integer domIdx = (Integer)_documents.get(uri);
          if (domIdx == null) {
              return(-1);
          } else {
              return domIdx.intValue();
          }
      }
  
      public DOM getDOMAdapter(String uri) {
          Integer domIdx = (Integer)_documents.get(uri);
          if (domIdx == null) {
              return(null);
          } else {
              return(_adapters[domIdx.intValue()]);
          }
      }
  
      public int getDocument()
      {
          return _main.getDocument();
      }
  
      public DTMManager getDTMManager() {
          return _dtmManager;
      }
  
      /**
        * Returns singleton iterator containing the document root
        */
      public DTMAxisIterator getIterator() {
          // main source document @ 0
          return _main.getIterator();
      }
  
      public String getStringValue() {
          return _main.getStringValue();
      }
  
      public DTMAxisIterator getChildren(final int node) {
          return _adapters[getDTMId(node)].getChildren(node);
      }
  
      public DTMAxisIterator getTypedChildren(final int type) {
          return new AxisIterator(Axis.CHILD, type);
      }
  
      public DTMAxisIterator getAxisIterator(final int axis) {
          return new AxisIterator(axis, NO_TYPE);
      }
  
      public DTMAxisIterator getTypedAxisIterator(final int axis, final int type)
      {
          return new AxisIterator(axis, type);
      }
  
      public DTMAxisIterator getNthDescendant(int node, int n,
                                              boolean includeself)
      {
          return _adapters[getDTMId(node)].getNthDescendant(node, n, includeself);
      }
  
      public DTMAxisIterator getNodeValueIterator(DTMAxisIterator iterator,
                                                  int type, String value,
                                                  boolean op)
      {
          return(new NodeValueIterator(iterator, type, value, op));
      }
  
      public DTMAxisIterator getNamespaceAxisIterator(final int axis,
                                                      final int ns)
      {
          DTMAxisIterator iterator = _main.getNamespaceAxisIterator(axis, ns);
          return(iterator);
      }
  
      public DTMAxisIterator orderNodes(DTMAxisIterator source, int node) {
          return _adapters[getDTMId(node)].orderNodes(source, node);
      }
  
      public int getExpandedTypeID(final int node) {
          if (node != DTM.NULL) {
              return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getExpandedTypeID(node);
          }
          else {
              return DTM.NULL;
          }
      }
  
      public int getNamespaceType(final int node) {
          return _adapters[getDTMId(node)].getNamespaceType(node);
      }
  
      public int getNSType(int node)
     {
          return _adapters[getDTMId(node)].getNSType(node);
     }
  
      public int getParent(final int node) {
          if (node == DTM.NULL) {
              return DTM.NULL;
          }
          return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getParent(node);
      }
  
      public int getAttributeNode(final int type, final int el) {
          if (el == DTM.NULL) {
              return DTM.NULL;
          }
          return _adapters[el >>> DTMManager.IDENT_DTM_NODE_BITS].getAttributeNode(type, el);
      }
  
      public String getNodeName(final int node) {
          if (node == DTM.NULL) {
              return "";
          }
          return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeName(node);
      }
  
      public String getNodeNameX(final int node) {
          if (node == DTM.NULL) {
              return "";
          }
          return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeNameX(node);
      }
  
      public String getNamespaceName(final int node) {
          if (node == DTM.NULL) {
              return "";
          }
          return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getNamespaceName(node);
      }
  
      public String getStringValueX(final int node) {
          if (node == DTM.NULL) {
              return "";
          }
          return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getStringValueX(node);
      }
  
      public void copy(final int node, SerializationHandler handler)
          throws TransletException
      {
          if (node != DTM.NULL) {
              _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].copy(node, handler);
          }
      }
  
      public void copy(DTMAxisIterator nodes, SerializationHandler handler)
              throws TransletException
      {
          int node;
          while ((node = nodes.next()) != DTM.NULL) {
              _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].copy(node, handler);
          }
      }
  
  
      public String shallowCopy(final int node, SerializationHandler handler)
              throws TransletException
      {
          if (node == DTM.NULL) {
              return "";
          }
          return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].shallowCopy(node, handler);
      }
  
      public boolean lessThan(final int node1, final int node2) {
          if (node1 == DTM.NULL) {
              return true;
          }
          if (node2 == DTM.NULL) {
              return false;
          }
          final int dom1 = getDTMId(node1);
          final int dom2 = getDTMId(node2);
          return dom1 == dom2 ? _adapters[dom1].lessThan(node1, node2)
                              : dom1 < dom2;
      }
  
      public void characters(final int textNode, SerializationHandler handler)
                   throws TransletException
      {
          if (textNode != DTM.NULL) {
              _adapters[textNode >>> DTMManager.IDENT_DTM_NODE_BITS].characters(textNode, handler);
          }
      }
  
      public void setFilter(StripFilter filter) {
          for (int dom=0; dom<_free; dom++) {
              if (_adapters[dom] != null) {
                  _adapters[dom].setFilter(filter);
              }
          }
      }
  
      public Node makeNode(int index) {
          if (index == DTM.NULL) {
              return null;
          }
          return _adapters[getDTMId(index)].makeNode(index);
      }
  
      public Node makeNode(DTMAxisIterator iter) {
          // TODO: gather nodes from all DOMs ?
          return _main.makeNode(iter);
      }
  
      public NodeList makeNodeList(int index) {
          if (index == DTM.NULL) {
              return null;
          }
          return _adapters[getDTMId(index)].makeNodeList(index);
      }
  
      public NodeList makeNodeList(DTMAxisIterator iter) {
          // TODO: gather nodes from all DOMs ?
          return _main.makeNodeList(iter);
      }
  
      public String getLanguage(int node) {
          return _adapters[getDTMId(node)].getLanguage(node);
      }
  
      public int getSize() {
          int size = 0;
          for (int i=0; i<_size; i++) {
              size += _adapters[i].getSize();
          }
          return(size);
      }
  
      public String getDocumentURI(int node) {
          if (node == DTM.NULL) {
              node = DOM.NULL;
          }
          return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getDocumentURI(0);
      }
  
      public boolean isElement(final int node) {
          if (node == DTM.NULL) {
              return false;
          }
          return(_adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].isElement(node));
      }
  
      public boolean isAttribute(final int node) {
          if (node == DTM.NULL) {
              return false;
          }
          return(_adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].isAttribute(node));
      }
  
      public int getDTMId(int nodeHandle)
      {
          if (nodeHandle == DTM.NULL)
              return 0;
  
          int id = nodeHandle >>> DTMManager.IDENT_DTM_NODE_BITS;
          while (id >= 2 && _adapters[id] == _adapters[id-1]) {
              id--;
          }
          return id;
      }
  
      public DOM getDTM(int nodeHandle) {
          return _adapters[getDTMId(nodeHandle)];
      }
  
      public int getNodeIdent(int nodeHandle)
      {
          return _adapters[nodeHandle >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeIdent(nodeHandle);
      }
  
      public int getNodeHandle(int nodeId)
      {
          return _main.getNodeHandle(nodeId);
      }
  
      public DOM getResultTreeFrag(int initSize, int rtfType)
      {
          return _main.getResultTreeFrag(initSize, rtfType);
      }
  
      public DOM getResultTreeFrag(int initSize, int rtfType, boolean addToManager)
      {
          return _main.getResultTreeFrag(initSize, rtfType, addToManager);
      }
  
      public DOM getMain()
      {
          return _main;
      }
  
      /**
       * Returns a DOMBuilder class wrapped in a SAX adapter.
       */
      public SerializationHandler getOutputDomBuilder()
      {
          return _main.getOutputDomBuilder();
      }
  
      public String lookupNamespace(int node, String prefix)
          throws TransletException
      {
          return _main.lookupNamespace(node, prefix);
      }
  
      // %HZ% Does this method make any sense here???
      public String getUnparsedEntityURI(String entity) {
          return _main.getUnparsedEntityURI(entity);
      }
  
      // %HZ% Does this method make any sense here???
      public Hashtable getElementsWithIDs() {
          return _main.getElementsWithIDs();
      }
  }
  