package org.dbxml.xml.dom;

/*
 * dbXML License, Version 1.0
 *
 *
 * Copyright (c) 1999-2001 The dbXML Group, L.L.C.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by
 *        The dbXML Group (http://www.dbxml.com/)."
 *    Alternately, this acknowledgment may appear in the software
 *    itself, if and wherever such third-party acknowledgments normally
 *    appear.
 *
 * 4. The names "dbXML" and "The dbXML Group" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    info@dbxml.com.
 *
 * 5. Products derived from this software may not be called "dbXML",
 *    nor may "dbXML" appear in their name, without prior written
 *    permission of The dbXML Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE DBXML GROUP OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id: CharacterDataImpl.java,v 1.14 2001/08/05 07:23:15 tom Exp $
 */

import org.dbxml.xml.*;
import org.dbxml.server.util.*;

import org.w3c.dom.*;

/**
 * CharacterDataImpl
 */

public abstract class CharacterDataImpl extends NodeImpl implements CharacterData {
   public CharacterDataImpl() {
   }
   
   public CharacterDataImpl(NodeImpl parentNode, byte[] data, int pos, int len) {
      super(parentNode, data, pos, len);
   }

   public CharacterDataImpl(NodeImpl parentNode, boolean dirty) {
      super(parentNode, dirty);
   }

   public CharacterDataImpl(NodeImpl parentNode, String nodeValue) {
      super(parentNode, true);
      if ( nodeValue == null )
         nodeValue = "";
      this.nodeValue = nodeValue;
   }

   protected final void checkLoaded() {
       if ( loaded )
         return;
      else
         loaded = true;

      try {
         if ( data != null ) {
            DocumentImpl doc = (DocumentImpl)getOwnerDocument();
            SymbolTable st = doc.getSymbols();

            ByteArrayInput bis = new ByteArrayInput(data, pos, len);
            XMLCompressedInput xci = new XMLCompressedInput(bis, st);

            xci.readSignature(); // Skip The Signature
            if ( getNodeType() == TEXT_NODE)
               xci.readContentSize();
            else
               xci.readInt();

            byte[] buf = new byte[bis.available()];
            xci.read(buf);
            nodeValue = new String(buf);
         }
      }
      catch ( Exception e ) {
         org.dbxml.Debug.printStackTrace(e);
      }
   }

   public final void setNodeValue(String nodeValue) throws DOMException {
      checkLoaded();
      checkReadOnly();
      if ( nodeValue == null )
         nodeValue = "";
      this.nodeValue = nodeValue;
      setDirty();
   }

   /**
    * Extracts a range of data from the node.
    * @param offset Start offset of substring to extract.
    * @param count The number of characters to extract.
    * @return The specified substring. If the sum of <code>offset</code> and
    *   <code>count</code> exceeds the <code>length</code>, then all
    *   characters to the end of the data are returned.
    * @exception DOMException
    *   INDEX_SIZE_ERR: Raised if the specified offset is negative or greater
    *   than the number of characters in <code>data</code>, or if the
    *   specified <code>count</code> is negative.
    *   <br>DOMSTRING_SIZE_ERR: Raised if the specified range of text does not
    *   fit into a <code>DOMString</code>.
    */
   public final String substringData(int offset, int count) throws DOMException {
      try {
         return nodeValue.substring(offset, offset+count);
      }
      catch ( Exception e ) {
         throw EX_INDEX_SIZE;
      }
   }

   /**
    * The character data of the node that implements this interface. The DOM
    * implementation may not put arbitrary limits on the amount of data that
    * may be stored in a  <code>CharacterData</code> node. However,
    * implementation limits may  mean that the entirety of a node's data may
    * not fit into a single <code>DOMString</code>. In such cases, the user
    * may call <code>substringData</code> to retrieve the data in
    * appropriately sized pieces.
    * @exception DOMException
    *   NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
    * @exception DOMException
    *   DOMSTRING_SIZE_ERR: Raised when it would return more characters than
    *   fit in a <code>DOMString</code> variable on the implementation
    *   platform.
    */
   public final String getData() throws DOMException {
      return getNodeValue();
   }

   public final void setData(String data) throws DOMException {
      setNodeValue(data);
   }

   /**
    * Insert a string at the specified character offset.
    * @param offset The character offset at which to insert.
    * @param arg The <code>DOMString</code> to insert.
    * @exception DOMException
    *   INDEX_SIZE_ERR: Raised if the specified offset is negative or greater
    *   than the number of characters in <code>data</code>.
    *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
    */
   public final void insertData(int offset, String arg) throws DOMException {
      String value = getNodeValue();
      checkReadOnly();
      try {
         setNodeValue(value.substring(0, offset) + arg + value.substring(offset+1));
      }
      catch ( Exception e ) {
         throw EX_INDEX_SIZE;
      }
   }

   /**
    * The number of characters that are available through <code>data</code> and
    * the <code>substringData</code> method below.  This may have the value
    * zero,  i.e., <code>CharacterData</code> nodes may be empty.
    */
   public final int getLength() {
      return getNodeValue().length();
   }

   /**
    * Replace the characters starting at the specified character offset with
    * the specified string.
    * @param offset The offset from which to start replacing.
    * @param count The number of characters to replace. If the sum of
    *   <code>offset</code> and <code>count</code> exceeds <code>length</code>
    *   , then all characters to the end of the data are replaced (i.e., the
    *   effect is the same as a <code>remove</code> method call with the same
    *   range, followed by an <code>append</code> method invocation).
    * @param arg The <code>DOMString</code> with which the range must be
    *   replaced.
    * @exception DOMException
    *   INDEX_SIZE_ERR: Raised if the specified offset is negative or greater
    *   than the number of characters in <code>data</code>, or if the
    *   specified <code>count</code> is negative.
    *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
    */
   public final void replaceData(int offset, int count, String arg) throws DOMException {
      String value = getNodeValue();
      checkReadOnly();
      try {
         setNodeValue(value.substring(0, offset) + arg + value.substring(offset+count));
      }
      catch ( Exception e ) {
         throw EX_INDEX_SIZE;
      }
   }

   /**
    * Append the string to the end of the character data of the node. Upon
    * success, <code>data</code> provides access to the concatenation of
    * <code>data</code> and the <code>DOMString</code> specified.
    * @param arg The <code>DOMString</code> to append.
    * @exception DOMException
    *   NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
    */
   public final void appendData(String arg) throws DOMException {
      String value = getNodeValue();
      checkReadOnly();
      setNodeValue(value + arg);
   }

   /**
    * Remove a range of characters from the node. Upon success,
    * <code>data</code> and <code>length</code> reflect the change.
    * @param offset The offset from which to remove characters.
    * @param count The number of characters to delete. If the sum of
    *   <code>offset</code> and <code>count</code> exceeds <code>length</code>
    *   then all characters from <code>offset</code> to the end of the data
    *   are deleted.
    * @exception DOMException
    *   INDEX_SIZE_ERR: Raised if the specified offset is negative or greater
    *   than the number of characters in <code>data</code>, or if the
    *   specified <code>count</code> is negative.
    *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
    */
   public final void deleteData(int offset, int count) throws DOMException {
      String value = getNodeValue();
      checkReadOnly();
      try {
         setNodeValue(value.substring(0, offset) + value.substring(offset+count));
      }
      catch ( Exception e ) {
         throw EX_INDEX_SIZE;
      }
   }
}

