/*
 * Copyright 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 org.jboss.axis.message;

import org.w3c.dom.DOMException;
import org.w3c.dom.Text;

/**
 * A representation of a node whose value is text. A <CODE>
 * Text</CODE> object may represent text that is content or text
 * that is a comment.
 *
 * @author Davanum Srinivas (dims@yahoo.com)
 * @author Heejune Ahn      (cityboy@tmax.co.kr)
 * @author Thomas Diesler   (thomas.diesler@jboss.org)
 */
public class TextImpl extends NodeImpl implements javax.xml.soap.Text
{

   public TextImpl(org.w3c.dom.Node node)
   {
      super(node);
   }

   /**
    * Retrieves whether this object represents a comment.
    */
   public boolean isComment()
   {
      String value = getNodeValue().trim();
      return value.startsWith("<!--") && value.endsWith("-->");
   }

   public String getValue()
   {
      return getNodeValue();
   }

   public void setValue(String value)
   {
      setNodeValue(value);
   }

   /**
    * Breaks this node into two nodes at the specified <code>offset</code>, keeping both in the tree as siblings.
    * <p/>
    * After being split, this node will contain all the content up to the <code>offset</code> point. A
    * new node of the same type, which contains all the content at and after the <code>offset</code> point, is returned.
    * If the original node had a parent node, the new node is inserted as the next sibling of the original node.
    * When the <code>offset</code> is equal to the length of this node, the new node has no data.
    *
    * @param offset The 16-bit unit offset at which to split, starting from <code>0</code>.
    * @return The new node, of the same type as this node.
    * @throws DOMException INDEX_SIZE_ERR: Raised if the specified offset is negative or greater
    *                      than the number of 16-bit units in <code>data</code>.
    *                      <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
    */
   public org.w3c.dom.Text splitText(int offset) throws DOMException
   {

      if (offset < 0 || offset > getNodeValue().length())
         throw new IllegalArgumentException("Invalid offset [" + offset + "] for '" + getNodeValue() + "'");

      String before = getNodeValue().substring(0, offset + 1);
      setNodeValue(before);

      String after = getNodeValue().substring(offset + 1);
      TextImpl txtNode = new TextImpl(domNode.getOwnerDocument().createTextNode(after));

      org.w3c.dom.Node parent = getParentNode();
      if (parent != null)
      {
         org.w3c.dom.Node sibling = getNextSibling();
         if (sibling == null)
            parent.appendChild(txtNode);
         else
            parent.insertBefore(txtNode, sibling);
      }

      return txtNode;
   }

   // org.w3c.dom.CharacterData ***************************************************************************************

   /**
    * The number of 16-bit units 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 int getLength()
   {
      return getNodeValue().length();
   }

   /**
    * Remove a range of 16-bit units from the node. Upon success,
    * <code>data</code> and <code>length</code> reflect the change.
    *
    * @param offset The offset from which to start removing.
    * @param count  The number of 16-bit units to delete. If the sum of
    *               <code>offset</code> and <code>count</code> exceeds
    *               <code>length</code> then all 16-bit units from <code>offset</code>
    *               to the end of the data are deleted.
    * @throws org.w3c.dom.DOMException INDEX_SIZE_ERR: Raised if the specified <code>offset</code> is
    *                                  negative or greater than the number of 16-bit units 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 void deleteData(int offset, int count) throws DOMException
   {
      String value = getNodeValue().substring(0, offset + 1);
      setNodeValue(value);
   }

   /**
    * 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.
    *
    * @throws org.w3c.dom.DOMException NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
    * @throws org.w3c.dom.DOMException DOMSTRING_SIZE_ERR: Raised when it would return more characters than
    *                                  fit in a <code>DOMString</code> variable on the implementation
    *                                  platform.
    */
   public String getData() throws DOMException
   {
      return getNodeValue();
   }

