/*
 * Created by IntelliJ IDEA.
 * User: Mike
 * Date: Feb 19, 2004
 * Time: 3:19:02 PM
 */
package com.atlassian.confluence.rpc.soap.services;

import com.atlassian.confluence.links.LinkManager;
import com.atlassian.confluence.links.OutgoingLink;
import com.atlassian.confluence.pages.Page;
import com.atlassian.confluence.pages.PageManager;
import com.atlassian.confluence.rpc.RemoteException;
import com.atlassian.confluence.rpc.soap.AbstractSoapTestCase;
import com.atlassian.confluence.security.Permission;
import com.atlassian.confluence.security.PermissionManager;
import com.atlassian.confluence.spaces.Space;
import com.atlassian.confluence.spaces.SpaceManager;
import com.atlassian.confluence.user.AuthenticatedUserThreadLocal;
import com.atlassian.user.User;
import com.atlassian.user.UserManager;
import com.atlassian.user.impl.memory.MemoryUserManager;
import com.atlassian.user.impl.memory.provider.MemoryProvider;
import com.atlassian.user.impl.osuser.security.password.OSUPasswordEncryptor;
import com.atlassian.user.repository.DefaultRepository;
import com.atlassian.user.security.password.PasswordEncryptor;
import com.mockobjects.constraint.Constraint;
import com.mockobjects.dynamic.C;
import com.mockobjects.dynamic.FullConstraintMatcher;
import com.mockobjects.dynamic.Mock;

import java.util.ArrayList;
import java.util.List;

public class TestSoapServiceHelperImpl extends AbstractSoapTestCase
{
    private User user;
    private SoapServiceHelperImpl helper;
    private Mock mockSpaceManager;
    private Mock mockPageManager;
    private Mock mockLinkManager;

    public void setUp() throws Exception
    {
        super.setUp();
        helper = new SoapServiceHelperImpl();
        PasswordEncryptor encryptor = new OSUPasswordEncryptor();
        UserManager um = new MemoryUserManager(new DefaultRepository(), new MemoryProvider(), encryptor);
        user = um.createUser("bob");
        AuthenticatedUserThreadLocal.setUser(user);

        // setup mock objects
        mockSpaceManager = new Mock(SpaceManager.class);
        helper.setSpaceManager((SpaceManager) mockSpaceManager.proxy());

        mockPageManager = new Mock(PageManager.class);
        helper.setPageManager((PageManager) mockPageManager.proxy());

        mockLinkManager = new Mock(LinkManager.class);
        helper.setLinkManager((LinkManager) mockLinkManager.proxy());

        helper.setPermissionManager((PermissionManager) mockPermissionManager.proxy());
    }

    public void tearDown() throws Exception
    {
        super.tearDown();
        
        AuthenticatedUserThreadLocal.setUser(null);
    }

    private void verifyMocks()
    {
        mockSpaceManager.verify();
        mockPermissionManager.verify();
        mockPageManager.verify();
        mockLinkManager.verify();
    }

    public void testRetrieveNonExistantSpace() throws Exception
    {
        mockSpaceManager.matchAndReturn("getSpace", C.args(C.eq("foo")), null);
        mockPermissionManager.matchAndReturn("hasPermission", C.args(C.eq(user), C.eq(Permission.VIEW), C.IS_NULL), false);

        try
        {
            helper.retrieveSpace("foo");
            fail("Should have thrown exception.");
        }
        catch (RemoteException e)
        {
        }

        verifyMocks();
    }

    public void testRetrieveSpaceNoBrowsePermission() throws Exception
    {
        Space space = makeSpace("FRUIT");
        mockSpaceManager.expectAndReturn("getSpace", C.args(C.eq("FRUIT")), space);
        mockPermissionManager.expectAndReturn("hasPermission", C.args(C.eq(user), C.eq(Permission.VIEW), C.eq(space)), false);
        try
        {
            helper.retrieveSpace("FRUIT");
            fail("Should have thrown exception.");
        }
        catch (RemoteException e)
        {
        }
        verifyMocks();
    }

    public void testRetrieveSpaceSuccessfully() throws Exception
    {
        Space space = makeSpace("FRUIT");
        mockSpaceManager.expectAndReturn("getSpace", C.args(C.eq("FRUIT")), space);
        mockPermissionManager.expectAndReturn("hasPermission", C.args(C.eq(user), C.eq(Permission.VIEW), C.eq(space)), true);

        assertEquals(space, helper.retrieveSpace("FRUIT"));
        verifyMocks();
    }

