package com.atlassian.stash.internal.crowd;

import com.atlassian.crowd.embedded.api.*;
import com.atlassian.crowd.exception.ApplicationNotFoundException;
import com.atlassian.crowd.exception.DirectoryCurrentlySynchronisingException;
import com.atlassian.crowd.exception.DirectoryNotFoundException;
import com.atlassian.crowd.exception.runtime.OperationFailedException;
import com.atlassian.crowd.manager.application.ApplicationManager;
import com.atlassian.crowd.manager.application.ApplicationManagerException;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

public class CustomizedCrowdDirectoryService implements CrowdDirectoryService {

    private final CrowdDirectoryService crowdDirectoryService;
    private final ApplicationManager applicationManager;
    private final ApplicationFactory applicationFactory;

    public CustomizedCrowdDirectoryService(CrowdDirectoryService crowdDirectoryService,
                                           ApplicationManager applicationManager, ApplicationFactory applicationFactory) {
        this.crowdDirectoryService = crowdDirectoryService;
        this.applicationFactory = applicationFactory;
        this.applicationManager = applicationManager;
    }

    @Transactional
    @Override
    public Directory addDirectory(Directory directory) throws OperationFailedException {
        Directory addedDirectory = crowdDirectoryService.addDirectory(directory);

        // set up the directoryMapping
        try {
            applicationManager.addDirectoryMapping(applicationFactory.getApplication(), addedDirectory, true, OperationType.values());
        } catch (ApplicationNotFoundException | DirectoryNotFoundException e) {
            throw new OperationFailedException(e);
        }
        return addedDirectory;
    }

    @Override
    public void testConnection(Directory directory) throws OperationFailedException {
        crowdDirectoryService.testConnection(directory);
    }

    @Override
    public List<Directory> findAllDirectories() {
        return crowdDirectoryService.findAllDirectories();
    }

    @Override
    public Directory findDirectoryById(long directoryId) {
        return crowdDirectoryService.findDirectoryById(directoryId);
    }

    @Override
    public Directory updateDirectory(Directory directory) throws OperationFailedException {
        return crowdDirectoryService.updateDirectory(directory);
    }

    @Override
    public void setDirectoryPosition(long directoryId, int position) throws OperationFailedException {
        crowdDirectoryService.setDirectoryPosition(directoryId, position);
    }

    @Override
    @Transactional
    public boolean removeDirectory(long directoryId) throws DirectoryCurrentlySynchronisingException, OperationFailedException {
        Directory directory = crowdDirectoryService.findDirectoryById(directoryId);
        if (directory != null) {
            // also delete the directory mappings
            try {
                applicationManager.removeDirectoryFromApplication(directory, applicationFactory.getApplication());
            } catch (ApplicationManagerException e) {
                throw new OperationFailedException(e);
            }
            return crowdDirectoryService.removeDirectory(directoryId);
        }

        return false;
    }

    @Override
    public boolean supportsNestedGroups(long directoryId) throws OperationFailedException {
        return crowdDirectoryService.supportsNestedGroups(directoryId);
    }

    @Override
    public boolean isDirectorySynchronisable(long directoryId) throws OperationFailedException {
        return crowdDirectoryService.isDirectorySynchronisable(directoryId);
    }

    @Override
    public void synchroniseDirectory(long directoryId) throws OperationFailedException {
        crowdDirectoryService.synchroniseDirectory(directoryId);
    }

    @Override
    public void synchroniseDirectory(long directoryId, boolean runInBackground) throws OperationFailedException {
        crowdDirectoryService.synchroniseDirectory(directoryId, runInBackground);
    }

    @Override
    public boolean isDirectorySynchronising(long directoryId) throws OperationFailedException {
        return crowdDirectoryService.isDirectorySynchronising(directoryId);
    }

    @Override
    public DirectorySynchronisationInformation getDirectorySynchronisationInformation(long directoryId) throws OperationFailedException {
        return crowdDirectoryService.getDirectorySynchronisationInformation(directoryId);
    }

    @Override
    public void setConnectionPoolProperties(ConnectionPoolProperties poolProperties) {
        crowdDirectoryService.setConnectionPoolProperties(poolProperties);
    }

    @Override
    public ConnectionPoolProperties getStoredConnectionPoolProperties() {
        return crowdDirectoryService.getStoredConnectionPoolProperties();
    }

    @Override
    public ConnectionPoolProperties getSystemConnectionPoolProperties() {
        return crowdDirectoryService.getSystemConnectionPoolProperties();
    }

    @Override
    public boolean isMembershipAggregationEnabled() {
        return crowdDirectoryService.isMembershipAggregationEnabled();
    }

    @Override
    public void setMembershipAggregationEnabled(boolean enabled) {
        crowdDirectoryService.setMembershipAggregationEnabled(enabled);
    }

}
