/*
 * 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.jcr.version;

import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.version.Version;
import javax.jcr.version.VersionException;
import javax.jcr.version.VersionHistory;
import javax.jcr.version.VersionManager;

import com.google.common.base.Function;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.test.AbstractJCRTest;
import org.jetbrains.annotations.Nullable;

import java.util.Set;

import static com.google.common.collect.ImmutableSet.of;
import static com.google.common.collect.Lists.transform;
import static com.google.common.collect.Sets.newHashSet;
import static java.util.Arrays.asList;

/**
 * {@code VersionableTest} contains tests for method relevant to
 * versionable nodes.
 */
public class VersionableTest extends AbstractJCRTest {

    public void testGetTypeOfPredecessors() throws RepositoryException {
        Node node = testRootNode.addNode(nodeName1, testNodeType);
        node.addMixin(mixVersionable);
        superuser.save();
        VersionManager vMgr = superuser.getWorkspace().getVersionManager();
        vMgr.checkin(node.getPath());
        assertEquals(PropertyType.nameFromValue(PropertyType.REFERENCE),
                PropertyType.nameFromValue(node.getProperty(jcrPredecessors).getType()));
    }

    public void testReadOnlyAfterCheckin() throws RepositoryException {
        Node node = testRootNode.addNode(nodeName1, testNodeType);
        node.addMixin(mixVersionable);
        superuser.save();
        VersionManager vMgr = superuser.getWorkspace().getVersionManager();
        if (!node.isCheckedOut()) {
            vMgr.checkout(node.getPath());
        }
        superuser.refresh(false);
        node.setProperty(propertyName1, "foo");
        superuser.save();
        vMgr.checkin(node.getPath());
        try {
            node.setProperty(propertyName1, "bar");
            fail("setProperty() must fail on a checked-in node");
        } catch (VersionException e) {
            // expected
        }
        try {
            node.setProperty(propertyName1, (String)null);
            fail("setProperty(..., null) must fail on a checked-in node");
        } catch (VersionException e) {
            // expected
        }
        try {
            Property prop = node.getProperty(propertyName1);
            assertNotNull(prop);
            prop.setValue("bar");
            fail("Property.setValue() must fail on a checked-in node");
        } catch (VersionException e) {
            // expected
        }
        try {
            Property prop = node.getProperty(propertyName1);
            assertNotNull(prop);
            prop.remove();
            fail("Property.remove() must fail on a checked-in node");
        } catch (VersionException e) {
            // expected
        }
    }

    public void testReferenceableChild() throws RepositoryException {
        Node node = testRootNode.addNode(nodeName1, ntUnstructured);
        node.addMixin(mixVersionable);
        Node child = node.addNode(nodeName2, ntUnstructured);
        child.addMixin(mixReferenceable);
        superuser.save();
        VersionManager vMgr = superuser.getWorkspace().getVersionManager();
        vMgr.checkin(node.getPath());
    }

    /**
     * Test from Jackrabbit: JCR-3635 (OAK-940)
     * <p>
     * Tests the case when a node already has a manual set
     * JcrConstants.JCR_FROZENUUID property and is versioned. The manual set
     * frozenUuid will overwrite the one that is automatically assigned by the
     * VersionManager, which should not happen
     */
    public void testCopyFrozenUuidProperty() throws Exception {
        Node firstNode = testRootNode.addNode(nodeName1);
        firstNode.setPrimaryType(JcrConstants.NT_UNSTRUCTURED);
        firstNode.addMixin(JcrConstants.MIX_VERSIONABLE);
        firstNode.getSession().save();

        // create version for the node
        Version firstNodeVersion = firstNode.checkin();
        firstNode.checkout();

        Node secondNode = testRootNode.addNode(nodeName2);
        secondNode.setPrimaryType(JcrConstants.NT_UNSTRUCTURED);
        secondNode.addMixin(JcrConstants.MIX_VERSIONABLE);
        Property firstNodeVersionFrozenUuid = firstNodeVersion.getFrozenNode().getProperty(JcrConstants.JCR_FROZENUUID);
        secondNode.setProperty(JcrConstants.JCR_FROZENUUID, firstNodeVersionFrozenUuid.getValue());
        secondNode.getSession().save();

        // create version of the second node
        Version secondNodeVersion = secondNode.checkin();
        secondNode.checkout();

        // frozenUuid from the second node version node should not be the same as the one from the first node version
        Property secondBodeVersionFrozenUuid = secondNodeVersion.getFrozenNode().getProperty(JcrConstants.JCR_FROZENUUID);
        assertFalse(JcrConstants.JCR_FROZENUUID + " should not be the same for two different versions of different nodes! ",
                secondBodeVersionFrozenUuid.getValue().equals(firstNodeVersionFrozenUuid.getValue()));
    }

    public void testCheckoutWithPendingChanges() throws Exception {
        Node node = testRootNode.addNode(nodeName1, testNodeType);
        node.addMixin(mixVersionable);
        superuser.save();
        node.checkin();
        Node newNode = testRootNode.addNode(nodeName2, testNodeType);
        assertTrue(newNode.isNew());
        node.checkout();
        assertTrue(node.isCheckedOut());
        assertTrue(newNode.isNew());
    }

    // OAK-1272
    public void testRemoveAndCreateSameVersionableChildNode() throws Exception {
        // create parent
        Node parentNode = testRootNode.addNode("parent");
        parentNode.setPrimaryType(ntUnstructured);
        parentNode.setProperty("name", "sample");
        // create a versionable child
        Node createdNode = parentNode.addNode("versionablechild", "nt:unstructured");
        createdNode.addMixin(mixVersionable);
        superuser.save();

        VersionManager vm = superuser.getWorkspace().getVersionManager();
        vm.checkin(testRootNode.getPath()+"/parent/versionablechild");

        // delete and create exact same node
        Node parent = testRootNode.getNode("parent");

        // remove children
        NodeIterator nodes = parent.getNodes();
        while (nodes.hasNext()) {
            Node childNode = nodes.nextNode();
            childNode.remove();
        }

        // create again versionable child node
        Node recreatedNode = parent.addNode("versionablechild", ntUnstructured);
        recreatedNode.addMixin(mixVersionable);
        superuser.save();
    }

