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 2005 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.xpointer;
  
  import jaxp.sun.org.apache.xerces.internal.impl.Constants;
  import jaxp.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
  import jaxp.sun.org.apache.xerces.internal.util.SymbolTable;
  import jaxp.sun.org.apache.xerces.internal.xni.Augmentations;
  import jaxp.sun.org.apache.xerces.internal.xni.QName;
  import jaxp.sun.org.apache.xerces.internal.xni.XMLAttributes;
  import jaxp.sun.org.apache.xerces.internal.xni.XNIException;
  import jaxp.sun.org.apache.xerces.internal.xs.AttributePSVI;
  import jaxp.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
  
  /**
   * <p>
   * Implements the XPointerPart interface and handles processing of
   * ShortHand Pointers.  It identifies at most one element in the
   * resource's information set; specifically, the first one (if any)
   * in document order that has a matching NCName as an identifier.
   * </p>
   *
   *
   */
  class ShortHandPointer implements XPointerPart {
  
      // The name of the ShortHand pointer
      private String fShortHandPointer;
  
      // The name of the ShortHand pointer
      private boolean fIsFragmentResolved = false;
  
      // SymbolTable
      private SymbolTable fSymbolTable;
  
      //
      // Constructors
      //
      public ShortHandPointer() {
      }
  
      public ShortHandPointer(SymbolTable symbolTable) {
          fSymbolTable = symbolTable;
      }
  
      /**
       * The XPointerProcessor takes care of this.  Simply set the ShortHand Pointer here.
       *
       * @see XPointerPart#parseXPointer(java.lang.String)
       */
      public void parseXPointer(String part) throws XNIException {
          fShortHandPointer = part;
          // reset fIsFragmentResolved
          fIsFragmentResolved = false;
      }
  
      /**
       * Resolves the XPointer ShortHand pointer based on the rules defined in
       * Section 3.2 of the XPointer Framework Recommendation.
       * Note that in the current implementation only supports DTD determined ID's.
       *
       * @see XPointerPart#resolveXPointer(QName, XMLAttributes, Augmentations, int event)
       */
      int fMatchingChildCount = 0;
      public boolean resolveXPointer(QName element, XMLAttributes attributes,
              Augmentations augs, int event) throws XNIException {
  
          // reset fIsFragmentResolved
          if (fMatchingChildCount == 0) {
              fIsFragmentResolved = false;
          }
  
          // On startElement or emptyElement, if no matching elements or parent
          // elements were found, check for a matching idenfitier.
          if (event == XPointerPart.EVENT_ELEMENT_START) {
              if (fMatchingChildCount == 0) {
                  fIsFragmentResolved = hasMatchingIdentifier(element, attributes, augs,
                      event);
              }
              if (fIsFragmentResolved) {
                 fMatchingChildCount++;
              }
          } else if (event == XPointerPart.EVENT_ELEMENT_EMPTY) {
              if (fMatchingChildCount == 0) {
                  fIsFragmentResolved = hasMatchingIdentifier(element, attributes, augs,
                      event);
              }
          }
          else {
              // On endElement, decrease the matching child count if the child or
              // its parent was resolved.
              if (fIsFragmentResolved) {
                  fMatchingChildCount--;
              }
          }
  
          return fIsFragmentResolved ;
      }
  
      /**
       *
       * @param element
       * @param attributes
       * @param augs
       * @param event
       * @return
       * @throws XNIException
       */
      private boolean hasMatchingIdentifier(QName element,
              XMLAttributes attributes, Augmentations augs, int event)
      throws XNIException {
          String normalizedValue = null;
  
          // The identifiers of an element are determined by the
          // ShortHand Pointer as follows:
  
          if (attributes != null) {
              for (int i = 0; i < attributes.getLength(); i++) {
  
                  // 1. If an element information item has an attribute information item
                  // among its [attributes] that is a schema-determined ID, then it is
                  // identified by the value of that attribute information item's
                  // [schema normalized value] property;
                  normalizedValue = getSchemaDeterminedID(attributes, i);
                  if (normalizedValue != null) {
                      break;
                  }
  
                  // 2. If an element information item has an element information item among
                  // its [children] that is a schema-determined ID, then it is identified by
                  // the value of that element information item's [schema normalized value] property;
                  // ???
                  normalizedValue = getChildrenSchemaDeterminedID(attributes, i);
                  if (normalizedValue != null) {
                      break;
                  }
  
                  // 3. If an element information item has an attribute information item among
                  // its [attributes] that is a DTD-determined ID, then it is identified by the
                  // value of that attribute information item's [normalized value] property.
                  // An attribute information item is a DTD-determined ID if and only if it has
                  // a [type definition] property whose value is equal to ID.
                  normalizedValue = getDTDDeterminedID(attributes, i);
                  if (normalizedValue != null) {
                      break;
                  }
                  // 4. No externally determined ID's
              }
          }
  
          if (normalizedValue != null
                  && normalizedValue.equals(fShortHandPointer)) {
              return true;
          }
  
          return false;
      }
  
      /**
       * Rerturns the DTD determine-ID
       *
       * @param attributes
       * @param index
       * @return String
       * @throws XNIException
       */
      public String getDTDDeterminedID(XMLAttributes attributes, int index)
      throws XNIException {
  
          if (attributes.getType(index).equals("ID")) {
              return attributes.getValue(index);
          }
          return null;
      }
  
      /**
       * Returns the schema-determined-ID.
       *
       *
       * @param attributes
       * @param index
       * @return A String containing the schema-determined ID.
       * @throws XNIException
       */
      public String getSchemaDeterminedID(XMLAttributes attributes, int index)
      throws XNIException {
          Augmentations augs = attributes.getAugmentations(index);
          AttributePSVI attrPSVI = (AttributePSVI) augs
          .getItem(Constants.ATTRIBUTE_PSVI);
  
          if (attrPSVI != null) {
              // An element or attribute information item is a schema-determined
              // ID if and only if one of the following is true:]
  
              // 1. It has a [member type definition] or [type definition] property
              // whose value in turn has [name] equal to ID and [target namespace]
              // equal to http://www.w3.org/2001/XMLSchema;
  
              // 2. It has a [base type definition] whose value has that [name] and [target namespace];
  
              // 3. It has a [base type definition] whose value has a [base type definition]
              // whose value has that [name] and [target namespace], and so on following
              // the [base type definition] property recursively;
  
              XSTypeDefinition typeDef = attrPSVI.getMemberTypeDefinition();
              if (typeDef != null) {
                  typeDef = attrPSVI.getTypeDefinition();
              }
  
              //
              if (typeDef != null && ((XSSimpleType) typeDef).isIDType()) {
                  return attrPSVI.getSchemaNormalizedValue();
              }
  
              // 4 & 5 NA
          }
  
          return null;
      }
  
      /**
       * Not quite sure how this can be correctly implemented.
       *
       * @param attributes
       * @param index
       * @return String - We return null since we currenly do not supprt this.
       * @throws XNIException
       */
      public String getChildrenSchemaDeterminedID(XMLAttributes attributes,
              int index) throws XNIException {
          return null;
      }
  
      /**
       *
       * @see XPointerPart#isFragmentResolved()
       */
      public boolean isFragmentResolved() {
          return fIsFragmentResolved;
      }
  
      /**
       *
       * @see XPointerPart#isChildFragmentResolved()
       */
      public boolean isChildFragmentResolved() {
          return fIsFragmentResolved & ( fMatchingChildCount >  0);
      }
  
      /**
       * Returns the name of the ShortHand pointer
       *
       * @see XPointerPart#getSchemeName()
       */
      public String getSchemeName() {
          return fShortHandPointer;
      }
  
      /**
       * @see XPointerPart#getSchemeData()
       */
      public String getSchemeData() {
          return null;
      }
  
      /**
       * @see XPointerPart#setSchemeName(java.lang.String)
       */
      public void setSchemeName(String schemeName) {
          fShortHandPointer = schemeName;
      }
  
      /**
       * @see XPointerPart#setSchemeData(java.lang.String)
       */
      public void setSchemeData(String schemeData) {
          // NA
      }
  }
  