/*
 *
 * ====================================================================
 *
 * Copyright 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.index.lucene;

import java.util.Enumeration;
import java.util.Hashtable;

import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.ServiceInitializationFailedException;
import org.apache.slide.common.ServiceParameterErrorException;
import org.apache.slide.common.ServiceParameterMissingException;
import org.apache.slide.common.Uri;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.content.NodeRevisionContent;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionNumber;
import org.apache.slide.event.DomainEvent;
import org.apache.slide.event.EventDispatcher;
import org.apache.slide.search.IndexException;
import org.apache.slide.util.conf.Configurable;
import org.apache.slide.util.conf.Configuration;
import org.apache.slide.util.conf.ConfigurationException;

/**
 * IndexStore implementation for indexing properties based on Jakarta Lucene.
 */
public class LucenePropertiesIndexer extends AbstractLuceneIndexer
 implements Configurable
{
    private Configuration indexedProperties = null;

    public void initialize(NamespaceAccessToken token)
            throws ServiceInitializationFailedException
    {
        super.initialize(token);
        
        try {
            indexConfiguration.initDefaultConfiguration();
            if (this.indexedProperties != null) {
                indexConfiguration.readPropertyConfiguration(this.indexedProperties);
            }
            
            this.index = new Index(indexConfiguration, getLogger(), 
                    "properties " + this.scope);
            
            if (this.index.needsInitialization()) {
            	DomainEvent.NAMESPACE_INITIALIZED.setEnabled(true);
            	EventDispatcher.getInstance().addEventListener(new IndexInitializer(
            			this.scope, IndexInitializer.PROPERTIES, getLogger()));
            }
        } 
        catch (IndexException e) {
           throw new ServiceInitializationFailedException(this, e);
        }
    }
    
    


    public void setParameters(Hashtable parameters)
            throws ServiceParameterErrorException,
            ServiceParameterMissingException
    {
        super.setParameters(parameters);
    }

    public void configure(Configuration configuration)
            throws ConfigurationException
    {
        if ("indexed-properties".equals(configuration.getAttribute("name"))) {
            this.indexedProperties = configuration;
        }
    }
    

    /**
     * Index an object properties.
     * 
     * @param uri
     *           Uri
     * @exception IndexException
     *               Error accessing the Data Source
     */
    public void createIndex(Uri uri,
            NodeRevisionDescriptor revisionDescriptor,
            NodeRevisionContent revisionContent) throws IndexException
    {
        debug("createIndex {0} {1}", uri, revisionDescriptor.getRevisionNumber());
        
        if (isIncluded(uri.toString())) {
            TransactionalIndexResource indexResource = getCurrentTxn();
            indexResource.addIndexJob(uri, revisionDescriptor);
        }
        
    }

    /**
     * Method updateIndex
     * 
     * @param uri
     *           an Uri
     * @param revisionDescriptor
     *           a NodeRevisionDescriptor
     * @param revisionContent
     *           a NodeRevisionContent
     * 
     * @throws IndexException
     *  
     */
    public void updateIndex(Uri uri,
            NodeRevisionDescriptor revisionDescriptor,
            NodeRevisionContent revisionContent) throws IndexException
    {
        debug("updateIndex {0} {1}", uri, revisionDescriptor.getRevisionNumber());

        if (isIncluded(uri.toString())) {
    
            boolean needsUpdate = false;
            // check whether we need an update, i.e. any of the updated or 
            // removed properties is to be indexed
            for(Enumeration e = revisionDescriptor.enumerateUpdatedProperties();e.hasMoreElements();) {
                NodeProperty property = (NodeProperty)e.nextElement();
                if(index.getConfiguration().isIndexedProperty(property.getPropertyName())) {
                    needsUpdate = true; 
                    break;
                }
            }
            for(Enumeration e = revisionDescriptor.enumerateRemovedProperties();!needsUpdate && e.hasMoreElements();) {
                NodeProperty property = (NodeProperty)e.nextElement();
                if(index.getConfiguration().isIndexedProperty(property.getPropertyName())) {
                    needsUpdate = true; 
                    break;
                }
            }
            
            if (needsUpdate) {
                TransactionalIndexResource indexResource = getCurrentTxn();
                indexResource.addUpdateJob(uri, revisionDescriptor);
            }
        }
    }

    /**
     * Drop an object revision from the index.
     * 
     * @param uri
     *           Uri
     * @exception IndexException
     */
    public void dropIndex(Uri uri, NodeRevisionNumber number)
            throws IndexException
    {
        debug("dropIndex {0} {1}", uri, number);

        if (isIncluded(uri.toString())) {
            TransactionalIndexResource indexResource = getCurrentTxn();
            indexResource.addRemoveJob(uri, number);
        }
    }

    
    

}