/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/common/XContent.java,v 1.4 2004/12/15 10:38:26 pnever Exp $
 * $Revision: 1.4 $
 * $Date: 2004/12/15 10:38:26 $
 *
 * ====================================================================
 *
 * Copyright 1999-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.apache.slide.store.tamino.common;

import com.softwareag.common.instrumentation.logging.Level;
import com.softwareag.common.instrumentation.logging.Logger;
import com.softwareag.common.instrumentation.logging.LoggerFactory;
import com.softwareag.common.instrumentation.logging.LoggerUtil;
import java.io.InputStream;
import org.apache.slide.content.NodeRevisionContent;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.store.tamino.datastore.XContentId;
import org.apache.slide.store.tamino.datastore.XContentWrapper;
import org.apache.slide.util.ClassName;
import org.apache.slide.util.XException;


/**
 * <p>IContent represents the content of the resource. It provides methods for setting
 * and retrieving the content (NodeRevisionContent) as well as methods about the kind
 * of the object (XML or non-XML). From the point of view of Slide, one IContent object
 * is uniquely identified by a URI and a RevisionDescriptor. IDbSession uses a String
 * to identify  the physical location of the content. This would be somehow the ino:id.
 * This contentId must be stored within the correlated RevisionDescriptor object as a
 * live property.</p>
 * @author    martin.wallmer@softwareag.com
 *
 * @version   $Revision: 1.4 $
 */
public class XContent implements IContent {
    
    private static final String LOGNAME = LoggerUtil.getThisClassName();
    private static final String CLASSNAME = new ClassName(LOGNAME).getPlainName();
    private static Logger logger = LoggerFactory.getLogger(LOGNAME);
    
    /** the wrapped content */
    private NodeRevisionContent nodeRevisionContent;
    
    /** the descriptor for this content */
    private NodeRevisionDescriptor nodeRevisionDescriptor;
    
    // the intermediate buffer //
    //private byte [] contentBytesBuffer;
    
    /** with this string the content can be identified within the datastore */
    private String contentId;
    
    /** the content length */
    private long contentLength;
    
    /** indicates, if this content is stored as XML in Tamino */
    private boolean isXml;
    
    /** wraps the content, if instantiated from a nodeRevisionContentObject */
    private XContentWrapper contentWrapper;
    
    /**
     * Constructs an XContent object.
     *
     * @pre        (nrc != null)
     *
     * @param      nrc  node revision content
     * @param      nrd  node revision descriptor
     * @exception  XException  xdav error
     */
    public XContent (NodeRevisionContent nrc, NodeRevisionDescriptor nrd) throws XException {
        if (logger.isLoggable (Level.FINE))
            logger.entering (CLASSNAME, "<init>", new Object[] {nrc});
        
        setContent (nrc);
        nodeRevisionDescriptor = nrd;
        
        if (logger.isLoggable(Level.FINE))
            logger.exiting (CLASSNAME, "<init>");
    }
    
    /**
     * Constructs an XContent object using a byte array.
     * Used if instantiated after read from datastore.
     *
     * @pre        (cb != null)
     *
     * @param      cb content bytes retrieved from datastore
     */
    public XContent (byte[] cb) {
        nodeRevisionContent = new NodeRevisionContent ();
        nodeRevisionContent.setContent (cb);
    }
    
    /**
     * Constructs an XContent object using an InputStream.
     * Used if instantiated after read from datastore.
     *
     * @pre        (is != null)
     *
     * @param      is input stream retrieved from datastore
     */
    public XContent (InputStream is) {
        nodeRevisionContent = new NodeRevisionContent ();
        nodeRevisionContent.setContent (is);
    }
    
    /**
     * nodeRevisionContent accessor.
     *
     * @return     the NodeRevisionContent object represented by this Content object
     */
    public NodeRevisionContent getContent () {
        return nodeRevisionContent;
    }
    
    
    /**
     * Set content.
     * @param nrc   node revision content
     * @exception   XException  xdav exception
     */
    public void setContent (NodeRevisionContent nrc) throws XException {
        
        contentWrapper = new XContentWrapper (nrc);
        nodeRevisionContent = nrc;
    }
    
    /**
     * <p>Returns the tamino schema, in which the content shall be stored. The return
     * value gives a hint, whether the content is XML or non-XML data: </p>
     * If the return value is
     * <ul>
     *  <li> null, the data is definitly non-XML data. </li>
     *  <li> not null, the data may be valid XML. There is no guarantee, that the
     *      schema exists in tamino </li>
     * </ul>
     *
     * @return     the schema for this content object or null.
     * @exception  XException  xdav error
     * @deprecated use TXMLObject to retrieve doctype information
     */
    public String getSchema () throws XException {
        if (logger.isLoggable (Level.FINE))
            logger.entering (CLASSNAME, "getSchema");
        String result = null;
        
        // first approach: make a jdom document and retrieve the root element
        // perhaps faster solution: parse and stop after root element
//      try {
//          is = nodeRevisionContent.streamContent();
//          doc = new SAXBuilder(false).build (is);
//          Element root = doc.getRootElement();
//          result = root.getName();
//      }
//      catch (IOException e) {
//          if (logger.isLoggable (Level.FINE)) logger.fine (e.getMessage());
//          throw new XException (e);
//      }
//      catch (JDOMException e) {
//          if (logger.isLoggable (Level.FINE)) {
//              logger.fine (e.getMessage());
//              // logger.fine (new String (nodeRevisionContent.getContent()));
//          }
//
//          result = null;
//      }
        
        
        
        // second approach: use the root element detection of Tammino API
        // perhaps faster solution: do own parse and stop after root element
        
        if (contentWrapper.isXml()) {
            result = contentWrapper.getXMLObject().getDoctype();
        }
        
        
        if (logger.isLoggable(Level.FINE))
            logger.exiting (CLASSNAME, "getSchema", result);
        return result;
    }
    /**
     * length accessor.
     *
     * @return     the length of the content
     */
    public long getLength() {
        if (logger.isLoggable (Level.FINE))
            logger.entering (CLASSNAME, "getLength");
        
        if( contentLength == 0 ) {
            setLength( nodeRevisionContent.getContentBytes().length );
        }
        
        if (logger.isLoggable(Level.FINE))
            logger.exiting (CLASSNAME, "getLength", new Long (contentLength));
        return contentLength;
    }
    
