package org.yamcs.ui.eventviewer;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;
import javax.swing.table.AbstractTableModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yamcs.protobuf.Yamcs.Event;
import org.yamcs.utils.TimeEncoding;
import com.google.protobuf.Descriptors.FieldDescriptor.Type;
import com.google.protobuf.ExtensionRegistry;
import com.google.protobuf.GeneratedMessage.GeneratedExtension;
import com.google.protobuf.InvalidProtocolBufferException;
class EventTableModel extends AbstractTableModel implements Observer {
private static final long serialVersionUID = 1L;
private static final Logger log=LoggerFactory.getLogger(EventTableModel.class);
private static List<String> columnNames=new ArrayList<>();
private List<GeneratedExtension<Event, Type>> extensions=new ArrayList<>();
private ExtensionRegistry registry;
/** Column indices */
public static final int SOURCE_COL = 0;
public static final int GENERATION_TIME_COL = 1;
public static final int RECEPTION_TIME_COL = 2;
public static final int EVENT_TYPE_COL = 3;
public static final int EVENT_TEXT_COL = 4;
public static final int FIRST_EXTENSION_COL = 5;
/** Vector with all events */
private Vector<Event> allEvents = null;
/** Parallel data model with only visible events */
private Vector<Event> visibleEvents = null;
/** Filtering table */
FilteringRulesTable filteringTable = null;
public EventTableModel(FilteringRulesTable table, List<Map<String, String>> extraColumns) {
columnNames.add("Source");
columnNames.add("Generation Time");
columnNames.add("Reception Time");
columnNames.add("Type");
columnNames.add("Description");
allEvents = new Vector<Event>();
visibleEvents = new Vector<Event>();
filteringTable = table;
filteringTable.registerObserver(this);
if(extraColumns!=null) {
for(Map<String,String> col:extraColumns) {
if(registry==null) {
registry=ExtensionRegistry.newInstance();
}
try {
Class<?> extensionClazz=Class.forName(col.get("class"));
Field field=extensionClazz.getField(col.get("extension"));
@SuppressWarnings("unchecked")
GeneratedExtension<Event, Type> extension=(GeneratedExtension<Event, Type>)field.get(null);
extensions.add(extension);
registry.add(extension);
log.info("Installing extension "+extension.getDescriptor().getFullName());
} catch (IllegalAccessException e) {
log.error("Could not load extension class", e);
continue;
} catch (ClassNotFoundException e) {
log.error("Could not load extension class", e);
continue;
} catch (SecurityException e) {
log.error("Could not load extension class", e);
continue;
} catch (NoSuchFieldException e) {
log.error("Could not load extension class", e);
continue;
}
columnNames.add(col.get("label"));
}
}
}
@Override
public int getRowCount() {
return visibleEvents.size();
}
@Override
public int getColumnCount() {
return columnNames.size();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Object value = null;
Event event = visibleEvents.elementAt(rowIndex);
if(columnIndex==SOURCE_COL) {
value=event.getSource();
} else if(columnIndex==EVENT_TEXT_COL) {
value=event; // return event here to be compatible with older code
} else if(columnIndex==EVENT_TYPE_COL) {
value=event.getType();
} else if(columnIndex==GENERATION_TIME_COL) {
value=TimeEncoding.toString(event.getGenerationTime());
} else if(columnIndex==RECEPTION_TIME_COL) {
value=TimeEncoding.toString(event.getReceptionTime());
} else if(columnIndex>=FIRST_EXTENSION_COL) {
int extensionIndex=columnIndex-FIRST_EXTENSION_COL;
if(columnIndex-FIRST_EXTENSION_COL<extensions.size()) {
value=event.getExtension(extensions.get(extensionIndex));
}
}
return value;
}
@Override
public String getColumnName(int col) {
return columnNames.get(col);
}
/**
* Add list of events into model.
* @param eventList List of events to be added.
*/
public void addEvents(final List<Event> eventList) {
List<Event> newEvents=eventList;
if(!extensions.isEmpty()) {
try {
newEvents=new ArrayList<Event>(eventList.size());
for(Event evt:eventList) {
newEvents.add(Event.parseFrom(evt.toByteArray(), registry));
}
} catch(InvalidProtocolBufferException e) {
e.printStackTrace();
}
}
allEvents.addAll(newEvents);
int firstr = visibleEvents.size();
for (Event event : newEvents) {
if (filteringTable.isEventVisible(event)) {
visibleEvents.add(event);
}
}
int lastr = visibleEvents.size() - 1;
if (firstr <= lastr) {
fireTableRowsInserted(firstr, lastr);
}
}
/**
* Add single event into model.
* @param event Event to be added.
*/
public void addEvent(final Event event) {
Event newEvent = event;
if(!extensions.isEmpty()) {
try {
newEvent=Event.parseFrom(event.toByteArray(), registry);
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
}
allEvents.add(newEvent);
if (filteringTable.isEventVisible(newEvent)) {
visibleEvents.add(newEvent);
int addedRow = visibleEvents.size() - 1;
fireTableRowsInserted(addedRow, addedRow);
}
}
/**
* Access to event on the specific row.
* @param row Row
* @return Event on the row.
*/
public Event getEvent(int row)
{
return visibleEvents.elementAt(row);
}
/**
* Remove all events from the model.
*/
public void clear()
{
fireTableRowsDeleted(0, getRowCount()-1);
allEvents.clear();
visibleEvents.clear();
}
/**
* Apply new filtering rules. After the change of filtering rules the
* visible data must conform with them.
*/
public void applyNewFilteringRules()
{
visibleEvents.clear();
for (Event event : allEvents)
{
if (filteringTable.isEventVisible(event))
{
visibleEvents.add(event);
}
}
fireTableDataChanged();
}
@Override
public void update(Observable o, Object arg)
{
applyNewFilteringRules();
}
}