/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.netbeans.modules.parsing.lucene;

import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.FieldSelector;
import org.apache.lucene.search.Query;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.modules.parsing.lucene.support.Convertor;
import org.netbeans.modules.parsing.lucene.support.DocumentIndex2;
import org.netbeans.modules.parsing.lucene.support.DocumentIndexCache;
import org.netbeans.modules.parsing.lucene.support.Index;
import org.netbeans.modules.parsing.lucene.support.IndexDocument;
import org.netbeans.modules.parsing.lucene.support.Queries;
import org.netbeans.modules.parsing.lucene.support.Queries.QueryKind;
import org.openide.util.Parameters;

/**
 *
 * @author Tomas Zezula
 */
public class DocumentIndexImpl implements DocumentIndex2, Runnable {
                            
    private static final Convertor<IndexDocument,Document> DEFAULT_ADD_CONVERTOR = Convertors.newIndexDocumentToDocumentConvertor();    
    private static final Convertor<Document,IndexDocumentImpl> DEFAULT_QUERY_CONVERTOR = Convertors.newDocumentToIndexDocumentConvertor();
    private static final Convertor<String,Query> REMOVE_CONVERTOR = Convertors.newSourceNameToQueryConvertor();
    private static final Logger LOGGER = Logger.getLogger(DocumentIndexImpl.class.getName());
    
    private final Set</*@GuardedBy("this")*/String> dirtyKeys = new HashSet<String>();
    //@GuardedBy ("this")
    private final DocumentIndexCache cache;
    private final Index luceneIndex;
    private final Convertor<? super IndexDocument, ? extends Document> addConvertor;
    private final Convertor<? super Document, ? extends IndexDocument> queryConvertor;
    /**
     * Transactional extension to the index
     */
    final Index.Transactional txLuceneIndex;
    final AtomicBoolean requiresRollBack = new AtomicBoolean();


    private DocumentIndexImpl (
            @NonNull final Index index,
            @NonNull final DocumentIndexCache cache) {
        assert index != null;
        assert cache != null;
        this.luceneIndex = index;
        this.cache = cache;
        Convertor<IndexDocument,Document> _addConvertor = null;
        Convertor<Document,IndexDocument> _queryConvertor = null;
        if (cache instanceof DocumentIndexCache.WithCustomIndexDocument) {
            final DocumentIndexCache.WithCustomIndexDocument cacheWithCustomDoc =
                    (DocumentIndexCache.WithCustomIndexDocument) cache;
            _addConvertor = cacheWithCustomDoc.createAddConvertor();
            _queryConvertor = cacheWithCustomDoc.createQueryConvertor();
        }
        addConvertor = _addConvertor != null ? _addConvertor : DEFAULT_ADD_CONVERTOR;
        queryConvertor = _queryConvertor != null ? _queryConvertor : DEFAULT_QUERY_CONVERTOR;
        if (index instanceof Index.Transactional) {
            this.txLuceneIndex = (Index.Transactional)index;
        } else {
            this.txLuceneIndex = null;
        }
    }
    
    /**
     * Adds document
     * @param document
     */
    @Override
    public void addDocument(IndexDocument document) {
        final boolean forceFlush;
        synchronized (this) {
            forceFlush = cache.addDocument(document);
        }
        if (forceFlush) {
            try {
                LOGGER.fine("Extra flush forced"); //NOI18N
                store(false, true);
                System.gc();
            } catch (IOException ioe) {
                //Reindexed in RU.storeChanges
                LOGGER.log(Level.WARNING, ioe.getMessage());
                requiresRollBack.set(true);
            }
        }
    }

    /**
     * Removes all documents for given path
     * @param relativePath
     */
    @Override
    public void removeDocument(String primaryKey) {
        final boolean forceFlush;
        synchronized (this) {
            forceFlush = cache.removeDocument(primaryKey);
        }
        if (forceFlush) {
            try {
                LOGGER.fine("Extra flush forced"); //NOI18N
                store(false, true);
            } catch (IOException ioe) {
                //Reindexed in RU.storeChanges
                LOGGER.log(Level.WARNING, ioe.getMessage());
                requiresRollBack.set(true);
            }
        }
    }

    
    /**
     * Checks if the Lucene index is valid.
     * @return {@link Status#INVALID} when the index is broken, {@link Status#EMPTY}
     * when the index does not exist or {@link  Status#VALID} if the index is valid
     * @throws IOException when index is already closed
     */
    @Override
    public Index.Status getStatus() throws IOException {
        return luceneIndex.getStatus(true);
    }
    
    @Override
    public void close() throws IOException {
        luceneIndex.close();
    }
    
    @Override
    public void store(boolean optimize) throws IOException {
        checkRollBackNeeded();
        store(optimize, false);
    }

    @Override
    public void run() {
        if (luceneIndex instanceof Runnable) {
            ((Runnable)luceneIndex).run();
        }
    }
    
    private void store(boolean optimize, boolean flushOnly) throws IOException {
        final  boolean change = storeImpl(optimize, flushOnly);
        if (!change && !flushOnly && txLuceneIndex != null) {
            commitImpl();
        }
    }