   /**
    * Extracts a range of data from the node.
    *
    * @param offset Start offset of substring to extract.
    * @param count  The number of 16-bit units to extract.
    * @return The specified substring. If the sum of <code>offset</code> and
    *         <code>count</code> exceeds the <code>length</code>, then all 16-bit
    *         units to the end of the data are returned.
    * @throws org.w3c.dom.DOMException INDEX_SIZE_ERR: Raised if the specified <code>offset</code> is
    *                                  negative or greater than the number of 16-bit units 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 String substringData(int offset, int count) throws DOMException
   {
      return getNodeValue().substring(offset, offset + count);
   }

   /**
    * Replace the characters starting at the specified 16-bit unit offset
    * with the specified string.
    *
    * @param offset The offset from which to start replacing.
    * @param count  The number of 16-bit units to replace. If the sum of
    *               <code>offset</code> and <code>count</code> exceeds
    *               <code>length</code>, then all 16-bit units 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.
    * @throws org.w3c.dom.DOMException INDEX_SIZE_ERR: Raised if the specified <code>offset</code> is
    *                                  negative or greater than the number of 16-bit units 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 void replaceData(int offset, int count, String arg) throws DOMException
   {
      StringBuffer buffer = new StringBuffer(getNodeValue());
      buffer.replace(offset, offset + count, arg);
      setNodeValue(buffer.toString());
   }

   /**
    * Insert a string at the specified 16-bit unit offset.
    *
    * @param offset The character offset at which to insert.
    * @param arg    The <code>DOMString</code> to insert.
    * @throws org.w3c.dom.DOMException INDEX_SIZE_ERR: Raised if the specified <code>offset</code> is
    *                                  negative or greater than the number of 16-bit units in
    *                                  <code>data</code>.
    *                                  <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
    */
   public void insertData(int offset, String arg) throws DOMException
   {
      StringBuffer buffer = new StringBuffer(getNodeValue());
      buffer.insert(offset, arg);
      setNodeValue(buffer.toString());
   }

   /**
    * 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.
    * @throws org.w3c.dom.DOMException NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
    */
   public void appendData(String arg) throws DOMException
   {
      setNodeValue(getNodeValue() + arg);
   }

   /**
    * 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.
    *
    * @throws org.w3c.dom.DOMException NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
    * @throws org.w3c.dom.DOMException DOMSTRING_SIZE_ERR: Raised when it would return more characters than
    *                                  fit in a <code>DOMString</code> variable on the implementation
    *                                  platform.
    */
   public void setData(String data) throws DOMException
   {
      setNodeValue(data);
   }
   
   // Stubbed out org.w3c.dom.Text methods **************************

   /**
    * TODO - complete the implementation
    * 
    * Returns whether this text node contains <a href='http://www.w3.org/TR/2004/REC-xml-infoset-20040204#infoitem.character'>
    * element content whitespace</a>, often abusively called "ignorable whitespace". The text node is 
    * determined to contain whitespace in element content during the load 
    * of the document or if validation occurs while using 
    * <code>Document.normalizeDocument()</code>.
    * @since DOM Level 3
    */
   public boolean isElementContentWhitespace()
   {
      return false;
   }

   /**
    * TODO - complete the implementation
    * 
    * Returns all text of <code>Text</code> nodes logically-adjacent text 
    * nodes to this node, concatenated in document order.
    * <br>For instance, in the example below <code>wholeText</code> on the 
    * <code>Text</code> node that contains "bar" returns "barfoo", while on 
    * the <code>Text</code> node that contains "foo" it returns "barfoo". 
    * @since DOM Level 3
    */
   public String getWholeText()
   {
      return null;
   }

   /**
    * TODO - complete the implementation
    * 
    * Replaces the text of the current node and all logically-adjacent text 
    * nodes with the specified text. All logically-adjacent text nodes are 
    * removed including the current node unless it was the recipient of the 
    * replacement text.
    * <br>This method returns the node which received the replacement text. 
    * The returned node is: 
    * <ul>
    * <li><code>null</code>, when the replacement text is 
    * the empty string;
    * </li>
    * <li>the current node, except when the current node is 
    * read-only;
    * </li>
    * <li> a new <code>Text</code> node of the same type (
    * <code>Text</code> or <code>CDATASection</code>) as the current node 
    * inserted at the location of the replacement.
    * </li>
    * </ul>
    * <br>For instance, in the above example calling 
    * <code>replaceWholeText</code> on the <code>Text</code> node that 
    * contains "bar" with "yo" in argument results in the following: 
    * <br>Where the nodes to be removed are read-only descendants of an 
    * <code>EntityReference</code>, the <code>EntityReference</code> must 
    * be removed instead of the read-only nodes. If any 
    * <code>EntityReference</code> to be removed has descendants that are 
    * not <code>EntityReference</code>, <code>Text</code>, or 
    * <code>CDATASection</code> nodes, the <code>replaceWholeText</code> 
    * method must fail before performing any modification of the document, 
    * raising a <code>DOMException</code> with the code 
    * <code>NO_MODIFICATION_ALLOWED_ERR</code>.
    * <br>For instance, in the example below calling 
    * <code>replaceWholeText</code> on the <code>Text</code> node that 
    * contains "bar" fails, because the <code>EntityReference</code> node 
    * "ent" contains an <code>Element</code> node which cannot be removed.
    * @param content The content of the replacing <code>Text</code> node.
    * @return The <code>Text</code> node created with the specified content.
    * @exception DOMException
    *   NO_MODIFICATION_ALLOWED_ERR: Raised if one of the <code>Text</code> 
    *   nodes being replaced is readonly.
    * @since DOM Level 3
    */
   public Text replaceWholeText(String content)
           throws DOMException
   {
      return null;
   }

}