package org.exoplatform.platform.component.organization.test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import javax.jcr.Session;

import org.exoplatform.commons.utils.ListAccess;
import org.exoplatform.container.PortalContainer;
import org.exoplatform.container.component.ComponentRequestLifecycle;
import org.exoplatform.platform.organization.integration.EventType;
import org.exoplatform.platform.organization.integration.NewGroupListener;
import org.exoplatform.platform.organization.integration.NewMembershipListener;
import org.exoplatform.platform.organization.integration.NewProfileListener;
import org.exoplatform.platform.organization.integration.NewUserListener;
import org.exoplatform.platform.organization.integration.OrganizationIntegrationService;
import org.exoplatform.platform.organization.integration.Util;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.organization.Group;
import org.exoplatform.services.organization.Membership;
import org.exoplatform.services.organization.OrganizationService;
import org.exoplatform.services.organization.User;
import org.exoplatform.services.organization.UserProfile;
import org.exoplatform.services.organization.impl.MembershipImpl;
import org.exoplatform.test.BasicTestCase;

public class TestOrganizationIntegration extends BasicTestCase {
  PortalContainer container = null;
  RepositoryService repositoryService = null;
  OrganizationService organizationService = null;

  @Override
  protected void setUp() throws Exception {
    container = PortalContainer.getInstance();
    repositoryService = (RepositoryService) container.getComponentInstanceOfType(RepositoryService.class);
    organizationService = (OrganizationService) container.getComponentInstanceOfType(OrganizationService.class);
  }