    public void testCanModifyAssertionWorks() throws RemoteException
    {
        Space space = makeSpace("FRUIT");

        // can't modify
        mockPermissionManager.expectAndReturn("hasPermission", C.args(C.eq(user), C.eq(Permission.VIEW), C.eq(space)), false);
        try
        {
            helper.assertCanCreatePage(space);
            fail("Should have thrown exception.");
        }
        catch (RemoteException e)
        {
        }

        // can modify
        mockPermissionManager.expectAndReturn("hasPermission", C.args(C.eq(user), C.eq(Permission.VIEW), C.eq(space)), true);
        mockPermissionManager.expectAndReturn("hasCreatePermission", C.args(C.eq(user), C.eq(space), C.eq(Page.class)), true);
        helper.assertCanCreatePage(space);

        verifyMocks();
    }

    public void testCanAdministrationWorks() throws RemoteException
    {
        // can't modify
        mockPermissionManager.expectAndReturn("hasPermission", C.args(C.eq(user), C.eq(Permission.ADMINISTER), C.eq(PermissionManager.TARGET_APPLICATION)), false);
        try
        {
            helper.assertCanAdministrate();
            fail("Should have thrown exception.");
        }
        catch (RemoteException e)
        {
        }

        // can modify
        mockPermissionManager.expectAndReturn("hasPermission", C.args(C.eq(user), C.eq(Permission.ADMINISTER), C.eq(PermissionManager.TARGET_APPLICATION)), true);
        helper.assertCanAdministrate();
        verifyMocks();
    }

    public void testRetrieveNonExistantPage() throws Exception
    {
        mockPageManager.expectAndReturn("getAbstractPage", C.args(C.eq(10L)), null);
        mockPermissionManager.matchAndReturn("hasPermission", C.args(C.eq(user), C.eq(Permission.VIEW), C.IS_NULL), false);
        try
        {
            helper.retrieveAbstractPage(10);
            fail("Should have thrown exception.");
        }
        catch (RemoteException e)
        {
        }

        verifyMocks();
    }

    public void testRetrievePageNoBrowsePermission() throws Exception
    {
        Space space = makeSpace("FRUIT");
        Page page = makePage(space, 10, "apples");
        mockPageManager.expectAndReturn("getAbstractPage", C.args(C.eq(10L)), page);
        mockPermissionManager.expectAndReturn("hasPermission", C.args(C.eq(user), C.eq(Permission.VIEW), C.eq(page)), false);
        try
        {
            helper.retrieveAbstractPage(10);
            fail("Should have thrown exception.");
        }
        catch (RemoteException e)
        {
        }
        verifyMocks();
    }

    public void testRetrievePageSuccessfully() throws Exception
    {
        Space space = makeSpace("FRUIT");
        Page page = makePage(space, 10, "apples");
        mockPageManager.expectAndReturn("getAbstractPage", C.args(C.eq(10L)), page);
        mockPermissionManager.expectAndReturn("hasPermission", C.args(C.eq(user), C.eq(Permission.VIEW), C.eq(page)), true);
        assertEquals(page, helper.retrieveAbstractPage(10));
        verifyMocks();
    }

    public void testRenamePage() throws Exception
    {
        Space space = makeSpace("FRUIT");
        Page page = makePage(space, 10, "apples");
        Page page2 = makePage(space, 15, "pears");
        Page page3 = makePage(space, 20, "oranges");
        List links = new ArrayList();
        links.add(new OutgoingLink(page2, "FRUIT", "apples"));
        links.add(new OutgoingLink(page3, "FRUIT", "apples"));
        // ContentEntityObject srcContent, String existingSpaceKey, String existingPageTitle, String newSpaceKey, String newPageTitle
        mockPageManager.expect("renamePage", C.args(C.eq(page), C.eq("bananas")));
        mockLinkManager.expectAndReturn("getIncomingLinksToContent", page, links);
        mockLinkManager.expect("getContentWithRenamedLinks", new FullConstraintMatcher(new Constraint[] {
            C.eq(page2), C.eq(page), C.eq("FRUIT"), C.eq("bananas")}));
        mockPageManager.expect("saveContentEntity", C.args(C.eq(page2), C.eq(page2.clone()), C.IS_NULL ));
        mockLinkManager.expect("getContentWithRenamedLinks", new FullConstraintMatcher(new Constraint[] {
            C.eq(page3), C.eq(page), C.eq("FRUIT"), C.eq("bananas")}));
        mockPageManager.expect("saveContentEntity", C.args(C.eq(page3), C.eq(page3.clone()), C.IS_NULL ));

        helper.renamePage(page, "bananas");
        verifyMocks();
    }

}