package net.ssehub.kernel_haven.util.io;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.TreeMap;

/**
 * Metadata about the fields for a class that is annotated via the {@link TableRow} annotation.
 *
 * @author Adam
 */
public class TableRowMetadata {
    
    private Class<?> rowClass;
    
    private Method[] fields;
    
    private String[] headers;
    
    /**
     * Creates the metadata for the given table row class.
     * 
     * @param tableRowClass The class to create this metadata for.
     * 
     * @throws IllegalArgumentException If the given class does not have the {@link TableRow} annotation.
     */
    public TableRowMetadata(Class<?> tableRowClass) throws IllegalArgumentException {
        if (!isTableRow(tableRowClass)) {
            throw new IllegalArgumentException("Can only create TableMetadata for classes annotated with @TableRow");
        }
        
        this.rowClass = tableRowClass;
        
        Map<Integer, Method> methods = new TreeMap<>();
        for (Method method: rowClass.getMethods()) {
            TableElement annotation = method.getAnnotation(TableElement.class);
            if (annotation != null) {
                methods.put(annotation.index(), method);
            }
        }

        fields = new Method[methods.size()];
        headers = new String[methods.size()];
        int index = 0;
        for (Map.Entry<Integer, Method> entry : methods.entrySet()) {
            // we silently ignore if index != entry.getKey(); the order is correct, because of the TreeMap; we don't
            //  care about "holes" in the ordering
            fields[index] = entry.getValue();
            headers[index] = entry.getValue().getAnnotation(TableElement.class).name();
            index++;
        }
    }
    
    /**
     * Retrieves the header names for this table.
     * 
     * @return The header names. Not <code>null</code>.
     */
    public Object[] getHeaders() {
        return headers;
    }
    
    /**
     * Retrieves the field content for the given instance of the class that this metadata represents.
     * 
     * @param instance The instance that the field content should be retrieved from.
     * @return The field contents, in the correct ordering.
     * 
     * @throws ReflectiveOperationException If retrieving the field contents fails (e.g. because the given object is
     *      not an instance of the class that this metadata is made for).
     */
    public Object[] getContent(Object instance) throws ReflectiveOperationException {
        Object[] values = new Object[fields.length];
        
        try {
            int index = 0;
           for (Method field : fields) {
                Object result = field.invoke(instance);
                values[index++] = result;
            }
            
        } catch (IllegalArgumentException e) {
            throw new ReflectiveOperationException("Can't access field value", e);
        }
        
        return values;
    }
    
    /**
     * Checks whether the given object is an instance of the class that this metadata is made for.
     * 
     * @param instance The instance to check.
     * @return Whether the instance is an instance of this class.
     */
    public boolean isSameClass(Object instance) {
        return instance.getClass() == rowClass;
    }
    
    /**
     * Tests whether the given class is annotated with the {@link TableRow} annotation.
     * 
     * @param clazz The class to check.
     * @return Whether the given class has the annotation.
     */
    public static boolean isTableRow(Class<?> clazz) {
        TableRow annotation = clazz.getAnnotation(TableRow.class);
        return annotation != null;
    }

}

@@ -35,16 +35,171 @@
 il.io;%0A%0A
+import static net.ssehub.kernel_haven.util.null_checks.NullHelpers.maybeNull;%0Aimport static net.ssehub.kernel_haven.util.null_checks.NullHelpers.notNull;%0A%0A
 import j
@@ -223,16 +223,16 @@
 Method;%0A
-
 import j
@@ -1261,16 +1261,26 @@
 ation = 
+maybeNull(
 method.g
@@ -1307,24 +1307,25 @@
 ement.class)
+)
 ;%0A          
@@ -1853,32 +1853,40 @@
 eaders%5Bindex%5D = 
+notNull(
 entry.getValue()
@@ -1919,16 +1919,17 @@
 t.class)
+)
 .name();
@@ -3819,16 +3819,26 @@
 ation = 
+maybeNull(
 clazz.ge
@@ -3864,16 +3864,17 @@
 w.class)
+)
 ;%0A      

Fix null warnings in TableRowMetadata