package org.ovirt.engine.core.bll.network.dc;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.ovirt.engine.core.bll.LockIdNameAttribute;
import org.ovirt.engine.core.bll.LockMessagesMatchUtil;
import org.ovirt.engine.core.bll.ValidationResult;
import org.ovirt.engine.core.bll.network.cluster.NetworkHelper;
import org.ovirt.engine.core.bll.provider.ProviderValidator;
import org.ovirt.engine.core.bll.utils.PermissionSubject;
import org.ovirt.engine.core.bll.validator.NetworkValidator;
import org.ovirt.engine.core.common.AuditLogType;
import org.ovirt.engine.core.common.VdcObjectType;
import org.ovirt.engine.core.common.action.AddNetworkStoragePoolParameters;
import org.ovirt.engine.core.common.businessentities.network.Network;
import org.ovirt.engine.core.common.errors.VdcBllMessages;
import org.ovirt.engine.core.common.locks.LockingGroup;
import org.ovirt.engine.core.common.utils.Pair;
import org.ovirt.engine.core.common.validation.group.CreateEntity;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;

@LockIdNameAttribute
public class AddNetworkCommand<T extends AddNetworkStoragePoolParameters> extends NetworkCommon<T> {
    public AddNetworkCommand(T parameters) {
        super(parameters);
    }

    @Override
    protected void executeCommand() {
        getNetwork().setId(Guid.newGuid());
        getNetworkDAO().save(getNetwork());

        if (getNetwork().isVmNetwork() && getParameters().isVnicProfileRequired()) {
            getVnicProfileDao().save(NetworkHelper.createVnicProfile(getNetwork()));
        }

        NetworkHelper.addPermissionsOnNetwork(getCurrentUser().getId(), getNetwork().getId());
        getReturnValue().setActionReturnValue(getNetwork().getId());
        setSucceeded(true);
    }

    @Override
    protected void setActionMessageParameters() {
        super.setActionMessageParameters();
        addCanDoActionMessage(VdcBllMessages.VAR__ACTION__ADD);
    }

    @Override
    protected boolean canDoAction() {
        AddNetworkValidator validator = getNetworkValidator();
        return validate(validator.dataCenterExists())
                && validate(validator.vmNetworkSetCorrectly())
                && validate(validator.stpForVmNetworkOnly())
                && validate(validator.mtuValid())
                && validate(validator.networkPrefixValid())
                && validate(validator.networkNameNotUsed())
                && validate(validator.vlanIdNotUsed())
                && (!getNetwork().isExternal() || externalNetworkValid(validator));
    }

    protected AddNetworkValidator getNetworkValidator() {
        return new AddNetworkValidator(getNetwork());
    }

    private boolean externalNetworkValid(AddNetworkValidator validator) {
        ProviderValidator providerValidator =
                new ProviderValidator(getDbFacade().getProviderDao().get(getNetwork().getProvidedBy().getProviderId()));
        return validate(providerValidator.providerIsSet())
                && validate(validator.externalNetworkNewInDataCenter())
                && validate(validator.externalNetworkIsVmNetwork());
    }

    @Override
    public AuditLogType getAuditLogTypeValue() {
        return getSucceeded() ? AuditLogType.NETWORK_ADD_NETWORK : AuditLogType.NETWORK_ADD_NETWORK_FAILED;
    }

    @Override
    protected List<Class<?>> getValidationGroups() {
        addValidationGroup(CreateEntity.class);
        return super.getValidationGroups();
    }

    @Override
    public List<PermissionSubject> getPermissionCheckSubjects() {
        return Collections.singletonList(new PermissionSubject(getStoragePoolId(),
                VdcObjectType.StoragePool, getActionType().getActionGroup()));
    }

    @Override
    protected Map<String, Pair<String, String>> getExclusiveLocks() {
        if (getNetworkName() == null) {
            return null;
        }

        Map<String, Pair<String, String>> locks = Collections.singletonMap(
                getNetworkName(),
                LockMessagesMatchUtil.makeLockingPair(LockingGroup.NETWORK,
                        VdcBllMessages.ACTION_TYPE_FAILED_NETWORK_IS_USED));

        return locks;
    }

    protected static class AddNetworkValidator extends NetworkValidator {

        public AddNetworkValidator(Network network) {
            super(network);
        }

        @Override
        protected DbFacade getDbFacade() {
            return super.getDbFacade();
        }

        /**
         * @return An error iff the network represents an external network that already exists in the data center that
         *         the network should be on.
         */
        public ValidationResult externalNetworkNewInDataCenter() {
            for (Network otherNetwork : getNetworks()) {
                if (network.getProvidedBy().equals(otherNetwork.getProvidedBy())) {
                    return new ValidationResult(VdcBllMessages.ACTION_TYPE_FAILED_EXTERNAL_NETWORK_ALREADY_EXISTS);
                }
            }

            return ValidationResult.VALID;
        }

        /**
         * @return An error iff the network represents an external network is not a VM network, since we don't know how
         *         to handle non-VM external networks.
         */
        public ValidationResult externalNetworkIsVmNetwork() {
            return network.isVmNetwork() ? ValidationResult.VALID
                    : new ValidationResult(VdcBllMessages.ACTION_TYPE_FAILED_EXTERNAL_NETWORK_MUST_BE_VM_NETWORK);
        }
    }
}

@@ -226,16 +226,81 @@
 chUtil;%0A
+import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute;%0A
 import o
@@ -1157,16 +1157,181 @@
 Facade;%0A
+import org.ovirt.engine.core.utils.transaction.TransactionMethod;%0Aimport org.ovirt.engine.core.utils.transaction.TransactionSupport;%0A%0A@NonTransactiveCommandAttribute
 %0A@LockId
@@ -1616,24 +1616,184 @@
 newGuid());%0A
+%0A        TransactionSupport.executeInNewTransaction(new TransactionMethod%3CVoid%3E() %7B%0A%0A            @Override%0A            public Void runInTransaction() %7B%0A        
         getN
@@ -1821,24 +1821,32 @@
 etwork());%0A%0A
+        
         if (
@@ -1930,16 +1930,24 @@
         
+   
+     
 getVnicP
@@ -2007,24 +2007,32 @@
 etwork()));%0A
+        
         %7D%0A%0A 
@@ -2038,16 +2038,24 @@
         
+  
+      
 NetworkH
@@ -2125,32 +2125,88 @@
 ork().getId());%0A
+                return null;%0A            %7D%0A        %7D);%0A%0A
         getRetur

Change AddNetworkCommand to non-transactive