/*******************************************************************************
* This file is protected by Copyright.
* Please refer to the COPYRIGHT file distributed with this source distribution.
*
* This file is part of REDHAWK IDE.
*
* All rights reserved. This program and the accompanying materials are made available under
* the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package gov.redhawk.frontend.provider;
import gov.redhawk.frontend.FrontendFactory;
import gov.redhawk.frontend.FrontendPackage;
import gov.redhawk.frontend.ListenerAllocation;
import gov.redhawk.frontend.TunerContainer;
import gov.redhawk.frontend.TunerStatus;
import gov.redhawk.frontend.UnallocatedTunerContainer;
import gov.redhawk.frontend.util.TunerProperties.StatusProperties;
import gov.redhawk.frontend.util.TunerProperties.TunerStatusAllocationProperties;
import gov.redhawk.frontend.util.TunerUtils;
import gov.redhawk.model.sca.RefreshDepth;
import gov.redhawk.model.sca.ScaAbstractProperty;
import gov.redhawk.model.sca.ScaDevice;
import gov.redhawk.model.sca.ScaPackage;
import gov.redhawk.model.sca.ScaSimpleProperty;
import gov.redhawk.model.sca.ScaStructSequenceProperty;
import gov.redhawk.model.sca.commands.ScaModelCommand;
import gov.redhawk.model.sca.services.AbstractDataProvider;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import mil.jpeojtrs.sca.scd.Interface;
import mil.jpeojtrs.sca.scd.ScdPackage;
import mil.jpeojtrs.sca.spd.SpdPackage;
import mil.jpeojtrs.sca.util.ScaEcoreUtils;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EContentAdapter;
import FRONTEND.AnalogTunerHelper;
import FRONTEND.DigitalTunerHelper;
/**
*
*/
public class FrontEndDataProvider extends AbstractDataProvider {
private static final Pattern PROP_PATTERN = Pattern.compile("FRONTEND::tuner_status.*");
private static final EStructuralFeature[] PATH = new EStructuralFeature[] { ScaPackage.Literals.PROFILE_OBJECT_WRAPPER__PROFILE_OBJ,
SpdPackage.Literals.SOFT_PKG__DESCRIPTOR, SpdPackage.Literals.DESCRIPTOR__COMPONENT, ScdPackage.Literals.SOFTWARE_COMPONENT__INTERFACES,
ScdPackage.Literals.INTERFACES__INTERFACE };
private final ScaDevice< ? > device;
private boolean supportsFei = false;
private Adapter tunerAdapter = new AdapterImpl() {
@Override
public void notifyChanged(Notification msg) {
if (msg.isTouch()) {
return;
}
switch (msg.getFeatureID(TunerStatus.class)) {
case FrontendPackage.TUNER_STATUS__TUNER_STATUS_STRUCT:
break;
default:
TunerStatusAllocationProperties.updateDeviceValue((TunerStatus) msg.getNotifier(), msg);
break;
}
}
};
private Adapter deviceAdapter = new EContentAdapter() {
@Override
protected void addAdapter(final Notifier notifier) {
if (notifier instanceof ScaAbstractProperty< ? >) {
ScaAbstractProperty< ? > prop = (ScaAbstractProperty< ? >) notifier;
if (FrontEndDataProvider.PROP_PATTERN.matcher(prop.getId()).matches()) {
super.addAdapter(notifier);
}
}
}
@Override
public void notifyChanged(Notification msg) {
super.notifyChanged(msg);
if (msg.isTouch()) {
return;
}
if (msg.getNotifier() instanceof ScaDevice< ? >) {
switch (msg.getFeatureID(ScaDevice.class)) {
case ScaPackage.SCA_DEVICE__DISPOSED:
if (msg.getNewBooleanValue()) {
removeTunerContainer();
((Notifier) msg.getNotifier()).eAdapters().remove(this);
}
break;
case ScaPackage.SCA_DEVICE__PROPERTIES:
updateTunerContainerJob.schedule(100);
break;
default:
break;
}
} else if (msg.getNotifier() instanceof ScaAbstractProperty< ? >) {
ScaAbstractProperty< ? > prop = (ScaAbstractProperty< ? >) msg.getNotifier();
if (FrontEndDataProvider.PROP_PATTERN.matcher(prop.getId()).matches()) {
updateTunerContainerJob.schedule(500);
}
}
}
};
private Job updateTunerContainerJob = new Job("Update Tuner Container") {
{
setUser(false);
setSystem(true);
}
@Override
protected IStatus run(IProgressMonitor monitor) {
if (isDisposed()) {
return Status.CANCEL_STATUS;
}
ScaModelCommand.execute(device, new ScaModelCommand() {
@Override
public void execute() {
updateTunerContainer();
}
});
return Status.OK_STATUS;
}
};
private final TunerContainer container = FrontendFactory.eINSTANCE.createTunerContainer();
private Job fetchAndPopulate = new Job("Fetch and populate FrontEnd Device") {
{
setUser(false);
setSystem(true);
}
@Override
protected IStatus run(IProgressMonitor monitor) {
if (isDisposed()) {
return Status.CANCEL_STATUS;
}
if (!device.isDisposed()) {
try {
device.refresh(monitor, RefreshDepth.FULL);
} catch (InterruptedException e) {
return Status.CANCEL_STATUS;
}
// device.fetchPorts(monitor);
// device.fetchProperties(monitor);
} else {
return Status.CANCEL_STATUS;
}
if (device.getProfileObj() == null) {
ScaModelCommand.execute(device, new ScaModelCommand() {
@Override
public void execute() {
if (device.getProfileObj() == null) {
device.eAdapters().add(new AdapterImpl() {
public void notifyChanged(Notification msg) {
switch (msg.getFeatureID(ScaDevice.class)) {
case ScaPackage.SCA_DEVICE__PROFILE_OBJ:
if (msg.getNewValue() != null) {
device.eAdapters().remove(this);
schedule();
}
break;
default:
break;
}
}
});
} else {
schedule();
}
}
});
return Status.CANCEL_STATUS;
}
supportsFei = calculateSupport();
if (supportsFei) {
ScaModelCommand.execute(device, new ScaModelCommand() {
@Override
public void execute() {
device.eAdapters().add(deviceAdapter);
updateTunerContainer();
}
});
}
return Status.OK_STATUS;
}
};
public FrontEndDataProvider(ScaDevice< ? > device) {
this.device = device;
}
private void removeTunerContainer() {
device.getFeatureData().remove(TunerUtils.TUNER_CONTAINER_ID);
}
@Override
public void dispose() {
if (!device.isDisposed()) {
ScaModelCommand.execute(device, new ScaModelCommand() {
@Override
public void execute() {
removeTunerContainer();
}
});
}
super.dispose();
}
@Override
public IStatus refresh(IProgressMonitor monitor) {
ScaModelCommand.execute(device, new ScaModelCommand() {
@Override
public void execute() {
if (isEnabled()) {
updateTunerContainer();
}
}
});
return super.refresh(monitor);
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
if (enabled) {
fetchAndPopulate.schedule();
} else {
ScaModelCommand.execute(device, new ScaModelCommand() {
@Override
public void execute() {
device.eAdapters().remove(deviceAdapter);
removeTunerContainer();
}
});
}
}
private boolean calculateSupport() {
EList<Interface> interfaceList = ScaEcoreUtils.getFeature(device, FrontEndDataProvider.PATH);
if (interfaceList != null) {
for (Interface i : interfaceList) {
// Check to see if this is a frontEndInterface
if (i.getRepid().equals(DigitalTunerHelper.id())) {
return true;
} else if (i.getRepid().equals(AnalogTunerHelper.id())) {
return true;
}
}
}
return false;
}
private void updateTunerContainer() {
if (isDisposed()) {
removeTunerContainer();
return;
}
if (!supportsFei || device.isDisposed()) {
removeTunerContainer();
return;
}
if (device.getFeatureData().get(TunerUtils.TUNER_CONTAINER_ID) != container) {
device.getFeatureData().put(TunerUtils.TUNER_CONTAINER_ID, container);
}
// Fetch list of tuners
ScaStructSequenceProperty prop = (ScaStructSequenceProperty) device.getProperty(StatusProperties.FRONTEND_TUNER_STATUS.getId());
if (prop == null) {
FrontEndDataActivator plugin = FrontEndDataActivator.getInstance();
if (plugin != null) {
plugin.getLog().log(
new Status(IStatus.ERROR, "Device " + device.getIdentifier() + " is not a valid FrontEnd device, missing property: "
+ StatusProperties.FRONTEND_TUNER_STATUS.getId(), null));
}
return;
}
int numCurrent = container.getTunerStatus().size();
int newSize = prop.getStructs().size();
int numRemove = numCurrent - newSize;
int numAdd = newSize - numCurrent;
// Remove old
for (int i = 0; i < numRemove; i++) {
TunerStatus removed = container.getTunerStatus().remove(container.getTunerStatus().size() - 1);
if (removed != null) {
removed.setTunerStatusStruct(null);
}
}
// Add new
for (int i = 0; i < numAdd; i++) {
final TunerStatus tuner = FrontendFactory.eINSTANCE.createTunerStatus();
tuner.eAdapters().add(tunerAdapter);
container.getTunerStatus().add(tuner);
}
Map<String, Integer> tunerTypeMap = new HashMap<String, Integer>();
// Update all
for (int i = 0; i < container.getTunerStatus().size(); i++) {
TunerStatus tuner = container.getTunerStatus().get(i);
if (tuner.getTunerStatusStruct() != prop.getStructs().get(i)) {
tuner.setTunerStatusStruct(prop.getStructs().get(i));
}
for (ScaSimpleProperty simple : tuner.getSimples()) {
TunerStatusAllocationProperties statusProp = TunerStatusAllocationProperties.fromPropID(simple.getId());
TunerStatusAllocationProperties.updateTunerStatusValue(tuner, statusProp, simple.getValue());
}
updateAllocationListeners(tuner);
boolean allocated = tuner.isAllocated();
if (!allocated) {
int current;
if (tunerTypeMap.containsKey(tuner.getTunerType())) {
current = tunerTypeMap.get(tuner.getTunerType());
} else {
current = 0;
}
tunerTypeMap.put(tuner.getTunerType(), current + 1);
}
}
Map<String, UnallocatedTunerContainer> current = new HashMap<String, UnallocatedTunerContainer>();
for (UnallocatedTunerContainer c : container.getUnallocatedContainer()) {
current.put(c.getTunerType(), c);
}
Map<String, UnallocatedTunerContainer> remove = new HashMap<String, UnallocatedTunerContainer>(current);
Map<String, UnallocatedTunerContainer> newItems = new HashMap<String, UnallocatedTunerContainer>();
for (String s : tunerTypeMap.keySet()) {
UnallocatedTunerContainer newC = FrontendFactory.eINSTANCE.createUnallocatedTunerContainer();
newC.setTunerType(s);
newItems.put(s, newC);
}
remove.keySet().removeAll(newItems.keySet());
newItems.keySet().removeAll(current.keySet());
for (UnallocatedTunerContainer i : container.getUnallocatedContainer()) {
Integer count = tunerTypeMap.get(i.getTunerType());
if (count == null) {
count = 0;
}
i.setCount(count);
}
if (!remove.isEmpty()) {
container.getUnallocatedContainer().removeAll(remove.values());
}
if (!newItems.keySet().isEmpty()) {
container.getUnallocatedContainer().addAll(newItems.values());
}
}
private void updateAllocationListeners(final TunerStatus tuner) {
ScaSimpleProperty allocSimple = tuner.getSimple(StatusProperties.ALLOCATION_ID_CSV.getId());
if (allocSimple == null) {
tuner.getListenerAllocations().clear();
return;
}
Object allocationValue = allocSimple.getValue();
Map<String, ListenerAllocation> currentListener = new HashMap<String, ListenerAllocation>();
for (ListenerAllocation a : tuner.getListenerAllocations()) {
currentListener.put(a.getListenerID(), a);
}
Map<String, ListenerAllocation> listenerToRemove = new HashMap<String, ListenerAllocation>(currentListener);
Map<String, ListenerAllocation> listenersToAdd = new HashMap<String, ListenerAllocation>();
if (allocationValue == null) {
allocationValue = "";
}
String allocationIDs = allocationValue.toString();
String[] allocations = allocationIDs.split(",");
boolean isControl = true;
for (String allocationId : allocations) {
if ("".equals(allocationId)) {
continue;
}
if (isControl) {
isControl = false;
continue;
}
ListenerAllocation allocation = FrontendFactory.eINSTANCE.createListenerAllocation();
allocation.setListenerID(allocationId);
listenersToAdd.put(allocationId, allocation);
}
listenerToRemove.keySet().removeAll(listenersToAdd.keySet());
listenersToAdd.keySet().removeAll(currentListener.keySet());
if (!listenerToRemove.isEmpty()) {
tuner.getListenerAllocations().removeAll(listenerToRemove.values());
}
if (!listenersToAdd.isEmpty()) {
tuner.getListenerAllocations().addAll(listenersToAdd.values());
}
}
@Override
public String getID() {
return FrontEndDataProviderFactory.ID;
}
}