    public void testIntegrationService() throws Exception {
        OrganizationIntegrationService organizationIntegrationService = container.createComponent(OrganizationIntegrationService.class);
        container.registerComponentInstance(organizationIntegrationService);
        assertNotNull(organizationIntegrationService);
        NewUserListener userListener = container.createComponent(NewUserListener.class);
        assertNotNull(userListener);
        organizationIntegrationService.addListenerPlugin(userListener);
        NewProfileListener profileListener = container.createComponent(NewProfileListener.class);
        assertNotNull(profileListener);
        organizationIntegrationService.addListenerPlugin(profileListener);
        NewMembershipListener membershipListener = container.createComponent(NewMembershipListener.class);
        assertNotNull(membershipListener);
        organizationIntegrationService.addListenerPlugin(membershipListener);
        NewGroupListener groupListener = container.createComponent(NewGroupListener.class);
        assertNotNull(groupListener);
        organizationIntegrationService.addListenerPlugin(groupListener);

    }
   /**
  public void testIntegrationService() throws Exception {
        verifyFoldersCreation(false);

        OrganizationIntegrationService organizationIntegrationService = container
                .createComponent(OrganizationIntegrationService.class);
        container.registerComponentInstance(organizationIntegrationService);

        NewUserListener userListener = container.createComponent(NewUserListener.class);
        organizationIntegrationService.addListenerPlugin(userListener);
        NewProfileListener profileListener = container.createComponent(NewProfileListener.class);
        organizationIntegrationService.addListenerPlugin(profileListener);
        NewMembershipListener membershipListener = container.createComponent(NewMembershipListener.class);
        organizationIntegrationService.addListenerPlugin(membershipListener);
        NewGroupListener groupListener = container.createComponent(NewGroupListener.class);
        organizationIntegrationService.addListenerPlugin(groupListener);

        Session session = null;
        try {
            session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
            organizationIntegrationService.syncGroup("/organization/management/executive-board", EventType.ADDED.toString());
            organizationIntegrationService.syncGroup("/organization/management/executive-board", EventType.DELETED.toString());

            assertTrue(Util.hasGroupFolder(session, "/organization"));
            assertTrue(Util.hasGroupFolder(session, "/organization/management"));
            assertTrue(Util.hasGroupFolder(session, "/organization/management/executive-board"));

            organizationIntegrationService.syncAllGroups(EventType.DELETED.toString());

            assertTrue(Util.hasGroupFolder(session, "/organization"));
            assertTrue(Util.hasGroupFolder(session, "/organization/management"));
            assertTrue(Util.hasGroupFolder(session, "/organization/management/executive-board"));

            organizationIntegrationService.syncUser("root", EventType.ADDED.toString());

            verifyUserFoldersCreation("root", true);

            organizationIntegrationService.syncUser("root", EventType.DELETED.toString());

            verifyUserFoldersCreation("root", true);

            deleteMembership("member:root:/organization/management/executive-board");
            verifyMembershipFoldersCreation("root", "/organization/management/executive-board", "member", true);
            organizationIntegrationService.syncMembership("root", "/organization/management/executive-board",
                    EventType.DELETED.toString());
            verifyMembershipFoldersCreation("root", "/organization/management/executive-board", "member", false);

            deleteUser("root");
            organizationIntegrationService.syncUser("root", EventType.DELETED.toString());

            verifyUserFoldersCreation("root", false);

            deleteGroup("/organization");
            organizationIntegrationService.syncGroup("/organization", EventType.DELETED.toString());

            assertFalse(Util.hasGroupFolder(session, "/organization"));
            assertFalse(Util.hasGroupFolder(session, "/organization/management"));
            assertFalse(Util.hasGroupFolder(session, "/organization/management/executive-board"));

            MembershipImpl membership = new MembershipImpl();
            {
                membership.setMembershipType("manager");
                membership.setUserName("john");
                membership.setGroupId("/organization/management/executive-board");
                membership.setId(Util.computeId(membership));

                assertFalse(Util.hasMembershipFolder(session, membership));
            }

            organizationIntegrationService.syncAll();
            verifyFoldersCreation(true);

            if (organizationService instanceof ComponentRequestLifecycle) {
                ((ComponentRequestLifecycle) organizationService).startRequest(container);
            }
            @SuppressWarnings("unchecked")
            List<Group> groups = new ArrayList<Group>(organizationService.getGroupHandler().getAllGroups());
            Collections.sort(groups, OrganizationIntegrationService.GROUP_COMPARATOR);
            Collections.reverse(groups);

            for (Group group : groups) {
                organizationService.getGroupHandler().removeGroup(group, true);
            }

            ListAccess<User> usersListAccess = organizationService.getUserHandler().findAllUsers();
            int i = 0;
            while (i <= usersListAccess.getSize()) {
                int length = i + 10 <= usersListAccess.getSize() ? 10 : usersListAccess.getSize() - i;
                User[] users = usersListAccess.load(i, length);
                for (User user : users) {
                    organizationService.getUserHandler().removeUser(user.getUserName(), true);
                }
                i += 10;
            }

            if (organizationService instanceof ComponentRequestLifecycle) {
                ((ComponentRequestLifecycle) organizationService).endRequest(container);
            }
            organizationIntegrationService.syncAll();

            assertFalse(Util.getGroupsFolder(session).hasNodes());
            assertFalse(Util.getMembershipsFolder(session).hasNodes());
            assertFalse(Util.getUsersFolder(session).hasNodes());
            assertFalse(Util.getProfilesFolder(session).hasNodes());
        } finally {
            if (session != null) {
                session.logout();
            }
        }
    }
    */

  private void deleteMembership(String membershipId) throws Exception {
    if (organizationService instanceof ComponentRequestLifecycle) {
      ((ComponentRequestLifecycle) organizationService).startRequest(container);
    }
    organizationService.getMembershipHandler().removeMembership(membershipId, true);
    if (organizationService instanceof ComponentRequestLifecycle) {
      ((ComponentRequestLifecycle) organizationService).endRequest(container);
    }
  }

  private void deleteUser(String username) throws Exception {
    if (organizationService instanceof ComponentRequestLifecycle) {
      ((ComponentRequestLifecycle) organizationService).startRequest(container);
    }
    organizationService.getUserHandler().removeUser(username, true);
    if (organizationService instanceof ComponentRequestLifecycle) {
      ((ComponentRequestLifecycle) organizationService).endRequest(container);
    }
  }

  private void deleteGroup(String groupId) throws Exception {
    if (organizationService instanceof ComponentRequestLifecycle) {
      ((ComponentRequestLifecycle) organizationService).startRequest(container);
    }
    organizationService.getGroupHandler().removeGroup(organizationService.getGroupHandler().findGroupById(groupId), true);
    if (organizationService instanceof ComponentRequestLifecycle) {
      ((ComponentRequestLifecycle) organizationService).endRequest(container);
    }
  }

