/*
 * Copyright 2010 Outerthought bvba
 *
 * 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.lilyproject.indexer.model.indexerconf;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.google.common.base.Predicate;
import org.lilyproject.repository.api.FieldType;
import org.lilyproject.repository.api.Record;
import org.lilyproject.repository.api.RepositoryException;
import org.lilyproject.repository.api.SchemaId;
import org.lilyproject.repository.api.Scope;
import org.lilyproject.util.repo.SystemFields;
import org.lilyproject.util.repo.VTaggedRecord;

// TODO for safety should consider making some of the returned lists immutable

/**
 * The configuration for the indexer, describes how record types should be mapped
 * onto index documents.
 *
 * <p>Fields and vtags are identified by ID in this object model.
 *
 * <p>The IndexerConf is constructed by the {@link IndexerConfBuilder}. Some essential
 * validation is done by that builder which would not be done in case of direct
 * construction.
 */
public class IndexerConf {
    private IndexRecordFilter recordFilter;
    private IndexFields indexFields;
    private Set<SchemaId> repoFieldDependencies = new HashSet<SchemaId>();
    private List<DynamicIndexField> dynamicFields = new ArrayList<DynamicIndexField>();
    private Set<SchemaId> vtags = new HashSet<SchemaId>();
    private Formatters formatters = new Formatters();
    private SystemFields systemFields;
    private boolean containsDerefExpression = false;

    protected void setRecordFilter(IndexRecordFilter recordFilter) {
        this.recordFilter = recordFilter;
        for (IndexCase indexCase : recordFilter.getAllIndexCases()) {
            vtags.addAll(indexCase.getVersionTags());
        }
    }

    /**
     * @return null if there is no matching IndexCase
     */
    public IndexCase getIndexCase(Record record) {
        return recordFilter.getIndexCase(record);
    }

    public IndexFields getIndexFields() {
        return indexFields;
    }

    public IndexRecordFilter getRecordFilter() {
        return recordFilter;
    }

    public void setIndexFields(IndexFields indexFields) {
        this.indexFields = indexFields;

        // update information about repository field dependencies
        repoFieldDependencies.clear();

        indexFields.visitAll(new Predicate<MappingNode>() {
            @Override
            public boolean apply(MappingNode node) {
                if (node instanceof IndexField) {
                    IndexField indexField = (IndexField) node;
                    SchemaId fieldDep = indexField.getValue().getFieldDependency();
                    if (fieldDep != null)
                        repoFieldDependencies.add(fieldDep);

                    if (indexField.getValue() instanceof DerefValue) {
                        containsDerefExpression = true;
                    }
                } else if (node instanceof ForEachNode) {
                    containsDerefExpression = true;
                }
                return true;
            }
        });
    }

    protected void addDynamicIndexField(DynamicIndexField field) {
        dynamicFields.add(field);
    }

    public List<DynamicIndexField> getDynamicFields() {
        return dynamicFields;
    }

    public boolean containsDerefExpressions() {
        return containsDerefExpression;
    }

    /**
     * Returns the set of all known vtags, thus all the vtags that are relevant to indexing.
     */
    public Set<SchemaId> getVtags() {
        return vtags;
    }

    public Formatters getFormatters() {
        return formatters;
    }

    public SystemFields getSystemFields() {
        return systemFields;
    }

    public void setSystemFields(SystemFields systemFields) {
        this.systemFields = systemFields;
    }

    public boolean changesAffectIndex(VTaggedRecord vtRecord, Scope scope)
            throws InterruptedException, RepositoryException {
        Set<FieldType> changedFields = vtRecord.getRecordEventHelper().getUpdatedFieldsByScope().get(scope);

        // Check static fields and dynamic fields
        for (FieldType fieldType : changedFields) {
            if (repoFieldDependencies.contains(fieldType.getId())) {
                return true;
            }

            // If there are lots of dynamic index fields, or lots of fields which are not indexed at all (thus
            // leading to lots of invocations of this method), than maybe we need to review this for performance.
            for (DynamicIndexField field : dynamicFields) {
                if (field.matches(fieldType).match) {
                    return true;
                }
            }

        }

        // Check <fields>
        return indexFields.isIndexAffectedByUpdate(vtRecord, scope);

    }

}

@@ -1693,83 +1693,8 @@
 ds;%0A
-    private Set%3CSchemaId%3E repoFieldDependencies = new HashSet%3CSchemaId%3E();%0A
     
@@ -2678,114 +2678,8 @@
 s;%0A%0A
-        // update information about repository field dependencies%0A        repoFieldDependencies.clear();%0A%0A
     
@@ -2926,196 +2926,8 @@
 de;%0A
-                    SchemaId fieldDep = indexField.getValue().getFieldDependency();%0A                    if (fieldDep != null)%0A                        repoFieldDependencies.add(fieldDep);%0A%0A
     
@@ -4266,166 +4266,118 @@
 eck 
-static fields and dynamic fields%0A        for (FieldType fieldType : changedFields) %7B%0A            if (repoFieldDependencies.contains(fieldType.getId())) %7B%0A    
+%3Cfields%3E%0A        boolean affects = indexFields.isIndexAffectedByUpdate(vtRecord, scope);%0A        if (affects)%0A
     
@@ -4393,32 +4393,33 @@
 eturn true;%0A
+%0A
         
     %7D%0A%0A     
@@ -4398,38 +4398,107 @@
  true;%0A%0A        
-    %7D%0A
+// Check dynamic fields%0A        for (FieldType fieldType : changedFields) %7B
 %0A            // 
@@ -4878,33 +4878,32 @@
 %7D%0A            %7D%0A
-%0A
         %7D%0A%0A     
@@ -4909,95 +4909,21 @@
     
-// Check %3Cfields%3E%0A        return indexFields.isIndexAffectedByUpdate(vtRecord, scope);%0A
+return false;
 %0A   

Remove obsolete repoFieldDependencies.