/*
 * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
 *
 * The contents of this file are subject to the CCM Public
 * License (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.redhat.com/licenses/ccmpl.html.
 *
 * Software distributed under the License is distributed on an
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 * or implied. See the License for the specific language
 * governing rights and limitations under the License.
 *
 */
package com.arsdigita.search;


import com.arsdigita.db.DbHelper;
import com.arsdigita.runtime.AbstractConfig;
import com.arsdigita.runtime.RuntimeConfig;
import com.arsdigita.util.Assert;
import com.arsdigita.util.parameter.BooleanParameter;
import com.arsdigita.util.parameter.EnumerationParameter;
import com.arsdigita.util.parameter.ErrorList;
import com.arsdigita.util.parameter.IntegerParameter;
import com.arsdigita.util.parameter.Parameter;
import com.arsdigita.util.parameter.ParameterError;

import org.apache.log4j.Logger;

import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;

/**
 * Stores the configuration record for the search service
 */
public final class SearchConfig extends AbstractConfig {

    private static Logger s_log = Logger.getLogger(SearchConfig.class);

    private EnumerationParameter m_indexer;
    private Parameter m_lazyUpdates;
    private Parameter m_xmlContentWeight;
    private Parameter m_rawContentWeight;

    public SearchConfig() {

        m_indexer = new IndexerParameter
            ("waf.search.indexer", 
             Parameter.REQUIRED,
             IndexerType.LUCENE);
        m_indexer.put(IndexerType.INTERMEDIA.getKey(), 
                      IndexerType.INTERMEDIA);
        m_indexer.put(IndexerType.LUCENE.getKey(), 
                      IndexerType.LUCENE);
        m_indexer.put(IndexerType.NOOP.getKey(), 
                      IndexerType.NOOP);

        m_lazyUpdates = new BooleanParameter
            ("waf.search.lazy_updates", 
             Parameter.REQUIRED, 
             new Boolean(true));

        m_xmlContentWeight = new IntegerParameter
            ("waf.search.intermedia.xml_content_weight",
             Parameter.REQUIRED,
             new Integer(1));
        m_rawContentWeight = new IntegerParameter
            ("waf.search.intermedia.raw_content_weight",
             Parameter.REQUIRED,
             new Integer(1));

        register(m_indexer);
        register(m_lazyUpdates);
        register(m_xmlContentWeight);
        register(m_rawContentWeight);

        loadInfo();
    }

    /**
     * Returns the current active indexer type
     */
    public IndexerType getIndexerType() {
        return (IndexerType)get(m_indexer);
    }

    /**
     * Returns the current active indexer type key
     * @see #isIntermediaEnabled()
     * @see #isLuceneEnabled()
     */
    public String getIndexer() {
        return getIndexerType().getKey();
    }

    /**
     * Sets the current active indexer type. This is not a public
     * method, as it should <em>only</em> be used by the unit
     * tests. Under normal operations, the indexer is controlled by
     * the parameters.
     */
    void setIndexerType(IndexerType indexer) {
        set(m_indexer, indexer);
    }

    /**
     * Convenience method for determining if intermedia
     * is currently enabled
     * @return true if intermedia is active, false otherwise
     * @see #getIndexer()
     */
    public boolean isIntermediaEnabled() {
        return IndexerType.INTERMEDIA.equals(getIndexerType());
    }

    /**
     * Convenience method for determining if lucene
     * is currently enabled
     * @return true if intermedia is active, false otherwise
     * @see #getIndexer()
     */
    public boolean isLuceneEnabled() {
        return IndexerType.LUCENE.equals(getIndexerType());
    }

    /**
     * Returns the bitmask for allowed content types.  The bits in the mask
     * correspond to the XXX constants defined in the {@link ContentType} class.
     * @return content bit mask
     * @see ContentType#RAW
     * @see ContentType#XML
     * @see ContentType#TEXT
     */
    public ContentType[] getContent() {
        return getIndexerType().getContent();
    }

