/*
 * 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.apache.jackrabbit.oak.plugins.document.mongo;

import com.mongodb.ReadPreference;

import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.plugins.document.AbstractMongoConnectionTest;
import org.apache.jackrabbit.oak.plugins.document.Collection;
import org.apache.jackrabbit.oak.plugins.document.DocumentMK;
import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
import org.apache.jackrabbit.oak.plugins.document.LeaseCheckMode;
import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection;
import org.apache.jackrabbit.oak.plugins.document.util.Utils;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import static com.google.common.collect.Iterables.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class CacheInvalidationIT extends AbstractMongoConnectionTest {

    private DocumentNodeStore c1;
    private DocumentNodeStore c2;
    private int initialCacheSizeC1;

    @Before
    public void prepareStores() throws Exception {
        // TODO start with clusterNodeId 2, because 1 has already been
        // implicitly allocated in the base class
        c1 = createNS(2);
        c2 = createNS(3);
        initialCacheSizeC1 = getCurrentCacheSize(c1);
    }

    private int createScenario() throws CommitFailedException {
        //          a
        //        / | \
        //       /  c  \
        //      b       d
        //     /|\      |
        //    / | \     h
        //   e  f  g
        String[] paths = {
                "/a",
                "/a/c",
                "/a/b",
                "/a/b/e",
                "/a/b/f",
                "/a/b/g",
                "/a/d",
                "/a/d/h",
        };
        NodeBuilder root = getRoot(c1).builder();
        createTree(root, paths);
        c1.merge(root, EmptyHook.INSTANCE, CommitInfo.EMPTY);

        assertEquals(initialCacheSizeC1 + paths.length, getCurrentCacheSize(c1));

        runBgOps(c1, c2);
        return paths.length;
    }

    @Test
    public void testCacheInvalidation() throws CommitFailedException {
        final int totalPaths = createScenario();

        NodeBuilder b2 = getRoot(c2).builder();
        builder(b2, "/a/d").setProperty("foo", "bar");
        c2.merge(b2, EmptyHook.INSTANCE, CommitInfo.EMPTY);

        //Push pending changes at /a
        c2.runBackgroundOperations();

        //Refresh the head for c1
        c1.runBackgroundOperations();

        //Only 2 entries /a and /a/d would be invalidated
        // '/' would have been added to cache in start of backgroundRead
        //itself
        assertEquals(initialCacheSizeC1 + totalPaths - 2, size(ds(c1).getNodeDocumentCache().keys()));
    }

    @Test
    public void testCacheInvalidationHierarchicalNotExist()
            throws CommitFailedException {

        NodeBuilder b2 = getRoot(c2).builder();
        // we create x/other, so that x is known to have a child node
        b2.child("x").child("other");
        b2.child("y");
        c2.merge(b2, EmptyHook.INSTANCE, CommitInfo.EMPTY);
        c2.runBackgroundOperations();
        c1.runBackgroundOperations();

        // we check for the existence of "x/futureX", which
        // should create a negative entry in the cache
        NodeState x = getRoot(c1).getChildNode("x");
        assertTrue(x.exists());
        assertFalse(x.getChildNode("futureX").exists());
        // we don't check for the existence of "y/futureY"
        NodeState y = getRoot(c1).getChildNode("y");
        assertTrue(y.exists());

        // now we add both "futureX" and "futureY"
        // in the other cluster node
        b2.child("x").child("futureX").setProperty("z", "1");
        c2.merge(b2, EmptyHook.INSTANCE, CommitInfo.EMPTY);
        b2.child("y").child("futureY").setProperty("z", "2");
        c2.merge(b2, EmptyHook.INSTANCE, CommitInfo.EMPTY);
        
        c2.runBackgroundOperations();
        c1.runBackgroundOperations();

        // both nodes should now be visible
        assertTrue(getRoot(c1).getChildNode("y").getChildNode("futureY").exists());
        assertTrue(getRoot(c1).getChildNode("x").getChildNode("futureX").exists());

    }

    private int getCurrentCacheSize(DocumentNodeStore ds){
        return size(ds(ds).getNodeDocumentCache().keys());
    }

    private static void refreshHead(DocumentNodeStore store) {
        ds(store).find(Collection.NODES, Utils.getIdFromPath("/"), 0);
    }


    private static MongoDocumentStore ds(DocumentNodeStore ns) {
        return (MongoDocumentStore) ns.getDocumentStore();
    }

    private static void createTree(NodeBuilder node, String[] paths) {
        for (String path : paths) {
            createPath(node, path);
        }
    }

    private static NodeBuilder builder(NodeBuilder builder, String path) {
        for (String name : PathUtils.elements(path)) {
            builder = builder.getChildNode(name);
        }
        return builder;
    }

    private static void createPath(NodeBuilder node, String path) {
        for (String element : PathUtils.elements(path)) {
            node = node.child(element);
        }
    }

    private static NodeState getRoot(NodeStore store) {
        return store.getRoot();
    }

    @After
    public void closeStores() {
        if (c2 != null) {
            c2.dispose();
        }
        if (c1 != null) {
            c1.dispose();
        }
    }

    private static void runBgOps(DocumentNodeStore... stores) {
        for (DocumentNodeStore ns : stores) {
            ns.runBackgroundOperations();
        }
    }

    private DocumentNodeStore createNS(int clusterId) throws Exception {
        MongoConnection mc = connectionFactory.getConnection();
        DocumentNodeStore ns = new DocumentMK.Builder()
                          .setMongoDB(mc.getMongoClient(), mc.getDBName())
                          .setClusterId(clusterId)
                          //Set delay to 0 so that effect of changes are immediately reflected
                          .setAsyncDelay(0)
                          .setBundlingDisabled(true)
                          .setLeaseCheckMode(LeaseCheckMode.DISABLED)
                          .getNodeStore();
        // enforce primary read preference, otherwise test fails on a replica
        // set with a read preference configured to secondary.
        MongoTestUtils.setReadPreference(ns, ReadPreference.primary());
        return ns;
    }

}