  private void verifyUserFoldersCreation(String username, boolean creationAssertionValue) throws Exception {
    Session session = null;
    try {
      session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
      if (organizationService instanceof ComponentRequestLifecycle) {
        ((ComponentRequestLifecycle) organizationService).startRequest(container);
      }
      assertEquals(creationAssertionValue, Util.hasUserFolder(session, username));
      assertEquals(creationAssertionValue, Util.hasProfileFolder(session, username));

      Collection<?> memberships = organizationService.getMembershipHandler().findMembershipsByUser(username);
      if (creationAssertionValue) {// Related groups has to be
                                   // integrated/added, but when deleting
                                   // user, the group could still exists

        for (Object objectMembership : memberships) {
          assertEquals(creationAssertionValue, Util.hasMembershipFolder(session, (Membership) objectMembership));
        }

        @SuppressWarnings("unchecked")
        List<Group> groups = new ArrayList<Group>(organizationService.getGroupHandler().findGroupsOfUser(username));
        Collections.sort(groups, OrganizationIntegrationService.GROUP_COMPARATOR);
        for (Group group : groups) {
          assertEquals(creationAssertionValue, Util.hasGroupFolder(session, group.getId()));
        }
      } else {
        assertTrue(memberships == null || memberships.isEmpty());
      }
      if (organizationService instanceof ComponentRequestLifecycle) {
        ((ComponentRequestLifecycle) organizationService).endRequest(container);
      }
    } finally {
      if (session != null) {
        session.logout();
      }
    }
  }

  private void verifyFoldersCreation(boolean creationAssertionValue) throws Exception {
    Session session = null;
    try {
      session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
      if (organizationService instanceof ComponentRequestLifecycle) {
        ((ComponentRequestLifecycle) organizationService).startRequest(container);
      }
      ListAccess<User> usersListAccess = organizationService.getUserHandler().findAllUsers();
      int i = 0;
      while (i <= usersListAccess.getSize()) {
        int length = i + 10 <= usersListAccess.getSize() ? 10 : usersListAccess.getSize() - i;
        User[] users = usersListAccess.load(i, length);
        for (User user : users) {
          assertEquals(creationAssertionValue, Util.hasUserFolder(session, user.getUserName()));
          UserProfile profile = organizationService.getUserProfileHandler().findUserProfileByName(user.getUserName());
          assertEquals(creationAssertionValue, Util.hasProfileFolder(session, profile.getUserName()));
          Collection<?> memberships = organizationService.getMembershipHandler().findMembershipsByUser(user.getUserName());
          for (Object objectMembership : memberships) {
            assertEquals(creationAssertionValue, Util.hasMembershipFolder(session, (Membership) objectMembership));
          }
        }
        i += 10;
      }
      @SuppressWarnings("unchecked")
      List<Group> groups = new ArrayList<Group>(organizationService.getGroupHandler().getAllGroups());
      Collections.sort(groups, OrganizationIntegrationService.GROUP_COMPARATOR);
      for (Group group : groups) {
        assertEquals(creationAssertionValue, Util.hasGroupFolder(session, group.getId()));
      }
      if (organizationService instanceof ComponentRequestLifecycle) {
        ((ComponentRequestLifecycle) organizationService).endRequest(container);
      }
    } finally {
      if (session != null) {
        session.logout();
      }
    }
  }

  private void verifyMembershipFoldersCreation(String username, String groupId, String membershipType, boolean assertionCondition)
      throws Exception {
    Session session = null;
    try {
      session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
      MembershipImpl membership = new MembershipImpl();
      {
        membership.setMembershipType(membershipType);
        membership.setUserName(username);
        membership.setGroupId(groupId);
        membership.setId(Util.computeId(membership));
      }
      assertEquals(assertionCondition, Util.hasMembershipFolder(session, membership));
      session.save();
    } finally {
      if (session != null) {
        session.logout();
      }
    }
  }
}
