/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/datastore/XContentWrapper.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.datastore;

import com.softwareag.tamino.db.api.objectModel.TNonXMLObject;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import org.apache.slide.content.NodeRevisionContent;
import org.apache.slide.store.tamino.common.XDatastoreException;
import org.apache.slide.store.tamino.datastore.schema.XDoctype;
import org.apache.slide.store.tamino.jdomobjects.SAXParserPool;
import org.apache.slide.util.XException;
import org.apache.xerces.parsers.SAXParser;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * Describes the content from datastores point of view. It is used when an XContent
 * is instantiated from a NodeRevisionContent.
 *
 * @author martin.wallmer@softwareag.com
 * @version $Revision: 1.4 $
 */
public class XContentWrapper {
    
    //private TXMLObject  xmlObject;
    private boolean     isXml;
    private NodeRevisionContent nodeRevisionContent;
    
    private long contentLength;
    
    private String namespaceUri = "";
    
    private String docType;
    
    /**
     * Construct a XContentWrapper object.
     *
     * @param      nrc node revision content
     *
     * @exception  XException data store exception
     *
     */
    public XContentWrapper (NodeRevisionContent nrc) throws XException {
        nodeRevisionContent = nrc;
        
        byte [] buf = nodeRevisionContent.getContentBytes();
        
        contentLength = buf.length;
        if (contentLength == 0) {
            isXml = false;
        }
        else
        {
            try {
                isXml = true;
                
                InputSource inSource = new InputSource (new ByteArrayInputStream (buf));
                initialize (inSource);
                //                xmlObject = TXMLObject.newInstance (nrc.streamContent());
            }
            catch (com.softwareag.common.instrumentation.contract.ViolatedPrecondition e) {
                isXml = false;
            }
            catch (Exception e) {
                // e.printStackTrace();
                isXml = false;
            }
        }
    }
    
    /**
     *  For REPAIR TOOL only !!!
     */
    public XContentWrapper (NodeRevisionContent nrc, String docType,boolean isXml) throws XException {
        this(nrc);
        this.docType = docType;
        this.isXml = isXml;
    }
    
    /**
     * returns the doctype (schema) of this object.
     *
     * @return     the doctype
     *
     * @exception  IllegalStateException if object is nonXML
     *
     */
    String getDoctype () {
        if (!isXml)
            throw new IllegalStateException ("Object is nonXML, assumed XML");
        
        return docType;
    }
    
    
    /**
     * should be similar to getDoctype, Tamino object should read that.
     *
     * @return   a String
     *
     */
    private String getNamespaceUri () {
        return namespaceUri;
    }
    
    /**
     * returns an XDoctype with the namespaceURI and prefix, as stated in the
     * document.
     *
     * @return   a XDoctype
     *
     */
    public XDoctype getWeakDoctype () {
        return new XDoctype (getDoctype(), getNamespaceUri());
    }
    
    /**
     * called during construction for XML objects. A parser is instantiated, the
     * first element is parsed to get the namespaceURI.
     * This should be a functionality of TXMLObject!
     *
     * @param    inSource            an InputSource
     *
     * @return   a String
     *
     * @throws   XException
     *
     */
    private void initialize (InputSource inSource)
        throws XException, SAXException, IOException
    {
        NameSpaceContentHandler ch = new NameSpaceContentHandler();
        SAXParser parser;
        parser = SAXParserPool.getParser(ch);
        try {
            parser.parse (inSource);
        }
        
        catch (SAXException e) {
            if (! (e instanceof RootAlreadyParsedException)) {
                e.fillInStackTrace();
                throw e;
            }
        }
        finally {
            SAXParserPool.returnParser(parser);
        }
    }
    
    /**
     * Indicates, if this object is XML or not.
     *
     * @return     true, if object is XML, else false
     */
    public boolean isXml () {
        return isXml;
    }
    
    /**
     * Accessor method for the TXMLObject.
     *
     * @return     the TNonXMLObject
     *
     * @exception  IllegalStateException if object is nonXML
     *
     */
    public TNonXMLObject getXMLObject () throws XDatastoreException {
        if (!isXml)
            throw new IllegalStateException ("Object is nonXML, assumed XML");
        
        return getNonXMLObject (docType, "text/xml");
    }
    
    /**
     * returns the content length. Uses the internal buffersize.
     *
     * @return     the content length
     */
    public long getContentLength () {
        return contentLength;
    }
    
    /**
     * indicates an empty content
     *
     * @return     true if content has lenght zero
     */
    public boolean isEmptyContent () {
        if (contentLength == 0)
            return true;
        else
            return false;
    }
    
    /**
     * Returns the TNonXMLObject for this object.
     *
     * @param      contentType the contentType
     *
     * @return     the TXMLObject
     * @exception  XDatastoreException  datastore error
     */
    public TNonXMLObject getNonXMLObject (String contentType) throws XDatastoreException {
        return getNonXMLObject(XDbSession.NONXML_CONTENT, contentType);
    }
    
    
    
    /**
     * Returns the TNonXMLObject for this object (which might be an XML object).
     *
     * @param      contentType the contentType
     *
     * @return     the TXMLObject
     * @exception  XDatastoreException  datastore error
     */
    TNonXMLObject getNonXMLObject (String schema, String contentType) throws XDatastoreException {
        try {
            return TNonXMLObject.newInstance (nodeRevisionContent.streamContent(),
                                              null,                     // collection
                                              schema,
                                              null,                     // docname
                                              contentType);
            
        }
        catch (Exception e) {
            throw new XDatastoreException (e);
        }
    }
    
    
    /**
     * SAX event handler. Reads the root element to determine the namespace URI.
     */
    class NameSpaceContentHandler extends DefaultHandler {
        
        private boolean rootRead = false;
        
        /**
         * Called when an open element tag event is thrown. When called the second
         * time, RootAlreadyParsedException is thrown
         *
         * @param    namespaceURI        a  String
         * @param    localName           a  String
         * @param    qName               a  String
         * @param    atts                an Attributes
         *
         * @throws   SAXException
         *
         */
        public void startElement (String namespaceURI,
                                  String localName,
                                  String qName,
                                  Attributes atts)
            throws SAXException
        {
            if (rootRead)
                throw new RootAlreadyParsedException ();
            
            rootRead = true;
            namespaceUri = namespaceURI;
            docType = localName;
            
        }
    }
}
/**
 * Thrown, when the root element was already parsed and a second element is
 * to be parsed.
 */
class RootAlreadyParsedException extends SAXException {
    RootAlreadyParsedException () {
        super ("");
    }
}

