package org.ovirt.engine.core.bll.utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import javax.inject.Singleton;

import org.ovirt.engine.core.bll.Backend;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterGeoRepNonEligibilityReason;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterGeoRepSession;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterStatus;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeEntity;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
import org.ovirt.engine.core.common.vdscommands.VDSReturnValue;
import org.ovirt.engine.core.common.vdscommands.gluster.GlusterVolumeVDSParameters;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
import org.ovirt.engine.core.dao.VdsGroupDao;
import org.ovirt.engine.core.dao.gluster.GlusterGeoRepDao;

@Singleton
public class GlusterGeoRepUtil {

    public Map<GlusterGeoRepNonEligibilityReason, Predicate<GlusterVolumeEntity>> getEligibilityPredicates(final GlusterVolumeEntity masterVolume) {
        Map<GlusterGeoRepNonEligibilityReason, Predicate<GlusterVolumeEntity>> eligibilityPredicates = new HashMap<>();
        final List<Guid> existingSessionSlavesIds = getSessionSlaveVolumeIds();


        eligibilityPredicates.put(GlusterGeoRepNonEligibilityReason.SLAVE_VOLUME_SHOULD_BE_UP, slaveVolume -> slaveVolume.getStatus() == GlusterStatus.UP);

        eligibilityPredicates.put(GlusterGeoRepNonEligibilityReason.SLAVE_AND_MASTER_VOLUMES_SHOULD_NOT_BE_IN_SAME_CLUSTER, slaveVolume -> ! masterVolume.getClusterId().equals(slaveVolume.getClusterId()));

        final Predicate<GlusterVolumeEntity> nonNullSlaveSizePredicate = slaveVolume -> slaveVolume.getAdvancedDetails().getCapacityInfo() != null;
        eligibilityPredicates.put(GlusterGeoRepNonEligibilityReason.SLAVE_VOLUME_SIZE_TO_BE_AVAILABLE, nonNullSlaveSizePredicate);

        final Predicate<GlusterVolumeEntity> nonNullMasterSizePredicate = slaveVolume -> masterVolume.getAdvancedDetails().getCapacityInfo() != null;
        eligibilityPredicates.put(GlusterGeoRepNonEligibilityReason.MASTER_VOLUME_SIZE_TO_BE_AVAILABLE, nonNullMasterSizePredicate);

        Predicate<GlusterVolumeEntity> masterSlaveSizePredicate = slaveVolume -> {
            boolean eligible = nonNullSlaveSizePredicate.test(slaveVolume) && nonNullMasterSizePredicate.test(masterVolume);
            if (eligible) {
                eligible = slaveVolume.getAdvancedDetails().getCapacityInfo().getTotalSize() >= masterVolume.getAdvancedDetails().getCapacityInfo().getTotalSize();
            }
            return eligible;
        };
        eligibilityPredicates.put(GlusterGeoRepNonEligibilityReason.SLAVE_VOLUME_SIZE_SHOULD_BE_GREATER_THAN_MASTER_VOLUME_SIZE, masterSlaveSizePredicate);

        eligibilityPredicates.put(GlusterGeoRepNonEligibilityReason.SLAVE_VOLUME_SHOULD_NOT_BE_SLAVE_OF_ANOTHER_GEO_REP_SESSION, slaveVolume -> !existingSessionSlavesIds.contains(slaveVolume.getId()));

        eligibilityPredicates.put(GlusterGeoRepNonEligibilityReason.SLAVE_CLUSTER_AND_MASTER_CLUSTER_COMPATIBILITY_VERSIONS_DO_NOT_MATCH, slaveVolume -> {
            VdsGroupDao vdsGroupDao = getVdsGroupDao();
            Version slaveCompatibilityVersion = vdsGroupDao.get(slaveVolume.getClusterId()).getCompatibilityVersion();
            Version masterCompatibilityVersion = vdsGroupDao.get(masterVolume.getClusterId()).getCompatibilityVersion();
            return masterCompatibilityVersion.equals(slaveCompatibilityVersion);
        });

        eligibilityPredicates.put(GlusterGeoRepNonEligibilityReason.NO_UP_SLAVE_SERVER,
                slaveVolume -> {
                    Guid slaveUpserverId = getUpServerId(slaveVolume.getClusterId());
                    if (slaveUpserverId == null) {
                        return false;
                    }
                    return true;
                });

        eligibilityPredicates.put(GlusterGeoRepNonEligibilityReason.SLAVE_VOLUME_TO_BE_EMPTY,
                slaveVolume -> {
                    Guid slaveUpserverId = getUpServerId(slaveVolume.getClusterId());
                    if(slaveUpserverId == null) {
                        return false;
                    }
                    return checkEmptyGlusterVolume(slaveUpserverId, slaveVolume.getName());
                });

        return eligibilityPredicates;
    }

    private List<Guid> getSessionSlaveVolumeIds() {
        List<GlusterGeoRepSession> existingSessions = getGeoRepDao().getAllSessions();
        List<Guid> sessionSlavesIds = new ArrayList<>();
        for(GlusterGeoRepSession currentSession : existingSessions) {
            sessionSlavesIds.add(currentSession.getSlaveVolumeId());
        }
        return sessionSlavesIds;
    }

    public boolean checkEmptyGlusterVolume(Guid slaveUpserverId, String slaveVolumeName) {
        VDSReturnValue returnValue =
                Backend.getInstance()
                        .getResourceManager()
                        .RunVdsCommand(VDSCommandType.CheckEmptyGlusterVolume,
                                new GlusterVolumeVDSParameters(slaveUpserverId, slaveVolumeName));
        if (!returnValue.getSucceeded()) {
            return false;
        }
        return (boolean) returnValue.getReturnValue();
    }

    public Guid getUpServerId(Guid clusterId) {
        VDS randomUpServer = ClusterUtils.getInstance().getRandomUpServer(clusterId);
        return randomUpServer == null ? null : randomUpServer.getId();
    }

    public VdsGroupDao getVdsGroupDao() {
        return DbFacade.getInstance().getVdsGroupDao();
    }

    public GlusterGeoRepDao getGeoRepDao() {
        return DbFacade.getInstance().getGlusterGeoRepDao();
    }
}

@@ -4008,20 +4008,23 @@
         
-if (
+return 
 slaveUps
@@ -4035,110 +4035,15 @@
 rId 
-=
+!
 = null
-) %7B%0A                        return false;%0A                    %7D%0A                    return true
 ;%0A  
@@ -4298,11 +4298,15 @@
     
-if(
+return 
 slav
@@ -4321,105 +4321,18 @@
 rId 
-=
+!
 = null
-) %7B%0A                        return false;%0A                    %7D%0A                    return
+ &&
  che
@@ -5246,13 +5246,15 @@
     
-if (!
+return 
 retu
@@ -5279,62 +5279,11 @@
 ed()
-) %7B%0A            return false;%0A        %7D%0A        return
+ &&
  (bo

Simplify GlusterGeoRepUtil conditionals