    /**
     * Determines if raw binary content is supported
     * @return true if raw content is supported
     * @see #allowsTextContent()
     * @see #allowsXMLContent()
     */
    public boolean allowsRawContent() {
        ContentType[] types = getContent();
        for (int i = 0 ; i < types.length ; i++) {
            if (types[i].equals(ContentType.RAW)) {
                return true;
            }
        }
        return false;
    }
    /**
     * Determines if plain text content is supported
     * @return true if text content is supported
     * @see #allowsRawContent()
     * @see #allowsXMLContent()
     */
    public boolean allowsTextContent() {
        ContentType[] types = getContent();
        for (int i = 0 ; i < types.length ; i++) {
            if (types[i].equals(ContentType.TEXT)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Determines if xml content is supported
     * @return true if xml content is supported
     * @see #allowsTextContent()
     * @see #allowsRawContent()
     */
    public boolean allowsXMLContent() {
        ContentType[] types = getContent();
        for (int i = 0 ; i < types.length ; i++) {
            if (types[i].equals(ContentType.XML)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Determines if the content type represented by
     * the specified bitmask is supported.
     * @return true if the bitmask requested is supported
     * @see #allowsXMLContent()
     * @see #allowsTextContent()
     * @see #allowsRawContent()
     */
    public boolean allowsContent(ContentType content) {
        ContentType[] types = getContent();
        for (int i = 0 ; i < types.length ; i++) {
            if (types[i].equals(content)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns the current document update observer
     * @return the document observer, or null if none is configured.
     */
    public DocumentObserver getObserver() {
        return getIndexerType().getObserver();
    }

    /**
     * Returns the lazy update flag. If this is set to
     * true, then the search index will only be updated
     * at the end of a transaction.
     * @return true if lazy updates are turned on
     */
    public boolean getLazyUpdates() {
        return ((Boolean) get(m_lazyUpdates)).booleanValue();
    }
 

    /**
     * Sets the lazy update flag. This is not a public
     * method, as it should <em>only</em> be used by the unit
     * tests. Under normal operations, the indexer is controlled by
     * the parameters.
     */
    void setLazyUpdates(boolean lazyUpdates) {
        set (m_lazyUpdates,new Boolean(lazyUpdates));
    }

    private class IndexerParameter extends EnumerationParameter {
        public IndexerParameter(final String name,
                                final int multiplicity,
                                final Object defaalt) {
            super(name, multiplicity, defaalt);
        }
        // XXX
        // This validation method is commented out for now due to
        // https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=111291
        // The basic problem is that the first time that the configuration is
        // being loaded, the RuntimeConfig context hasn't been loaded yet, so
        // RuntimeConfig.getConfig() fails.  - dgregor@redhat.com 12/01/2003
        //
        // protected void doValidate(final Object value, final ErrorList errors) {
        //     super.doValidate(value,errors);
        //     if (Search.INDEXER_INTERMEDIA.equals(value) &&
        //         DbHelper.getDatabaseFromURL(RuntimeConfig.getConfig().getJDBCURL()) != DbHelper.DB_ORACLE) {
        //         errors.add(new ParameterError
        //                    (IndexerParameter.this,
        //                     "Intermedia searching only works on Oracle, not " +
        //                     DbHelper.getDatabaseName(DbHelper.getDatabaseFromURL(RuntimeConfig.getConfig().getJDBCURL()))));
        //     }
        // }
    }

    /**
     * The relative given to XML content when ranking search results.
     * Only used by the interMedia query engine.
     **/
    public Integer getXMLContentWeight() {
        return (Integer) get(m_xmlContentWeight);
    }

    /**
     * The relative given to raw content when ranking search results.
     * Only used by the interMedia query engine.
     **/
    public Integer getRawContentWeight() {
        return (Integer) get(m_rawContentWeight);
    }
}
