package org.ovirt.engine.core.bll.validator.storage;

import com.woorea.openstack.base.client.OpenStackResponseException;
import com.woorea.openstack.cinder.model.Limits;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;

import org.ovirt.engine.core.bll.ValidationResult;
import org.ovirt.engine.core.bll.provider.storage.OpenStackVolumeProviderProxy;
import org.ovirt.engine.core.common.businessentities.storage.CinderDisk;
import org.ovirt.engine.core.common.businessentities.storage.Disk;
import org.ovirt.engine.core.common.errors.VdcBllMessages;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
import org.ovirt.engine.core.dao.DiskDao;

public class CinderDisksValidator {

    private Iterable<CinderDisk> cinderDisks;

    private Map<Guid, OpenStackVolumeProviderProxy> diskProxyMap;

    public CinderDisksValidator(Iterable<CinderDisk> cinderDisks) {
        this.cinderDisks = cinderDisks;
        this.diskProxyMap = initializeVolumeProviderProxyMap();
    }

    public CinderDisksValidator(CinderDisk cinderDisk) {
        this(Collections.singleton(cinderDisk));
    }

    private ValidationResult validate(Callable<ValidationResult> callable) {
        try {
            return callable.call();
        } catch (OpenStackResponseException e) {
            return new ValidationResult(VdcBllMessages.ACTION_TYPE_FAILED_CINDER,
                    String.format("$cinderException %1$s", e.getMessage()));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public ValidationResult validateCinderDiskLimits() {
        return validate(new Callable<ValidationResult>() {
            @Override
            public ValidationResult call() {
                int diskIndex = 0;
                for (CinderDisk disk : cinderDisks) {
                    OpenStackVolumeProviderProxy proxy = diskProxyMap.get(disk.getId());
                    Limits limits = proxy.getLimits();
                    if (limits.getAbsolute().getTotalVolumesUsed() + diskIndex >= limits.getAbsolute().getMaxTotalVolumes()) {
                        return new ValidationResult(VdcBllMessages.CANNOT_ADD_CINDER_DISK_VOLUME_LIMIT_EXCEEDED,
                                String.format("$maxTotalVolumes %d", limits.getAbsolute().getMaxTotalVolumes()),
                                String.format("$diskAlias %s", disk.getDiskAlias()));
                    }
                    diskIndex++;
                }
                return ValidationResult.VALID;
            }
        });
    }

    public ValidationResult validateCinderDisksAlreadyRegistered() {
        return validate(new Callable<ValidationResult>() {
            @Override
            public ValidationResult call() {
                for (CinderDisk disk : cinderDisks) {
                    Disk diskFromDB = getDiskDao().get(disk.getId());
                    if (diskFromDB != null) {
                        return new ValidationResult(VdcBllMessages.CINDER_DISK_ALREADY_REGISTERED,
                                String.format("$diskAlias %s", diskFromDB.getDiskAlias()));
                    }
                }
                return ValidationResult.VALID;
            }
        });
    }

    private Map<Guid, OpenStackVolumeProviderProxy> initializeVolumeProviderProxyMap() {
        if (diskProxyMap == null) {
            diskProxyMap = new HashMap<>();
            for (CinderDisk cinderDisk : cinderDisks) {
                OpenStackVolumeProviderProxy volumeProviderProxy = getVolumeProviderProxy(cinderDisk);
                diskProxyMap.put(cinderDisk.getId(), volumeProviderProxy);
            }

        }
        return diskProxyMap;
    }

    private OpenStackVolumeProviderProxy getVolumeProviderProxy(CinderDisk cinderDisk) {
        if (cinderDisk == null || cinderDisk.getStorageIds().isEmpty()) {
            return null;
        }
        return OpenStackVolumeProviderProxy.getFromStorageDomainId(cinderDisk.getStorageIds().get(0));
    }

    protected DiskDao getDiskDao() {
        return DbFacade.getInstance().getDiskDao();
    }
}

@@ -165,16 +165,44 @@
 imits;%0A%0A
+import java.util.ArrayList;%0A
 import j
@@ -245,24 +245,47 @@
 il.HashMap;%0A
+import java.util.List;%0A
 import java.
@@ -2670,32 +2670,1161 @@
      %7D);%0A    %7D%0A%0A
+    private static class CinderStorageRelatedDisksAndProxy %7B%0A        private Guid storageDomainId;%0A        private List%3CCinderDisk%3E cinderDisks = new ArrayList%3C%3E();%0A        private OpenStackVolumeProviderProxy proxy;%0A%0A        public CinderStorageRelatedDisksAndProxy(Guid storageDomainId, List%3CCinderDisk%3E cinderDisks, OpenStackVolumeProviderProxy proxy) %7B%0A            setStorageDomainId(storageDomainId);%0A            setCinderDisks(cinderDisks);%0A            setProxy(proxy);%0A        %7D%0A%0A        public Guid getStorageDomainId() %7B%0A            return storageDomainId;%0A        %7D%0A%0A        public void setStorageDomainId(Guid storageDomainId) %7B%0A            this.storageDomainId = storageDomainId;%0A        %7D%0A%0A        public List%3CCinderDisk%3E getCinderDisks() %7B%0A            return cinderDisks;%0A        %7D%0A%0A        public void setCinderDisks(List%3CCinderDisk%3E cinderDisks) %7B%0A            this.cinderDisks = cinderDisks;%0A        %7D%0A%0A        public OpenStackVolumeProviderProxy getProxy() %7B%0A            return proxy;%0A        %7D%0A%0A        public void setProxy(OpenStackVolumeProviderProxy proxy) %7B%0A            this.proxy = proxy;%0A        %7D%0A    %7D%0A%0A
     public Valid

Introduce private class at Cinder validator.