    // Oak-1272
    public void testRecreateVersionableNodeWithChangedProperty() throws Exception {
        Node node = testRootNode.addNode(nodeName1, ntUnstructured);
        node.addMixin(mixVersionable);
        node.setProperty(propertyName1, "foo");
        superuser.save();

        VersionManager vm = superuser.getWorkspace().getVersionManager();
        vm.checkin(node.getPath());

        // re-create node
        node.remove();
        node = testRootNode.addNode(nodeName1, ntUnstructured);
        node.addMixin(mixVersionable);
        node.setProperty(propertyName1, "bar");

        superuser.save();
    }

    // Oak-1272
    public void testRecreateVersionableNodeWithNewProperty() throws Exception {
        Node node = testRootNode.addNode(nodeName1, ntUnstructured);
        node.addMixin(mixVersionable);
        superuser.save();

        VersionManager vm = superuser.getWorkspace().getVersionManager();
        vm.checkin(node.getPath());

        // re-create node
        node.remove();
        node = testRootNode.addNode(nodeName1, ntUnstructured);
        node.addMixin(mixVersionable);
        node.setProperty(propertyName1, "bar");

        superuser.save();
    }

    // Oak-1272
    public void testRecreateVersionableNodeWithRemovedProperty() throws Exception {
        Node node = testRootNode.addNode(nodeName1, ntUnstructured);
        node.addMixin(mixVersionable);
        node.setProperty(propertyName1, "foo");
        superuser.save();

        VersionManager vm = superuser.getWorkspace().getVersionManager();
        vm.checkin(node.getPath());

        // re-create node
        node.remove();
        node = testRootNode.addNode(nodeName1, ntUnstructured);
        node.addMixin(mixVersionable);

        superuser.save();
    }

    // Oak-1272
    public void testRecreateVersionableNodeWithChangedChild() throws Exception {
        Node node = testRootNode.addNode(nodeName1, ntUnstructured);
        node.addMixin(mixVersionable);
        node.addNode(nodeName2, ntUnstructured).setProperty(propertyName1, "foo");
        superuser.save();

        VersionManager vm = superuser.getWorkspace().getVersionManager();
        vm.checkin(node.getPath());

        // re-create node
        node.remove();
        node = testRootNode.addNode(nodeName1, ntUnstructured);
        node.addMixin(mixVersionable);
        node.addNode(nodeName2, ntUnstructured).setProperty(propertyName1, "bar");

        superuser.save();
    }

    // Oak-1272
    public void testRecreateVersionableNodeWithRemovedChild() throws Exception {
        Node node = testRootNode.addNode(nodeName1, ntUnstructured);
        node.addMixin(mixVersionable);
        node.addNode(nodeName2, ntUnstructured).setProperty(propertyName1, "foo");
        superuser.save();

        VersionManager vm = superuser.getWorkspace().getVersionManager();
        vm.checkin(node.getPath());

        // re-create node
        node.remove();
        node = testRootNode.addNode(nodeName1, ntUnstructured);
        node.addMixin(mixVersionable);

        superuser.save();
    }

    // Oak-1272
    public void testRecreateVersionableNodeWithAddedChild() throws Exception {
        Node node = testRootNode.addNode(nodeName1, ntUnstructured);
        node.addMixin(mixVersionable);
        superuser.save();

        VersionManager vm = superuser.getWorkspace().getVersionManager();
        vm.checkin(node.getPath());

        // re-create node
        node.remove();
        node = testRootNode.addNode(nodeName1, ntUnstructured);
        node.addMixin(mixVersionable);
        node.addNode(nodeName2, ntUnstructured).setProperty(propertyName1, "bar");

        superuser.save();
    }

    // OAK-5193
    public void testSuccessorsPredecessorsMergedOnRemove() throws Exception {
        Node node = testRootNode.addNode(nodeName1, ntUnstructured);
        node.addMixin(mixVersionable);
        superuser.save();

        VersionManager vm = superuser.getWorkspace().getVersionManager();
        VersionHistory history = vm.getVersionHistory(node.getPath());

        vm.checkpoint(node.getPath()); // 1.0
        Version v11 = vm.checkpoint(node.getPath());
        vm.checkpoint(node.getPath()); // 1.2
        vm.checkpoint(node.getPath()); // 1.3
        vm.restore(v11, true);
        vm.checkpoint(node.getPath()); // 1.1
        vm.checkpoint(node.getPath()); // 1.1.0
        assertSuccessors(history, of("1.1.0", "1.2"), "1.1");
        vm.checkpoint(node.getPath()); // 1.1.1

        history.removeVersion("1.2");
        assertSuccessors(history, of("1.1.0", "1.3"), "1.1");
    }

    private static void assertSuccessors(VersionHistory history, Set<String> expectedSuccessors, String versionName) throws RepositoryException {
        assertEquals(expectedSuccessors, getNames(history.getVersion(versionName).getSuccessors()));
    }

    private static Set<String> getNames(Version[] versions) {
        return newHashSet(transform(asList(versions), new Function<Version, String>() {
            @Nullable
            @Override
            public String apply(@Nullable Version input) {
                try {
                    return input.getName();
                } catch (RepositoryException e) {
                    return null;
                }
            }
        }));
    }

}
