/*
 * $Header: /home/cvspublic/jakarta-slide/src/stores/org/apache/slide/store/ojb/property/ElementListPropertyHandler.java,v 1.2 2005/01/23 13:57:27 cvillegas Exp $
 * $Revision: 1.2 $
 * $Date: 2005/01/23 13:57:27 $
 *
 * ====================================================================
 *
 * Copyright 1999-2002 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.ojb.property;

import org.apache.ojb.broker.PersistenceBroker;
import org.apache.ojb.broker.PersistenceBrokerException;
import org.apache.ojb.broker.query.*;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.store.ojb.peer.PropertyPeer;
import org.apache.slide.store.ojb.peer.PropertyValuePeer;
import org.apache.slide.util.logger.Logger;
import org.apache.slide.common.Domain;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import java.util.List;
import java.util.Iterator;
import java.io.IOException;
import java.io.StringReader;

/**
 * A handler for lists of XML elements. 
 * It stores the contents of each element in separate rows in the property_values table.
 */
public class ElementListPropertyHandler implements PropertyHandler {
    
    protected static final String LOG_CHANNEL = ElementListPropertyHandler.class.getName();

    protected static final String XMLPREFIX="<?xml version=\"1.0\"?><property>";
    protected static final String XMLSUFFIX="</property>";

    public NodeProperty retrieve(PersistenceBroker broker, PropertyPeer propertyPeer) 
    		throws PropertyHandlerException {
        // the value in PropertyPeer is used as element template
        String startTag = "";
        String endTag = " ";
        try {
            Document tDoc = new SAXBuilder().build(new StringReader(XMLPREFIX + propertyPeer.getValue() + XMLSUFFIX));
            List ts = tDoc.getRootElement().getChildren();
            Element template = null;
            if ( ts.size() > 0 )
                template = (Element)ts.get(0);
            if ( template != null ) {
                Namespace ns = template.getNamespace();
                startTag = "<" + template.getQualifiedName();
                if ( !ns.getURI().equals("") ) {
                    startTag += " xmlns";
                    if ( !ns.getPrefix().equals("") )
                        startTag += ":" + ns.getPrefix();
                    startTag += "=\"" + ns.getURI() + "\"";
                }
                startTag += ">";
                endTag = "</" + template.getQualifiedName() + ">";
            }
        } catch (Exception je) {
            log("Error parsing element template:", Logger.WARNING);
        }
        StringBuffer value = new StringBuffer();
        try {
            Criteria crit = new Criteria();
            crit.addEqualTo("propertyId", new Long(propertyPeer.getPropertyId()));
            QueryByCriteria query = QueryFactory.newQuery(PropertyValuePeer.class, crit);
            query.addOrderByAscending("valueId");
            Iterator vi = broker.getIteratorByQuery(query);
            while(vi.hasNext()) {
                PropertyValuePeer pvp = (PropertyValuePeer)vi.next();
                value.append(startTag);
                value.append(pvp.getValue());
                value.append(endTag);
            }
        } catch (PersistenceBrokerException e) {
            throw new PropertyHandlerException("Error computing property value", e);
        }
        NodeProperty property = new NodeProperty(propertyPeer.getName(),
                value.toString(),
                propertyPeer.getNamespace(),
                propertyPeer.getType(),
                propertyPeer.isPropertyProtected());
        return property;
    }

    public void store(PersistenceBroker broker, PropertyPeer propertyPeer, NodeProperty property) 
    		throws PropertyHandlerException {
        try {
            Document tDoc = new SAXBuilder().build(new StringReader(XMLPREFIX + property.getValue() + XMLSUFFIX));
            Iterator elems = tDoc.getRootElement().getChildren().iterator();
            long valueId = 0;
            while( elems.hasNext() ) {
                Element elem = (Element)elems.next();
                valueId++;
                if ( valueId == 1 ) {
                    propertyPeer.setName(property.getName());
                    propertyPeer.setNamespace(property.getNamespace());
                    propertyPeer.setType(property.getType());
                    propertyPeer.setPropertyProtected(property.isProtected());
                    Namespace ns = elem.getNamespace();
                    String value = "<" + elem.getQualifiedName();
                    if ( !ns.getURI().equals("") ) {
                        value += " xmlns";
                        if ( !ns.getPrefix().equals("") )
                            value += ":" + ns.getPrefix();
                        value += "=\"" + ns.getURI() + "\"";
                    }
                    value += "/>";
                    propertyPeer.setValue(value);
                    broker.store(propertyPeer);
                    QueryByCriteria query = new QueryByCriteria(propertyPeer);
                    propertyPeer = (PropertyPeer)broker.getObjectByQuery(query);
                    if ( propertyPeer == null )
                        throw new PropertyHandlerException("Could not retrieve stored property: " + property.getNamespace() + ":" + property.getName());
                }   
                PropertyValuePeer propertyValue = new PropertyValuePeer();
                propertyValue.setPropertyId(propertyPeer.getPropertyId());
                propertyValue.setValueId(valueId);
                propertyValue.setValue(elem.getText());
                broker.store(propertyValue);
            }
        } catch (PersistenceBrokerException e) {
            throw new PropertyHandlerException(e.getMessage(), e);
        } catch (JDOMException je) {
            throw new PropertyHandlerException(je.getMessage(), je);
        } catch (IOException ioe ) {
            throw new PropertyHandlerException(ioe.getMessage(), ioe);
        }
    }
    
    public void remove(PersistenceBroker broker, PropertyPeer propertyPeer)
			throws PropertyHandlerException {
        
        // should we just use cascade delete?
        Criteria crit = new Criteria();
        crit.addEqualTo("propertyId", new Long(propertyPeer.getPropertyId()));
        Query query = QueryFactory.newQuery(PropertyValuePeer.class, crit);
        try {
            broker.deleteByQuery(query);
            broker.delete(propertyPeer);
            broker.clearCache();
        } catch (PersistenceBrokerException e) {
            throw new PropertyHandlerException(e.getMessage(), e);
        }
    }
    
    protected void log(String message) {
        Domain.log(message, LOG_CHANNEL, Logger.DEBUG);
    }

    protected void log(String message, int level) {
        Domain.log(message, LOG_CHANNEL, level);
    }
}