    /**
     * Set length.
     * @param length length
     */
    public void setLength (long length) {
        if (logger.isLoggable (Level.FINE))
            logger.entering (CLASSNAME, "setLength", new Object[] {new Long (length)});
        
        contentLength = length;
        
        if (logger.isLoggable(Level.FINE))
            logger.exiting (CLASSNAME, "setLength");
    }
    
    //  /**
    //   * set length. use the internal buffer size
    //   */
    //    public void setLength () {
    //        if (logger.isLoggable (Level.FINE))
    //            logger.entering (CLASSNAME, "setLength");
//
    //        if (contentBuffer == null)
    //            contentBuffer = nodeRevisionContent.getContent();
//
    //        setLength (contentBuffer.length);
//
    //        if (logger.isLoggable(Level.FINE))
    //            logger.exiting (CLASSNAME, "setLength");
    //    }
//
    
    /**
     * contentId accessor. With the contentId DbSession is able to find the content.
     *
     * @return     the contentId
     */
    public String getContentId () {
        if (logger.isLoggable (Level.FINE))
            logger.entering (CLASSNAME, "getContentId");
        
        if (logger.isLoggable(Level.FINE))
            logger.exiting (CLASSNAME, "getContentId", contentId);
        
        return contentId;
    }
    
    /**
     * contentId mutator
     *
     * @pre        (id != null)
     *
     * @param      id  the content id of this content object
     */
    public void setContentId (String id) {
        if (logger.isLoggable (Level.FINE))
            logger.entering (CLASSNAME, "setContentId", new Object[] {id});
        
        contentId = id;
        isXml = new XContentId(id).isXml();
        
        if (logger.isLoggable(Level.FINE))
            logger.exiting (CLASSNAME, "setContentId");
        
    }
    
    /**
     * retrieves the content as InputStream.
     *
     * @return     the InputStream representing the content
     *
     * @exception  XException when underlying service reports an error
     */
    public InputStream streamContent () throws XException {
        if (logger.isLoggable (Level.FINE))
            logger.entering (CLASSNAME, "streamContent");
        
        InputStream result;
        try {
            result = nodeRevisionContent.streamContent();
        }
        catch (Exception e) {
            throw new XException (e);
        }
        
        if (logger.isLoggable(Level.FINE))
            logger.exiting (CLASSNAME, "streamContent", result);
        
        return result;
    }
    
    /**
     * Retrieves the unique name for this content. Consists of uri and revision.
     *
     * @return     the unique name for this content
     *
     */
    public String getRevisionName () {
        return
            new StringBuffer (nodeRevisionDescriptor.getName())
            .append ('_')
            .append (nodeRevisionDescriptor.getRevisionNumber().toString()).toString();
    }
    
    /**
     * Retrieves the MIME type of this content.
     *
     * @return     the unique name for this content
     *
     */
    public String getDocumentType () {
        return nodeRevisionDescriptor.getContentType();
    }
    
    
    /**
     * Returns the ContentWrapper. Used by datastore.
     *
     * @pre        true
     * @post       true
     *
     * @return     The content wrapper.
     *
     */
    public XContentWrapper getContentWrapper () {
        return contentWrapper;
    }
    
    /**
     * Test for empty content.
     * @return true, if content is empty, false otherwise
     */
    public boolean isEmptyContent () {
        if (contentWrapper.isEmptyContent ())
            return true;
        else
            return false;
    }
    
    /**
     *  Buffer the content so that this object can be cached.
     * @return the content as byte array
     */
    public byte[] bufferContent() {
        return nodeRevisionContent.getContentBytes();
    }
    
    /**
     * Returns "XContent".
     * @return "XContent"
     */
    public String toString () {
        String result = "XContent";
        
        //        XMLOutputter out = new XMLOutputter("  ", true);
//
        //        try {
        //            Reader reader = new CharArrayReader (nodeRevisionContent.getContent());
        //            Document doc = new SAXBuilder(false).build (reader);
        //            Element root = doc.getRootElement();
//
        //            result = out.outputString (doc);
        //        }
        //        catch (IOException e) {
        //            result = "IOException: " + e.getMessage();
        //        }
        //        catch (JDOMException e) {
        //            result = "NON XML: " + e.getMessage();
        //        }
        return result;
    }
    
    
    /**
     * Method getIsXml
     *
     * @return   a boolean
     *
     */
    public boolean getIsXml() {
        return isXml;
    }
    
    /**
     * Method setIsXml
     *
     * @param    isXml               a  boolean
     *
     */
    public void setIsXml (boolean isXml) {
        this.isXml = isXml;
    }
}

