package org.ovirt.engine.ui.uicommonweb.models.vms.instancetypes;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.ovirt.engine.core.common.businessentities.InstanceType;
import org.ovirt.engine.ui.uicommonweb.models.EntityModel;
import org.ovirt.engine.ui.uicommonweb.models.ListModel;
import org.ovirt.engine.ui.uicommonweb.models.Model;
import org.ovirt.engine.ui.uicommonweb.models.vms.CustomInstanceType;
import org.ovirt.engine.ui.uicommonweb.models.vms.UnitVmModel;
import org.ovirt.engine.ui.uicompat.Event;
import org.ovirt.engine.ui.uicompat.EventArgs;
import org.ovirt.engine.ui.uicompat.IEventListener;
/**
* Class which listens to fields which if changed makes the VM detached from the instance type.
* If detects a change in such a field it deciedes, if the VM should be detached from the current instance type
* or attached back to the original one if the fields has been changed back.
*/
public class InstanceTypeAttachDetachManager implements IEventListener<EventArgs> {
private UnitVmModel model;
private InstanceTypeManager instanceTypeManager;
private InstanceType managedInstanceType;
private Map<Model, Object> modelToProperValue;
private List<Model> detachableModels;
private boolean alreadyRegistered = false;
public InstanceTypeAttachDetachManager(InstanceTypeManager instanceTypeManager, UnitVmModel model) {
this.instanceTypeManager = instanceTypeManager;
this.model = model;
initDetachableFields();
}
public void manageInstanceType(InstanceType instanceType) {
this.managedInstanceType = instanceType;
setAttachedTo(instanceType);
modelToProperValue = new HashMap<>();
for (Model model : detachableModels) {
if (model instanceof ListModel) {
modelToProperValue.put(model, ((ListModel) model).getSelectedItem());
} else if (model instanceof EntityModel) {
modelToProperValue.put(model, ((EntityModel) model).getEntity());
}
}
if (!alreadyRegistered) {
model.getInstanceTypes().getSelectedItemChangedEvent().addListener(this);
listenToDetachableFields(detachableModels);
alreadyRegistered = true;
}
}
private void listenToDetachableFields(List<Model> models) {
for (Model model : models) {
if (model instanceof ListModel) {
((ListModel<?>) model).getSelectedItemChangedEvent().addListener(this);
} else if (model instanceof EntityModel) {
((EntityModel<?>) model).getEntityChangedEvent().addListener(this);
}
}
}
@Override
public void eventRaised(Event<? extends EventArgs> ev, Object sender, EventArgs args) {
if (!instanceTypeManager.isActive()) {
return;
}
boolean attached = model.getAttachedToInstanceType().getEntity();
boolean instanceTypeChanged = sender == model.getInstanceTypes();
boolean customInstanceType = model.getInstanceTypes().getSelectedItem() instanceof CustomInstanceType;
boolean allFieldsAttached = checkAllFieldsAttached();
if (!attached && !customInstanceType && instanceTypeChanged) {
// if the instance type changed attach again to the new instance type
model.getAttachedToInstanceType().setEntity(true);
}
if (instanceTypeChanged && customInstanceType) {
// if changed to custom instance type than detach
setAttachedTo(CustomInstanceType.INSTANCE);
}
if (!instanceTypeChanged) {
// if some managed field changed, consider detach / attach (ignoring custom instance type)
if (attached && !allFieldsAttached && !customInstanceType) {
// detach if it was attached but some managed field gets changed
setAttachedTo(CustomInstanceType.INSTANCE);
}
if (!attached && allFieldsAttached && customInstanceType) {
// it was previously detached but the fields changed back so attaching again
setAttachedTo(managedInstanceType);
}
}
}
private void setAttachedTo(InstanceType instanceType) {
if (instanceType == null) {
return;
}
instanceTypeManager.deactivate();
model.getAttachedToInstanceType().setEntity(!(instanceType instanceof CustomInstanceType));
model.getInstanceTypes().setSelectedItem(instanceType);
instanceTypeManager.activate();
}
private boolean checkAllFieldsAttached() {
for (Map.Entry<Model, Object> entry : modelToProperValue.entrySet()) {
if (entry.getKey() instanceof ListModel) {
if (!Objects.equals(((ListModel) entry.getKey()).getSelectedItem(), entry.getValue())) {
return false;
}
} else if (entry.getKey() instanceof EntityModel) {
if (!Objects.equals(((EntityModel) entry.getKey()).getEntity(), entry.getValue())) {
return false;
}
}
}
return true;
}
/**
* All the fields which are hard bound to the instance type (e.g. if changed, the
* VM gets detached from the instance type)
*/
private void initDetachableFields() {
detachableModels = Arrays.asList(
model.getMemSize(),
model.getTotalCPUCores(),
model.getNumOfSockets(),
model.getCoresPerSocket(),
model.getThreadsPerCore(),
model.getIsHighlyAvailable(),
model.getMigrationMode(),
model.getOverrideMigrationDowntime(),
model.getMigrationDowntime(),
model.getOverrideMigrationPolicy(),
model.getMigrationPolicies(),
model.getPriority(),
model.getMinAllocatedMemory(),
model.getMemoryBalloonDeviceEnabled(),
model.getNumOfIoThreads(),
model.getIoThreadsEnabled());
}
}