/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/datastore/XDescriptorsProcessor.java,v 1.3 2004/07/30 06:51:54 ozeigermann Exp $
 * $Revision: 1.3 $
 * $Date: 2004/07/30 06:51:54 $
 *
 * ====================================================================
 *
 * 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.common.instrumentation.contract.ViolatedPrecondition;
import com.softwareag.tamino.db.api.accessor.TQuery;
import com.softwareag.tamino.db.api.accessor.TStreamAccessor;
import com.softwareag.tamino.db.api.common.TException;
import com.softwareag.tamino.db.api.io.TInputStream;
import com.softwareag.tamino.db.api.objectModel.TDataObject;
import com.softwareag.tamino.db.api.objectModel.TNonXMLObject;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.slide.store.tamino.jdomobjects.XDescriptors;
import org.apache.slide.store.tamino.jdomobjects.XmlStream;
import org.apache.slide.util.XAssertionFailed;
import org.apache.slide.util.XException;

/**
 * Used to write XDescriptors Objects into Tamino. For performance reasons
 * all descriptors, that may be handled by one Tamino _process call are gathered
 * in one stream and processes as TNonXMLObjects. The result stream is parsed,
 * the ino:ids put to the appropriate descriptors objects.
 *
 * If instantiatet with XDescriptorsAccessor, the "Old fashioned" way to write
 * XDescriptors objects.
 *
 * @author martin.wallmer@softwareag.com
 *
 * @version $Revision: 1.3 $
 */
public class XDescriptorsProcessor {
    //private static final String PROLOG = "";
    private static final String PROLOG = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
    private XDescriptorsAccessor descriptorsAccessor;
    
    private List processList;
    private List deleteList;
    
    private String contentCollection;
    
    XDescriptorsProcessor (String contentCollection) {
        this.contentCollection = contentCollection;
    }
    
    XDescriptorsProcessor (XDescriptorsAccessor accessor) {
        this.descriptorsAccessor= accessor;
    }
    
    /**
     * Method createDeleteQuery
     *
     * @param    deleteList          a  List
     *
     * @return   a  TQuery
     */
    private TQuery createDeleteQuery (List deleteList) {
        Iterator it = deleteList.iterator();
        
        StringBuffer sb  = new StringBuffer (contentCollection).append ("[");
        while (it.hasNext()) {
            XDescriptors xd = (XDescriptors)it.next();
            sb.append ("@ino:id=\"" + xd.getDescriptorsId() + "\"");
            if (it.hasNext()) {
                sb.append (" or ");
            }
            
        }
        sb.append ("]");
        // System.out.println(sb.toString());
        TQuery result = new TQuery (sb.toString());
        return result;
    }
    
    
    
    /**
     * create an InputStream from all Objects
     *
     * @param    processList         a  List
     *
     * @return   a  TDataObject
     */
    private TDataObject getObject(List processList)
        throws UnsupportedEncodingException
    {
        StringBuffer sb = new StringBuffer (PROLOG);
        Iterator it = processList.iterator();
        
        while (it.hasNext()) {
            // Element root = ((XDescriptors)it.next()).toXml().getRootElement();
            
            XmlStream stream = new XmlStream();
            ((XDescriptors)it.next()).toStream (stream);
            sb.append (stream.toString());
        }
        
        String s = sb.toString();
        InputStream is = new ByteArrayInputStream (s.getBytes("UTF-8"));
        //System.out.println(sb.toString());
        
        TDataObject result = TNonXMLObject.newInstance (is);
        result.setContentType ("text/xml;charset=UTF-8");
        
        return result;
    }
    
    
    /**
     * processes all inserts and updates in one call, deletes in one other call.
     *
     */
    void process (TStreamAccessor acc) throws XException
    {
        try
        {
            XProcessResultParser interpreter = new XProcessResultParser ();
            if (processList != null) {
                
                TDataObject obj = getObject (processList);
                TInputStream resultStream = acc.insert (obj);
                interpreter.parse (resultStream);
                String resp = interpreter.getResponse();
                if (!"0".equals(resp))
                    throw new XException ("processing descriptor(s) failed with Tamino error " + resp +
                                              ": " + interpreter.getMessage());
                
                List ids = interpreter.getInoIdList();
                if (ids.size() != processList.size())
                    throw new XAssertionFailed ("number of received ino:ids differ from number of processed descriptors");
                
                for (int i = 0; i < ids.size(); i++) {
                    XDescriptors desc = (XDescriptors)processList.get(i);
                    desc.setDescriptorsId ((String)ids.get(i));
                }
            }
            
            if (deleteList != null) {
                TQuery deleteQuery = createDeleteQuery (deleteList);
                TInputStream resultStream = acc.delete (deleteQuery);
                
                interpreter.parse (resultStream);
                String resp = interpreter.getResponse();
                if (!"0".equals(resp))
                    throw new XException ("deleting descriptor(s) failed with Tamino error " + resp +
                                              ": " + interpreter.getMessage());
                
            }
        }
        catch (UnsupportedEncodingException e) {
            throw new XException (e);
        }
        catch (TException e) {
            throw new XException (e);
        }
        catch (ViolatedPrecondition e) {
            throw new XException (e);
        }
    }
    
    
    /**
     * add a descriptors object to the list
     *
     * @param    desc                a  XDescriptors
     *
     * @throws   XException
     *
     */
    void addInsert (XDescriptors desc)  throws XException {
        if (descriptorsAccessor == null) {
            if (processList == null) processList = new ArrayList ();
            processList.add (desc);
        }
        else {
            descriptorsAccessor.insert (desc);
        }
    }
    
    /**
     * add a descriptors object to the list
     *
     * @param    desc                a  XDescriptors
     *
     * @throws   XException
     *
     */
    void addUpdate (XDescriptors desc)  throws XException {
        // use insert as well
        if (descriptorsAccessor == null) {
            if (processList == null) processList = new ArrayList ();
            processList.add (desc);
        }
        else {
            descriptorsAccessor.update (desc);
        }
    }
    
    /**
     * add a descriptors object to the list.
     * TODO:
     *
     * @param    desc                a  XDescriptors
     *
     * @throws   XException
     *
     */
    void addDelete (XDescriptors desc)  throws XException {
        if (deleteList == null) deleteList = new ArrayList ();
        deleteList.add (desc);
    }
}

