content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You 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 mf.org.apache.xerces.dom;
  
  import mf.org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl;
  import mf.org.apache.xerces.xni.NamespaceContext;
  import mf.org.w3c.dom.DOMException;
  
  
  /**
   * AttrNSImpl inherits from AttrImpl and adds namespace support.
   * <p/>
   * The qualified name is the node name, and we store localName which is also
   * used in all queries. On the other hand we recompute the prefix when
   * necessary.
   *
   * @author Arnaud  Le Hors, IBM
   * @author Andy Clark, IBM
   * @author Ralf Pfeiffer, IBM
   * @version $Id: AttrNSImpl.java 924245 2010-03-17 11:58:14Z mrglavas $
   * @xerces.internal
   */
  public class AttrNSImpl
          extends AttrImpl {
  
      //
      // Constants
      //
  
      /**
       * Serialization version.
       */
      static final long serialVersionUID = -781906615369795414L;
  
      static final String xmlnsURI = "http://www.w3.org/2000/xmlns/";
      static final String xmlURI = "http://www.w3.org/XML/1998/namespace";
  
      //
      // Data
      //
  
      /**
       * DOM2: Namespace URI.
       */
      protected String namespaceURI;
  
      /**
       * DOM2: localName.
       */
      protected String localName;
  
      /*
       * Default constructor
       */
      public AttrNSImpl() {
      }
  
      /**
       * DOM2: Constructor for Namespace implementation.
       */
      protected AttrNSImpl(CoreDocumentImpl ownerDocument,
                           String namespaceURI,
                           String qualifiedName) {
  
          super(ownerDocument, qualifiedName);
          setName(namespaceURI, qualifiedName);
      }
  
      // when local name is known
      public AttrNSImpl(CoreDocumentImpl ownerDocument,
                        String namespaceURI,
                        String qualifiedName,
                        String localName) {
          super(ownerDocument, qualifiedName);
  
          this.localName = localName;
          this.namespaceURI = namespaceURI;
      }
  
      // for DeferredAttrImpl
      protected AttrNSImpl(CoreDocumentImpl ownerDocument,
                           String value) {
          super(ownerDocument, value);
      }
  
      private void setName(String namespaceURI, String qname) {
          CoreDocumentImpl ownerDocument = ownerDocument();
          String prefix;
          // DOM Level 3: namespace URI is never empty string.
          this.namespaceURI = namespaceURI;
          if (namespaceURI != null) {
              this.namespaceURI = (namespaceURI.length() == 0) ? null
                      : namespaceURI;
  
          }
          int colon1 = qname.indexOf(':');
          int colon2 = qname.lastIndexOf(':');
          ownerDocument.checkNamespaceWF(qname, colon1, colon2);
          if (colon1 < 0) {
              // there is no prefix
              localName = qname;
              if (ownerDocument.errorChecking) {
                  ownerDocument.checkQName(null, localName);
  
                  if (qname.equals("xmlns") && (namespaceURI == null
                          || !namespaceURI.equals(NamespaceContext.XMLNS_URI))
                          || (namespaceURI != null && namespaceURI.equals(NamespaceContext.XMLNS_URI)
                          && !qname.equals("xmlns"))) {
                      String msg =
                              DOMMessageFormatter.formatMessage(
                                      DOMMessageFormatter.DOM_DOMAIN,
                                      "NAMESPACE_ERR",
                                      null);
                      throw new DOMException(DOMException.NAMESPACE_ERR, msg);
                  }
              }
          } else {
              prefix = qname.substring(0, colon1);
              localName = qname.substring(colon2 + 1);
              ownerDocument.checkQName(prefix, localName);
              ownerDocument.checkDOMNSErr(prefix, namespaceURI);
          }
      }
  
      // Support for DOM Level 3 renameNode method.
      // Note: This only deals with part of the pb. It is expected to be
      // called after the Attr has been detached for one thing.
      // CoreDocumentImpl does all the work.
      void rename(String namespaceURI, String qualifiedName) {
          if (needsSyncData()) {
              synchronizeData();
          }
          this.name = qualifiedName;
          setName(namespaceURI, qualifiedName);
      }
  
      //
      // DOM2: Namespace methods
      //
  
      /**
       * Introduced in DOM Level 2. <p>
       * <p/>
       * The namespace URI of this node, or null if it is unspecified.<p>
       * <p/>
       * This is not a computed value that is the result of a namespace lookup
       * based on an examination of the namespace declarations in scope. It is
       * merely the namespace URI given at creation time.<p>
       * <p/>
       * For nodes created with a DOM Level 1 method, such as createElement
       * from the Document interface, this is null.
       *
       * @since WD-DOM-Level-2-19990923
       */
      @Override
      public String getNamespaceURI() {
          if (needsSyncData()) {
              synchronizeData();
          }
          // REVIST: This code could/should be done at a lower-level, such that
          // the namespaceURI is set properly upon creation. However, there still
          // seems to be some DOM spec interpretation grey-area.
          return namespaceURI;
      }
  
      /**
       * Introduced in DOM Level 2. <p>
       * <p/>
       * The namespace prefix of this node, or null if it is unspecified. <p>
       * <p/>
       * For nodes created with a DOM Level 1 method, such as createElement
       * from the Document interface, this is null. <p>
       *
       * @since WD-DOM-Level-2-19990923
       */
      @Override
      public String getPrefix() {
          if (needsSyncData()) {
              synchronizeData();
          }
          int index = name.indexOf(':');
          return index < 0 ? null : name.substring(0, index);
      }
  
      /**
       * Introduced in DOM Level 2. <p>
       * <p/>
       * Note that setting this attribute changes the nodeName attribute, which
       * holds the qualified name, as well as the tagName and name attributes of
       * the Element and Attr interfaces, when applicable.<p>
       *
       * @param prefix The namespace prefix of this node, or null(empty string) if it is unspecified.
       * @throws INVALID_CHARACTER_ERR Raised if the specified
       *                               prefix contains an invalid character.
       * @throws DOMException
       * @since WD-DOM-Level-2-19990923
       */
      @Override
      public void setPrefix(String prefix)
              throws DOMException {
          if (needsSyncData()) {
              synchronizeData();
          }
          if (ownerDocument().errorChecking) {
              if (isReadOnly()) {
                  String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
                  throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
              }
              if (prefix != null && prefix.length() != 0) {
  
                  if (!CoreDocumentImpl.isXMLName(prefix, ownerDocument().isXML11Version())) {
                      String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
                      throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
                  }
                  if (namespaceURI == null || prefix.indexOf(':') >= 0) {
                      String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null);
                      throw new DOMException(DOMException.NAMESPACE_ERR, msg);
  
                  }
                  if (prefix.equals("xmlns")) {
                      if (!namespaceURI.equals(xmlnsURI)) {
                          String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null);
                          throw new DOMException(DOMException.NAMESPACE_ERR, msg);
                      }
                  } else if (prefix.equals("xml")) {
                      if (!namespaceURI.equals(xmlURI)) {
                          String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null);
                          throw new DOMException(DOMException.NAMESPACE_ERR, msg);
                      }
                  } else if (name.equals("xmlns")) {
                      String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null);
                      throw new DOMException(DOMException.NAMESPACE_ERR, msg);
                  }
              }
          }
  
          // update node name with new qualifiedName
          if (prefix != null && prefix.length() != 0) {
              name = prefix + ":" + localName;
          } else {
              name = localName;
          }
      }
  
      /**
       * Introduced in DOM Level 2. <p>
       * <p/>
       * Returns the local part of the qualified name of this node.
       *
       * @since WD-DOM-Level-2-19990923
       */
      @Override
      public String getLocalName() {
          if (needsSyncData()) {
              synchronizeData();
          }
          return localName;
      }
  
  
      /**
       * @see mf.org.w3c.dom.TypeInfo#getTypeName()
       */
      @Override
      public String getTypeName() {
          if (type != null) {
              if (type instanceof XSSimpleTypeDecl) {
                  return ((XSSimpleTypeDecl) type).getName();
              }
              return (String) type;
          }
          return null;
      }
  
      /**
       * Introduced in DOM Level 3. <p>
       * Checks if a type is derived from another by restriction. See:
       * http://www.w3.org/TR/DOM-Level-3-Core/core.html#TypeInfo-isDerivedFrom
       *
       * @param typeNamespaceArg The namspace of the ancestor type declaration
       * @param typeNameArg      The name of the ancestor type declaration
       * @param derivationMethod The derivation method
       * @return boolean True if the type is derived by restriciton for the
       * reference type
       */
      @Override
      public boolean isDerivedFrom(String typeNamespaceArg,
                                   String typeNameArg,
                                   int derivationMethod) {
          if (type != null) {
              if (type instanceof XSSimpleTypeDecl) {
                  return ((XSSimpleTypeDecl) type).isDOMDerivedFrom(
                          typeNamespaceArg, typeNameArg, derivationMethod);
              }
          }
          return false;
      }
  
      /**
       * @see mf.org.w3c.dom.TypeInfo#getTypeNamespace()
       */
      @Override
      public String getTypeNamespace() {
          if (type != null) {
              if (type instanceof XSSimpleTypeDecl) {
                  return ((XSSimpleTypeDecl) type).getNamespace();
              }
              return DTD_URI;
          }
          return null;
      }
  
  }
  