package com.atlassian.stash.internal.crowd;

import com.atlassian.beehive.ClusterLockService;
import com.atlassian.crowd.dao.application.ApplicationDAO;
import com.atlassian.crowd.directory.loader.DirectoryInstanceLoader;
import com.atlassian.crowd.embedded.api.PasswordCredential;
import com.atlassian.crowd.embedded.spi.DirectoryDao;
import com.atlassian.crowd.exception.*;
import com.atlassian.crowd.manager.directory.BeforeGroupRemoval;
import com.atlassian.crowd.manager.directory.DirectorySynchroniser;
import com.atlassian.crowd.manager.directory.SynchronisationStatusManager;
import com.atlassian.crowd.manager.directory.monitor.poller.DirectoryPollerManager;
import com.atlassian.crowd.manager.permission.PermissionManager;
import com.atlassian.crowd.manager.recovery.RecoveryModeAwareDirectoryManager;
import com.atlassian.crowd.manager.recovery.RecoveryModeService;
import com.atlassian.crowd.model.user.User;
import com.atlassian.event.api.EventPublisher;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * Override of Crowd's {@link RecoveryModeAwareDirectoryManager} that does not create a transaction around user
 * authentication. Crowd authentication may involve a remote call which could keep a transaction open for up to
 * 2 minutes if there are network issues or the remote Crowd/LDAP instance is under heavy load or malfunctioning.
 * Instead of a single transaction at a high level, multiple small transactions will be created when interacting with
 * the database.
 *
 * @since 3.4
 */
public class CustomizedDirectoryManager extends RecoveryModeAwareDirectoryManager {

    public CustomizedDirectoryManager(DirectoryDao directoryDao, ApplicationDAO applicationDAO,
                                      EventPublisher eventPublisher, PermissionManager permissionManager,
                                      DirectoryInstanceLoader directoryInstanceLoader,
                                      DirectorySynchroniser directorySynchroniser,
                                      DirectoryPollerManager directoryPollerManager,
                                      ClusterLockService clusterLockService,
                                      SynchronisationStatusManager synchronisationStatusManager,
                                      BeforeGroupRemoval beforeGroupRemoval,
                                      RecoveryModeService recoveryModeService) {

        super(directoryDao, applicationDAO, eventPublisher, permissionManager, directoryInstanceLoader,
                directorySynchroniser, directoryPollerManager, clusterLockService, synchronisationStatusManager,
                beforeGroupRemoval, recoveryModeService);
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public User authenticateUser(long directoryId, String username, PasswordCredential passwordCredential)
            throws OperationFailedException, InactiveAccountException, InvalidAuthenticationException,
            ExpiredCredentialException, DirectoryNotFoundException, UserNotFoundException {

        return super.authenticateUser(directoryId, username, passwordCredential);
    }
}
