package org.zstack.storage.volume;

import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.cloudbus.CloudBusCallBack;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.header.core.Completion;
import org.zstack.header.image.ImageBackupStorageRefInventory;
import org.zstack.header.image.ImageInventory;
import org.zstack.header.image.ImageVO;
import org.zstack.header.message.MessageReply;
import org.zstack.header.storage.primary.*;
import org.zstack.header.vm.PreVmInstantiateResourceExtensionPoint;
import org.zstack.header.vm.VmInstanceConstant.VmOperation;
import org.zstack.header.vm.VmInstanceSpec;
import org.zstack.header.vm.VmInstanceSpec.ImageSpec;
import org.zstack.header.vm.VmInstanceSpec.IsoSpec;
import org.zstack.header.vm.VmInstanceSpec.VolumeSpec;
import org.zstack.header.vm.VmInstantiateResourceException;
import org.zstack.utils.CollectionUtils;
import org.zstack.utils.Utils;
import org.zstack.utils.function.Function;
import org.zstack.utils.logging.CLogger;

import java.util.List;

import static org.zstack.utils.CollectionDSL.list;

/**
 * Created by frank on 5/23/2015.
 */
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public class DownloadIsoForVmExtension implements PreVmInstantiateResourceExtensionPoint {
    private CLogger logger = Utils.getLogger(DownloadIsoForVmExtension.class);

    @Autowired
    private CloudBus bus;
    @Autowired
    private DatabaseFacade dbf;

    private static List<VmOperation> operations;
    static {
        operations = list(
                VmOperation.NewCreate,
                VmOperation.Start,
                VmOperation.Reboot
        );
    }

    @Override
    public void preBeforeInstantiateVmResource(VmInstanceSpec spec) throws VmInstantiateResourceException {
    }

    @Override
    public void preInstantiateVmResource(final VmInstanceSpec spec, final Completion completion) {
        if (spec.getDestIso() == null || !operations.contains(spec.getCurrentVmOperation())) {
            completion.success();
            return;
        }

        assert spec.getDestIso().getBackupStorageUuid() != null : "backup storage uuid cannot be null";

        final String psUuid;
        ImageSpec imageSpec = new ImageSpec();
        final ImageInventory iso = ImageInventory.valueOf(dbf.findByUuid(spec.getDestIso().getImageUuid(), ImageVO.class));
        imageSpec.setInventory(iso);
        imageSpec.setSelectedBackupStorage(CollectionUtils.find(iso.getBackupStorageRefs(), new Function<ImageBackupStorageRefInventory, ImageBackupStorageRefInventory>() {
            @Override
            public ImageBackupStorageRefInventory call(ImageBackupStorageRefInventory arg) {
                return arg.getBackupStorageUuid().equals(spec.getDestIso().getBackupStorageUuid()) ? arg : null;
            }
        }));

        if (VmOperation.NewCreate == spec.getCurrentVmOperation()) {
            VolumeSpec vspec = spec.getVolumeSpecs().get(0);
            PrimaryStorageInventory pinv = vspec.getPrimaryStorageInventory();
            psUuid = pinv.getUuid();
        } else {
            psUuid = spec.getVmInventory().getRootVolume().getPrimaryStorageUuid();
        }

        DownloadIsoToPrimaryStorageMsg msg = new DownloadIsoToPrimaryStorageMsg();
        msg.setPrimaryStorageUuid(psUuid);
        msg.setIsoSpec(imageSpec);
        msg.setVmInstanceUuid(spec.getVmInventory().getUuid());
        msg.setDestHostUuid(spec.getDestHost().getUuid());
        bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, psUuid);
        bus.send(msg, new CloudBusCallBack(completion) {
            @Override
            public void run(MessageReply reply) {
                if (reply.isSuccess()) {
                    DownloadIsoToPrimaryStorageReply re = reply.castReply();
                    IsoSpec isoSpec = new IsoSpec();
                    isoSpec.setInstallPath(re.getInstallPath());
                    isoSpec.setPrimaryStorageUuid(psUuid);
                    isoSpec.setImageUuid(iso.getUuid());
                    spec.setDestIso(isoSpec);
                    completion.success();
                } else {
                    completion.fail(reply.getError());
                }
            }
        });
    }

    @Override
    public void preReleaseVmResource(VmInstanceSpec spec, final Completion completion) {
        if (spec.getDestIso() != null) {
            String psUuid;
            if (VmOperation.NewCreate == spec.getCurrentVmOperation()) {
                VolumeSpec vspec = spec.getVolumeSpecs().get(0);
                PrimaryStorageInventory pinv = vspec.getPrimaryStorageInventory();
                psUuid = pinv.getUuid();
            } else {
                psUuid = spec.getVmInventory().getRootVolume().getPrimaryStorageUuid();
            }

            DeleteIsoFromPrimaryStorageMsg msg = new DeleteIsoFromPrimaryStorageMsg();
            msg.setVmInstanceUuid(spec.getVmInventory().getUuid());
            msg.setIsoSpec(spec.getImageSpec());
            msg.setPrimaryStorageUuid(spec.getDestIso().getPrimaryStorageUuid());
            bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, psUuid);
            bus.send(msg, new CloudBusCallBack(completion) {
                @Override
                public void run(MessageReply reply) {
                    if (!reply.isSuccess()) {
                        logger.warn(reply.getError().toString());
                    }
                    completion.success();
                }
            });
        } else {
            completion.success();
        }
    }
}

@@ -5261,49 +5261,14 @@
 uid(
+p
 s
-pec.getDestIso().getPrimaryStorage
 Uuid
-()
 );%0A 

Fix issue #1036