    private boolean storeImpl(
            final boolean optimize,
            final boolean flushOnly) throws IOException {
        final Collection<? extends IndexDocument> _toAdd;
        final Collection<? extends String> _toRemove;
        synchronized (this) {
            _toAdd = cache.getAddedDocuments();
            _toRemove = cache.getRemovedKeys();
            cache.clear();
            if (!dirtyKeys.isEmpty()) {
                for(IndexDocument ldoc : _toAdd) {
                    this.dirtyKeys.remove(ldoc.getPrimaryKey());
                }
                this.dirtyKeys.removeAll(_toRemove);
            }
        }
        if (!_toAdd.isEmpty() || !_toRemove.isEmpty()) {
            LOGGER.log(Level.FINE, "Flushing: {0}", luceneIndex.toString()); //NOI18N
            if (flushOnly && txLuceneIndex != null) {
                txLuceneIndex.txStore(
                        _toAdd,
                        _toRemove,
                        addConvertor,
                        REMOVE_CONVERTOR
                );
            } else {
                luceneIndex.store(
                        _toAdd,
                        _toRemove,
                        addConvertor,
                        REMOVE_CONVERTOR,
                        optimize);
            }
            return true;
        }
        return false;
    }

    private void commitImpl() throws IOException {
        checkRollBackNeeded();
        txLuceneIndex.commit();
    }

    private void checkRollBackNeeded() throws IOException {
        if (requiresRollBack.get()) {
            throw new IOException("Index requires rollback.");   //NOI18N
        }
    }

    @Override
    public Collection<? extends IndexDocument> query(String fieldName, String value, QueryKind kind, String... fieldsToLoad) throws IOException, InterruptedException {
        assert fieldName != null;
        assert value != null;
        assert kind != null;
        final Query query = Queries.createQuery(fieldName, fieldName, value, kind);
        return query(
            query,
            org.netbeans.modules.parsing.lucene.support.Convertors.<IndexDocument>identity(),
            fieldsToLoad);
    }
    
    @Override
    public Collection<? extends IndexDocument> findByPrimaryKey (
            final String primaryKeyValue,
            final Queries.QueryKind kind,
            final String... fieldsToLoad) throws IOException, InterruptedException {
                return query(IndexDocumentImpl.FIELD_PRIMARY_KEY, primaryKeyValue, kind, fieldsToLoad);
    }

    @Override
    @NonNull
    public <T> Collection<? extends T> query(
            @NonNull final Query query,
            @NonNull final Convertor<? super IndexDocument, ? extends T> convertor,
            @NullAllowed final String... fieldsToLoad) throws IOException, InterruptedException {
        Parameters.notNull("query", query); //NOI18N
        Parameters.notNull("convertor", convertor); //NOI18N
        final Collection<T> result = new ArrayDeque<T>();
        FieldSelector selector = null;
        if (fieldsToLoad != null && fieldsToLoad.length > 0) {
            final String[] fieldsWithSource = Arrays.copyOf(fieldsToLoad, fieldsToLoad.length+1);
            fieldsWithSource[fieldsToLoad.length] = IndexDocumentImpl.FIELD_PRIMARY_KEY;
            selector = Queries.createFieldSelector(fieldsWithSource);
        }
        luceneIndex.query(
            result,
            org.netbeans.modules.parsing.lucene.support.Convertors.compose(queryConvertor, convertor),
            selector,
            null,
            query);
        return result;
    }

    @Override
    public void markKeyDirty(final String primaryKey) {
        synchronized (this) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.log(Level.FINE, "{0}, adding dirty key: {1}", new Object[]{this, primaryKey}); //NOI18N
            }
            dirtyKeys.add(primaryKey);
        }
    }

    @Override
    public void removeDirtyKeys(final Collection<? extends String> keysToRemove) {
        synchronized (this) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.log(Level.FINE, "{0}, Removing dirty keys: {1}", new Object[]{this, keysToRemove}); //NOI18N
            }
            dirtyKeys.removeAll(keysToRemove);
        }
    }

    @Override
    public Collection<? extends String> getDirtyKeys() {
        synchronized (this) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.log(Level.FINE, "{0}, dirty keys: {1}", new Object[]{this, dirtyKeys}); //NOI18N
            }
            return new ArrayList<String>(dirtyKeys);
        }
    }
    
    
    @Override
    public String toString () {
        return String.format(
            "DocumentIndexImpl[%s]",  //NOI18N
            luceneIndex.toString());
    }

    @NonNull
    public static DocumentIndex2 create(
            @NonNull final Index index,
            @NonNull final DocumentIndexCache cache) {
        return new DocumentIndexImpl(index, cache);
    }

    @NonNull
    public static DocumentIndex2.Transactional createTransactional(
            @NonNull final Index.Transactional index,
            @NonNull final DocumentIndexCache cache) {
        return new DocumentIndexImpl.Transactional(index, cache);
    }

    private static final class Transactional extends DocumentIndexImpl implements DocumentIndex2.Transactional {

        private Transactional(
            @NonNull final Index.Transactional index,
            @NonNull final DocumentIndexCache cache) {
            super(index, cache);
        }

        @Override
        public void txStore() throws IOException {
            super.storeImpl(false, true);
        }

        @Override
        public void commit() throws IOException {
            super.commitImpl();
        }

        @Override
        public void rollback() throws IOException {
            this.requiresRollBack.set(false);
            this.txLuceneIndex.rollback();
        }

        @Override
        public void clear() throws IOException {
            this.requiresRollBack.set(false);
            this.txLuceneIndex.clear();
        }

        @Override
        public String toString () {
            return "DocumentIndex.Transactional ["+super.luceneIndex.toString()+"]";  //NOI18N
        }

    }
                    
}
