commit 9e9e8d679c50d4d6fc1825870790eb3928535cfa
Author: mlinha <mlinhac@gmail.com>
Date:   Thu May 28 18:29:41 2020 +0200

    re #7885 added SUM and ability to work with multiple values and sorted parameters in configuration, optimization

diff --git a/src/main/java/vldc/aswi/model/table/NameUserName.java b/src/main/java/vldc/aswi/model/table/NameUserName.java
index 86c6e659..80c41826 100644
--- a/src/main/java/vldc/aswi/model/table/NameUserName.java
+++ b/src/main/java/vldc/aswi/model/table/NameUserName.java
@@ -1,27 +1,58 @@
 package vldc.aswi.model.table;
 
+/**
+ * Class for connection between name of the column and the user name of the column.
+ */
 public class NameUserName {
 
+    /**
+     * Name of the column.
+     */
+
     private String name;
+    /**
+     * User name of the column.
+     */
     private String userName;
 
+    /**
+     * Creates an instance of the class.
+     * @param name name of the column
+     * @param userName user name of the column
+     */
     public NameUserName(String name, String userName) {
         this.name = name;
         this.userName = userName;
     }
 
+    /**
+     * Gets the column name.
+     * @return column name
+     */
     public String getName() {
         return name;
     }
 
+    /**
+     * Sets the column name.
+     * @param  name column name
+     */
     public void setName(String name) {
         this.name = name;
     }
 
+    /**
+     * Gets the user column name.
+     * @return user column name
+     */
     public String getUserName() {
         return userName;
     }
 
+    /**
+     * Sets the user column name.
+     * @param userName user column name
+     */
     public void setUserName(String userName) {
         this.userName = userName;
     }
diff --git a/src/main/java/vldc/aswi/model/table/Node.java b/src/main/java/vldc/aswi/model/table/Node.java
index a0eca9c2..ca6234eb 100644
--- a/src/main/java/vldc/aswi/model/table/Node.java
+++ b/src/main/java/vldc/aswi/model/table/Node.java
@@ -4,22 +4,43 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
+/**
+ * Class representing a node in a tree of row or column values.
+ */
 public class Node {
 
+    /**
+     * Values of the nodes on a path the the node.
+     */
     private List<String> values;
 
+    /**
+     * Creates a node.
+     */
     public Node() {
         this.values = new ArrayList<>();
     }
 
+    /**
+     * Creates a node with the same values as the given node.
+     * @param node node to be copied
+     */
     public Node(Node node) {
         this.values = new ArrayList<>(node.values);
     }
 
+    /**
+     * Gets values.
+     * @return values.
+     */
     public List<String> getValues() {
         return values;
     }
 
+    /**
+     * Sets values.
+     * @param values values.
+     */
     public void setValues(List<String> values) {
         this.values = values;
     }
diff --git a/src/main/java/vldc/aswi/model/table/ValueFunction.java b/src/main/java/vldc/aswi/model/table/ValueFunction.java
index d18705bb..e7bc8593 100644
--- a/src/main/java/vldc/aswi/model/table/ValueFunction.java
+++ b/src/main/java/vldc/aswi/model/table/ValueFunction.java
@@ -1,27 +1,58 @@
 package vldc.aswi.model.table;
 
+
+/**
+ * Class representing connection between a value and a function
+ */
 public class ValueFunction {
 
+    /**
+     * Value
+     */
     private String value;
+    /**
+     * Function
+     */
     private String function;
 
+    /**
+     * Creates an instance of the class
+     * @param value value
+     * @param function function
+     */
     public ValueFunction(String value, String function) {
         this.value = value;
         this.function = function;
     }
 
+    /**
+     * Gets value.
+     * @return value
+     */
     public String getValue() {
         return value;
     }
 
+    /**
+     * Sets value.
+     * @param value value
+     */
     public void setValue(String value) {
         this.value = value;
     }
 
+    /**
+     * Gets function.
+     * @return function
+     */
     public String getFunction() {
         return function;
     }
 
+    /**
+     * Sets function.
+     * @param function function.
+     */
     public void setFunction(String function) {
         this.function = function;
     }
diff --git a/src/main/java/vldc/aswi/service/LocationManager.java b/src/main/java/vldc/aswi/service/LocationManager.java
index e308020a..316df3a6 100644
--- a/src/main/java/vldc/aswi/service/LocationManager.java
+++ b/src/main/java/vldc/aswi/service/LocationManager.java
@@ -14,4 +14,10 @@ public interface LocationManager {
      * @return List of locations.
      */
     List<Location> getLocations();
+
+    /**
+     * Get location from database by ID.
+     * @return location by ID.
+     */
+    public Location getLocationById(long id);
 }
diff --git a/src/main/java/vldc/aswi/service/LocationManagerImpl.java b/src/main/java/vldc/aswi/service/LocationManagerImpl.java
index 6ecbc5c7..0d37a71e 100644
--- a/src/main/java/vldc/aswi/service/LocationManagerImpl.java
+++ b/src/main/java/vldc/aswi/service/LocationManagerImpl.java
@@ -50,4 +50,13 @@ public class LocationManagerImpl implements LocationManager {
         this.locationRepository.findAll().forEach(retVal::add);
         return retVal;
     }
+
+    /**
+     * Get location from database by ID.
+     * @return location by ID.
+     */
+    @Override
+    public Location getLocationById(long id) {
+        return locationRepository.getById(id);
+    }
 }
diff --git a/src/main/java/vldc/aswi/service/SqlQueryManager.java b/src/main/java/vldc/aswi/service/SqlQueryManager.java
index a0285a1a..3efde122 100644
--- a/src/main/java/vldc/aswi/service/SqlQueryManager.java
+++ b/src/main/java/vldc/aswi/service/SqlQueryManager.java
@@ -1,5 +1,7 @@
 package vldc.aswi.service;
 
+import vldc.aswi.domain.Assembly;
+import vldc.aswi.domain.Configuration;
 import vldc.aswi.model.table.contingencyTable.ContingencyTableRow;
 
 import java.util.List;
@@ -11,10 +13,10 @@ public interface SqlQueryManager {
 
     /**
      * Get list of  contingencyTableRow.
-     * @param sqlQuery - SQL query.
+     * @param configuration - configuration from which table will be created.
      * @return List of contingencyTableRow.
      */
-    List<ContingencyTableRow> getContingencyTableRow(String sqlQuery);
+    List<ContingencyTableRow> getContingencyTableRow(Configuration configuration);
 
     /**
      * Validate given SQL query.
diff --git a/src/main/java/vldc/aswi/service/SqlQueryManagerImpl.java b/src/main/java/vldc/aswi/service/SqlQueryManagerImpl.java
index d22ca4e7..1160ae45 100644
--- a/src/main/java/vldc/aswi/service/SqlQueryManagerImpl.java
+++ b/src/main/java/vldc/aswi/service/SqlQueryManagerImpl.java
@@ -4,6 +4,10 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import vldc.aswi.database.DatabaseInterface;
+import vldc.aswi.domain.Assembly;
+import vldc.aswi.domain.Configuration;
+import vldc.aswi.domain.Function;
+import vldc.aswi.domain.parameter.ParameterInConfiguration;
 import vldc.aswi.model.table.NameUserName;
 import vldc.aswi.model.table.TableColumn;
 import vldc.aswi.model.table.ValueFunction;
@@ -11,9 +15,8 @@ import vldc.aswi.model.table.contingencyTable.ContingencyTableRow;
 import vldc.aswi.utils.Converter;
 
 import javax.sql.DataSource;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Manager for SqlQuery.
@@ -28,24 +31,44 @@ public class SqlQueryManagerImpl implements SqlQueryManager{
 
     /**
      * Get list of  contingencyTableRow.
-     * @param sqlQuery - SQL query.
+     * @param configuration - configuration from which table will be created.
      * @return List of contingencyTableRow.
      */
     @Override
-    public List<ContingencyTableRow> getContingencyTableRow(String sqlQuery) {
-        Map<String, TableColumn> tableColumns = this.databaseInterface.executeQueryAndReturnTableColumns(sqlQuery);
+    public List<ContingencyTableRow> getContingencyTableRow(Configuration configuration) {
+        long startTime = System.nanoTime();
+        Map<String, TableColumn> tableColumns = this.databaseInterface.executeQueryAndReturnTableColumns(
+                configuration.getAssembly().getSQLQuery()
+        );
+        long stopTime = System.nanoTime();
+        System.out.println("Select:" + TimeUnit.MILLISECONDS.convert((stopTime - startTime), TimeUnit.NANOSECONDS));
         List<NameUserName> rowNames = new ArrayList<>();
-        rowNames.add(new NameUserName("PROGRAM_STUDIA", "d"));
-        rowNames.add(new NameUserName("TYP_STUDIA", "d"));
-
         List<NameUserName> columnNames = new ArrayList<>();
-        columnNames.add(new NameUserName("FAKULTA_STUDIA", "d"));
-        columnNames.add(new NameUserName("FORMA_STUDIA", "d"));
-
         List<ValueFunction> valueFunctions = new ArrayList<>();
-        valueFunctions.add(new ValueFunction("VEK", "d"));
-        Converter c = new Converter();
-        return c.convertTableColumnsToContingencyTableRows(tableColumns, rowNames, columnNames, valueFunctions);
+
+        // sort parameters in configuration to have them in order set by user
+        Collections.sort(configuration.getParametersInConfiguration());
+
+        // TODO: 28.05.2020 map would be better
+        for(ParameterInConfiguration parameterInConfiguration : configuration.getParametersInConfiguration()) {
+            if (parameterInConfiguration.getLocation() != null && parameterInConfiguration.getLocation().getName().equals("Řádek")) {
+                rowNames.add(new NameUserName(parameterInConfiguration.getParameter().getNameOfSelect().toUpperCase(),
+                        parameterInConfiguration.getColumnName()));
+            }
+            else if (parameterInConfiguration.getLocation() != null && parameterInConfiguration.getLocation().getName().equals("Sloupec")) {
+                columnNames.add(new NameUserName(parameterInConfiguration.getParameter().getNameOfSelect().toUpperCase(),
+                        parameterInConfiguration.getColumnName()));
+            }
+            else if(parameterInConfiguration.getLocation() != null && parameterInConfiguration.getLocation().getName().equals("Hodnota")) {
+                for (Function function : parameterInConfiguration.getFunctions()) {
+                    valueFunctions.add(new ValueFunction(parameterInConfiguration.getParameter().getNameOfSelect().toUpperCase(),
+                            function.getName().toUpperCase()));
+                }
+            }
+        }
+
+        Converter converter = new Converter();
+        return converter.convertTableColumnsToContingencyTableRows(tableColumns, rowNames, columnNames, valueFunctions);
     }
 
     /**
diff --git a/src/main/java/vldc/aswi/utils/Converter.java b/src/main/java/vldc/aswi/utils/Converter.java
index ae77a487..c843d0e9 100644
--- a/src/main/java/vldc/aswi/utils/Converter.java
+++ b/src/main/java/vldc/aswi/utils/Converter.java
@@ -7,9 +7,11 @@ import vldc.aswi.model.table.ValueFunction;
 import vldc.aswi.model.table.contingencyTable.ContingencyTableRow;
 import vldc.aswi.model.table.contingencyTable.ContingencyTableRowCell;
 
+import javax.persistence.criteria.CriteriaBuilder;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Class for converting classes.
@@ -27,64 +29,55 @@ public class Converter {
     public List<ContingencyTableRow> convertTableColumnsToContingencyTableRows(Map<String, TableColumn> tableColumns,
                                                                                       List<NameUserName> rowNames,
                                                                                       List<NameUserName> columnNames,
-                                                                                      List<ValueFunction> valueFunctions) {
-        /*
+                                                                               List<ValueFunction> valueFunctions) {
+        long startTime = System.nanoTime();
         List<ContingencyTableRow> contingencyTableRows = new ArrayList<>();
 
-        // Create header row with column names.
-        ContingencyTableRow contingencyTableRowHeader = new ContingencyTableRow(true, 0);
-        for (String columnName : tableColumns.keySet()) {
-            contingencyTableRowHeader.addTableRowCell(new ContingencyTableRowCell(columnName, 0));
-        }
-        contingencyTableRows.add(contingencyTableRowHeader);
-
-        boolean listExpanded = false;
+        long startTime2 = System.nanoTime();
+        List<ContingencyTableRow> headerRows = createHeaderOnlyRows(tableColumns, columnNames, valueFunctions);
+        long stopTime2 = System.nanoTime();
+        System.out.println("Headers:" + TimeUnit.MILLISECONDS.convert((stopTime2 - startTime2), TimeUnit.NANOSECONDS));
 
-        // Create contingency table row.
-        for (TableColumn tableColumn : tableColumns.values()) {
-            List<String> values = tableColumn.getValues();
-
-            // If list is not created, then create it.
-            if (!listExpanded) {
-                for (int j = 0; j < values.size(); j++) {
-                    ContingencyTableRow contingencyTableRow = new ContingencyTableRow(false, 0);
-                    contingencyTableRows.add(contingencyTableRow);
-                }
-                listExpanded = true;
-            }
-
-            // Iterate through all values and assign one value per one row.
-            for (int j = 0; j < values.size(); j++) {
-                ContingencyTableRowCell contingencyTableRowCell = new ContingencyTableRowCell(values.get(j), 0);
-                contingencyTableRows.get(j + 1).addTableRowCell(contingencyTableRowCell);
-            }
-        }
-
-          */
-        List<ContingencyTableRow> contingencyTableRows = new ArrayList<>();
-
-        List<ContingencyTableRow> headerRows = createHeaderOnlyRows(tableColumns, columnNames);
+        long startTime3 = System.nanoTime();
         List<ContingencyTableRow> dataRows = createDataRows(tableColumns, columnNames, rowNames, valueFunctions);
+        long stopTime3 = System.nanoTime();
+        System.out.println("Rows:" + TimeUnit.MILLISECONDS.convert((stopTime3 - startTime3), TimeUnit.NANOSECONDS));
 
         contingencyTableRows.addAll(headerRows);
         contingencyTableRows.addAll(dataRows);
 
+        long stopTime = System.nanoTime();
+        System.out.println("Converter:" + TimeUnit.SECONDS.convert((stopTime - startTime), TimeUnit.NANOSECONDS) + "s");
+
         return contingencyTableRows;
     }
 
-    private List<ContingencyTableRow> createHeaderOnlyRows(Map<String, TableColumn> tableColumns, List<NameUserName> columnNames) {
+    /**
+     * Generates header rows.
+     * @param tableColumns Map of TableColumn
+     * @param columnNames list of column and user column names
+     * @param valueFunctions list of values and their functions
+     * @return list of contingency table rows
+     */
+    private List<ContingencyTableRow> createHeaderOnlyRows(Map<String, TableColumn> tableColumns,
+                                                           List<NameUserName> columnNames, List<ValueFunction> valueFunctions) {
         List<List<String>> values = new ArrayList<>();
         columnNodes = new ArrayList<>();
         List<ContingencyTableRow> headerRows = new ArrayList<>();
+
+        List<String> valueOptions = new ArrayList<>();
+        for (ValueFunction valueFunction : valueFunctions) {
+            valueOptions.add(valueFunction.getFunction() + " z " + valueFunction.getValue());
+        }
+        values.add(valueOptions);
+        headerRows.add(new ContingencyTableRow(true, 0));
+
         for(NameUserName nameUserName : columnNames) {
             TableColumn column = tableColumns.get(nameUserName.getName());
             values.add(getOriginalValuesFromList(column.getValues()));
             headerRows.add(new ContingencyTableRow(true, 0));
         }
 
-        Node node = new Node();
-        generateColumns(0, values, columnNodes, node);
-
         for (int i = 0; i < values.size(); i++) {
             int colSpan = 1;
             for (int j = values.size() - 1; j > i; j--) {
@@ -103,26 +96,40 @@ public class Converter {
             for (int k = 0; k < loopCount; k++) {
                 for (String value : values.get(i)) {
                     headerRows.get(i).addTableRowCell(new ContingencyTableRowCell(value, colSpan));
-                    if (i != values.size() - 1) {
+                    if (i != values.size() - 1 && i != 0) {
                         headerRows.get(i).addTableRowCell(new ContingencyTableRowCell(value + " Celkem", 1));
                     }
                 }
 
-                for (int l = 0; l < i; l++) {
+                for (int l = 0; l < i - 1; l++) {
                     headerRows.get(i).addTableRowCell(new ContingencyTableRowCell("", 1));
                 }
             }
-            if (i == 0) {
-                headerRows.get(i).addTableRowCell(new ContingencyTableRowCell("Celkový počet", 1));
-            }
-            else {
-                headerRows.get(i).addTableRowCell(new ContingencyTableRowCell("", 1));
+            for(ValueFunction valueFunction: valueFunctions) {
+                if (i == 0) {
+                    headerRows.get(i).addTableRowCell(new ContingencyTableRowCell("Celkový " + valueFunction.getFunction() +
+                            " z " + valueFunction.getValue(), 1));
+                } else {
+                    headerRows.get(i).addTableRowCell(new ContingencyTableRowCell("", 1));
+                }
             }
         }
 
+        long startTime = System.nanoTime();
+        values.remove(0);
+        Node node = new Node();
+        generateColumns(0, values, columnNodes, node);
+        long stopTime = System.nanoTime();
+        System.out.println("Colums list:" + TimeUnit.MILLISECONDS.convert((stopTime - startTime), TimeUnit.NANOSECONDS));
+
         return headerRows;
     }
 
+    /**
+     * Gets original values of a given list.
+     * @param list list from which original values should be taken
+     * @return list of original values
+     */
     private List<String> getOriginalValuesFromList(List<String> list) {
         List<String> origList = new ArrayList<>();
 
@@ -135,6 +142,14 @@ public class Converter {
         return origList;
     }
 
+    /**
+     * Creates data rows.
+     * @param tableColumns Map of TableColumn
+     * @param columnNames list of column and user column names
+     * @param rowNames list of row and user row names
+     * @param valueFunctions list of values and their functions
+     * @return list of contingency table rows
+     */
     private List<ContingencyTableRow> createDataRows(Map<String, TableColumn> tableColumns, List<NameUserName> columnNames,
                                                      List<NameUserName> rowNames, List<ValueFunction> valueFunctions) {
         List<ContingencyTableRow> dataRows = new ArrayList<>();
@@ -145,16 +160,27 @@ public class Converter {
             values.add(getOriginalValuesFromList(column.getValues()));
         }
 
+        long startTime = System.nanoTime();
         Node node = new Node();
         generateRows(dataRows, 0, values, rowNodes, node);
+        long stopTime = System.nanoTime();
+        System.out.println("Rows List:" + TimeUnit.MILLISECONDS.convert((stopTime - startTime), TimeUnit.NANOSECONDS));
 
         for (int i = 0; i < dataRows.size(); i++) {
-            fillRowWithCountData(dataRows.get(i), tableColumns, rowNodes.get(i), rowNames, columnNames, valueFunctions);
+            fillRowWithData(dataRows.get(i), tableColumns, rowNodes.get(i), rowNames, columnNames, valueFunctions);
         }
 
         return dataRows;
     }
 
+    /**
+     * Recursively generates all possible row combinations, sorted as in contingency table.
+     * @param rows list of sorted contingency table rows
+     * @param index index in the values list
+     * @param values list of lists of values of each query row
+     * @param rowNodes list of row nodes
+     * @param prevNode parent node of the nodes
+     */
     private void generateRows(List<ContingencyTableRow> rows, int index, List<List<String>> values, List<Node> rowNodes,
                               Node prevNode) {
         if (index < values.size()) {
@@ -177,6 +203,13 @@ public class Converter {
         }
     }
 
+    /**
+     * Recursively generates all possible column combinations, sorted as in contingency table.
+     * @param index index in the values list
+     * @param values list of lists of values of each query row
+     * @param columnNodes list of column nodes
+     * @param prevNode parent node of the nodes
+     */
     private void generateColumns(int index, List<List<String>> values, List<Node> columnNodes, Node prevNode) {
         if (index < values.size()) {
             List<String> list = values.get(index);
@@ -190,49 +223,87 @@ public class Converter {
         }
     }
 
-    private void fillRowWithCountData(ContingencyTableRow row, Map<String, TableColumn> tableColumns, Node node,
-                                      List<NameUserName> rowNames, List<NameUserName> columnNames, List<ValueFunction> valueFunctions) {
-        int totalCount = 0;
-        //sloupec v kont. tabulce
-        for (Node columnNode : columnNodes) {
-            int count = 0;
-            // radek v orig. tabulce
-            for (int i = 0; i < tableColumns.get(rowNames.get(0).getName()).getValues().size(); i++) {
-                boolean isUsable = true;
-                //zvoleny sloupec z radku
-                for (int j = 0; j < node.getValues().size(); j++) {
-                    if (!tableColumns.get(rowNames.get(j).getName()).getValues().get(i).equals(node.getValues().get(j))) {
-                        isUsable = false;
-                        break;
-                    }
-                }
-                int j;
-                // zvoleny sloupec ze sloupcu
-                for (j = 0; j < columnNode.getValues().size(); j++) {
-                    if (!tableColumns.get(columnNames.get(j).getName()).getValues().get(i).equals(columnNode.getValues().get(j))) {
-                        isUsable = false;
-                        break;
+    /**
+     * Fills each data row with data.
+     * @param row row to ne filled with data
+     * @param tableColumns Map of TableColumn
+     * @param node node of the row
+     * @param rowNames list of row names and user names
+     * @param columnNames list of column names and user names
+     * @param valueFunctions list of values and their functions
+     */
+    private void fillRowWithData(ContingencyTableRow row, Map<String, TableColumn> tableColumns, Node node,
+                                 List<NameUserName> rowNames, List<NameUserName> columnNames, List<ValueFunction> valueFunctions) {
+        if (columnNodes.size() == 0) {
+            columnNodes.add(new Node());
+        }
+
+        List<Integer> usableIDs = getUsableIDs(tableColumns, node, rowNames);
+
+        int[] totals = new int[valueFunctions.size()];
+        //hodnota
+        for (int v = 0; v < valueFunctions.size(); v++) {
+            ValueFunction valueFunction = valueFunctions.get(v);
+            //sloupec v kont. tabulce
+            for (Node columnNode : columnNodes) {
+                int result = 0;
+                // radek v orig. tabulce
+                for (Integer usableID : usableIDs) {
+                    boolean isUsable = true;
+                    int j;
+                    // zvoleny sloupec ze sloupcu
+                    for (j = 0; j < columnNode.getValues().size(); j++) {
+                        if (!tableColumns.get(columnNames.get(j).getName()).getValues().get(usableID).equals(columnNode.getValues().get(j))) {
+                            isUsable = false;
+                            break;
+                        }
                     }
-                }
-                // zvoleny sloupec z hodnot
-                for (ValueFunction valueFunction : valueFunctions) {
-                    if (tableColumns.get(valueFunction.getValue()).getValues().get(i) == null) {
+                    // zvoleny sloupec z hodnot
+                    if (tableColumns.get(valueFunction.getValue()).getValues().get(usableID) == null) {
                         isUsable = false;
-                        break;
                     }
-                }
 
-                if (isUsable) {
-                    count++;
-                    if (j - 1 == 0) {
-                        totalCount++;
+                    if (isUsable) {
+                        if (valueFunction.getFunction().equals("COUNT")) {
+                            result++;
+                        } else if (valueFunction.getFunction().equals("SUM")) {
+                            result += Integer.parseInt(tableColumns.get(valueFunction.getValue()).getValues().get(usableID));
+                        }
+                        if (j - 1 == 0 || j == 0) {
+                            if (valueFunction.getFunction().equals("COUNT")) {
+                                totals[v]++;
+                            } else if (valueFunction.getFunction().equals("SUM")) {
+                                totals[v] += Integer.parseInt(tableColumns.get(valueFunction.getValue()).getValues().get(usableID));
+                            }
+                        }
                     }
                 }
+                row.addTableRowCell(new ContingencyTableRowCell(Integer.toString(result), 0));
             }
+        }
+        for (int total : totals) {
+            row.addTableRowCell(new ContingencyTableRowCell(Integer.toString(total), 0));
+        }
+    }
+
+    /**
+     * Gets a list of IDs of the query rows that fit the contingency table row settings.
+     * @param tableColumns Map of TableColumn
+     * @param node node of the row
+     * @param rowNames list of row names and user names
+     * @return list of usable IDs
+     */
+    private List<Integer> getUsableIDs(Map<String, TableColumn> tableColumns, Node node, List<NameUserName> rowNames) {
+        List<Integer> ids = new ArrayList<>();
 
-            row.addTableRowCell(new ContingencyTableRowCell(Integer.toString(count), 0));
+        for (int i = 0; i < tableColumns.get(rowNames.get(0).getName()).getValues().size(); i++) {
+            for (int j = 0; j < node.getValues().size(); j++) {
+                if (tableColumns.get(rowNames.get(j).getName()).getValues().get(i).equals(node.getValues().get(j))) {
+                    ids.add(i);
+                }
+            }
         }
 
-        row.addTableRowCell(new ContingencyTableRowCell(Integer.toString(totalCount), 0));
+        return ids;
     }
 }
diff --git a/src/main/java/vldc/aswi/web/controller/AssemblyController.java b/src/main/java/vldc/aswi/web/controller/AssemblyController.java
index e0c53d89..79d2ee75 100644
--- a/src/main/java/vldc/aswi/web/controller/AssemblyController.java
+++ b/src/main/java/vldc/aswi/web/controller/AssemblyController.java
@@ -46,6 +46,10 @@ public class AssemblyController extends BasicController {
     @Autowired
     private AssemblyManager assemblyManager;
 
+    /** Autowired configuration manager */
+    @Autowired
+    private ConfigurationManager configurationManager;
+
     /** Autowired role manager. */
     @Autowired
     private RoleManager roleManager;
@@ -150,13 +154,13 @@ public class AssemblyController extends BasicController {
 
     /**
      * Post method for form, where configuration is created from assembly.
-     * @param assembly - Assembly values.
+     * @param newConfiguration - Configuration values.
      * @param bindingResult - Error results from assembly validators.
      * @param atts - Redirect attributes.
      * @return ModelAndView for assembly.
      */
     @PostMapping("/assembly")
-    public ModelAndView assemblyPost(Assembly assembly,
+    public ModelAndView assemblyPost(Configuration newConfiguration,
                                      BindingResult bindingResult,
                                      RedirectAttributes atts,
                                      @RequestParam("assemblyID") String id,
@@ -165,9 +169,22 @@ public class AssemblyController extends BasicController {
                                      @RequestParam(required=false, value="exportPdf") String exportPdf,
                                      @RequestParam(required=false, value="saveConfiguration") String saveConfiguration)
     {
+        ModelAndView modelAndView = new ModelAndView();
+
         if (generateTable != null)
         {
             System.out.println("Generuj tabulku");
+            prepareForTable(newConfiguration);
+            System.out.println("Generuj tabulku");
+            ModelMap modelMap = modelAndView.getModelMap();
+            modelMap.addAttribute("configurationID", id);
+            modelMap.addAttribute("contingencyTableRows", this.sqlQueryManager.getContingencyTableRow(newConfiguration));
+            Comparator<ParameterInConfiguration> comparator = Comparator.comparingInt(o -> o.getParameter().getParameterOrder());
+            initializeFields(newConfiguration);
+            modelMap.addAttribute("configuration", newConfiguration);
+            modelMap.addAttribute("comparator", comparator);
+            modelMap.addAttribute("formAction", "/assembly?assemblyID=" + newConfiguration.getAssembly().getId());
+            modelAndView.setViewName("assembly");
         }
         else if (exportXls != null)
         {
@@ -180,11 +197,13 @@ public class AssemblyController extends BasicController {
         else if (saveConfiguration != null)
         {
             System.out.println("ulož konfiguraci");
-        }
 
+            Configuration configuration = configurationManager.saveConfiguration(newConfiguration, "");
 
+            initializeFields(configuration);
 
-        ModelAndView modelAndView = new ModelAndView("redirect:/assembly?assemblyID=" + id);
+            modelAndView.setViewName("redirect:/configuration?configurationID=" + configuration.getId());
+        }
 
         return modelAndView;
 /*
@@ -348,4 +367,40 @@ public class AssemblyController extends BasicController {
 
         return modelAndView;
     }
+
+    /**
+     * Initializes fields of a given configuration
+     * @param configuration configuration which fields should be initialized
+     */
+    private void initializeFields(Configuration configuration) {
+        for(ParameterInConfiguration parameterInConfiguration : configuration.getParametersInConfiguration()) {
+            if(parameterInConfiguration.getLocation() == null) {
+                parameterInConfiguration.setLocation(new Location());
+            }
+            if(parameterInConfiguration.getOperator() == null) {
+                parameterInConfiguration.setOperator(new Operator());
+            }
+            if(parameterInConfiguration.getFunctions() == null) {
+                parameterInConfiguration.setFunctions(new ArrayList<>());
+            }
+        }
+    }
+
+    /**
+     * Prepares the configuration for contingency table generation. Initializes assembly and parameters of parameters in
+     * configuration.
+     * @param configuration configuration to be prepared.
+     */
+    private void prepareForTable(Configuration configuration) {
+        Assembly assembly = assemblyManager.getAssemblyById(configuration.getAssembly().getId());
+        configuration.setAssembly(assembly);
+
+        for(int i = 0; i < configuration.getParametersInConfiguration().size(); i++) {
+            ParameterInConfiguration parameterInConfiguration = configuration.getParametersInConfiguration().get(i);
+            parameterInConfiguration.setParameter(assembly.getParameters().get(i));
+            if (parameterInConfiguration.getLocation() != null) {
+                parameterInConfiguration.setLocation(locationManager.getLocationById(parameterInConfiguration.getLocation().getId()));
+            }
+        }
+    }
 }
diff --git a/src/main/java/vldc/aswi/web/controller/ConfigurationController.java b/src/main/java/vldc/aswi/web/controller/ConfigurationController.java
index 400513a8..ac494b02 100644
--- a/src/main/java/vldc/aswi/web/controller/ConfigurationController.java
+++ b/src/main/java/vldc/aswi/web/controller/ConfigurationController.java
@@ -7,16 +7,17 @@ import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.ModelMap;
 import org.springframework.validation.BindingResult;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.ModelAttribute;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.*;
 import org.springframework.web.servlet.ModelAndView;
+import vldc.aswi.domain.Assembly;
 import vldc.aswi.domain.Configuration;
 import vldc.aswi.domain.Location;
 import vldc.aswi.domain.Operator;
 import vldc.aswi.domain.parameter.ParameterInConfiguration;
+import vldc.aswi.model.table.contingencyTable.ContingencyTableRow;
+import vldc.aswi.service.AssemblyManager;
 import vldc.aswi.service.ConfigurationManager;
+import vldc.aswi.service.LocationManager;
 import vldc.aswi.service.SqlQueryManager;
 import vldc.aswi.utils.AuthControl;
 import vldc.aswi.utils.Utils;
@@ -32,6 +33,14 @@ import java.util.List;
 @Controller
 public class ConfigurationController extends BasicController{
 
+    /** Autowired location manager. */
+    @Autowired
+    private LocationManager locationManager;
+
+    /** Autowired assembly manager. */
+    @Autowired
+    private AssemblyManager assemblyManager;
+
     /** Autowired sql query manager. */
     @Autowired
     private SqlQueryManager sqlQueryManager;
@@ -86,7 +95,7 @@ public class ConfigurationController extends BasicController{
      * @return modelAndView with redirection
      */
     @PostMapping("/configuration")
-    public ModelAndView configurationPost( Configuration newConfiguration,
+    public ModelAndView configurationPost(Configuration newConfiguration,
                                            BindingResult bindingResult,
                                            @RequestParam("configurationID") String id,
                                            @RequestParam(required=false, value="generateTable") String generateTable,
@@ -94,9 +103,21 @@ public class ConfigurationController extends BasicController{
                                            @RequestParam(required=false, value="exportPdf") String exportPdf,
                                            @RequestParam(required=false, value="saveConfiguration") String saveConfiguration)
     {
+        ModelAndView modelAndView = new ModelAndView();
+
         if (generateTable != null)
         {
+            prepareForTable(newConfiguration);
             System.out.println("Generuj tabulku");
+            ModelMap modelMap = modelAndView.getModelMap();
+            modelMap.addAttribute("configurationID", id);
+            modelMap.addAttribute("contingencyTableRows", this.sqlQueryManager.getContingencyTableRow(newConfiguration));
+            Comparator<ParameterInConfiguration> comparator = Comparator.comparingInt(o -> o.getParameter().getParameterOrder());
+            initializeFields(newConfiguration);
+            modelMap.addAttribute("configuration", newConfiguration);
+            modelMap.addAttribute("comparator", comparator);
+            modelMap.addAttribute("formAction", "/configuration?configurationID=" + id);
+            modelAndView.setViewName("assembly");
         }
         else if (exportXls != null)
         {
@@ -109,10 +130,12 @@ public class ConfigurationController extends BasicController{
         else if (saveConfiguration != null)
         {
             System.out.println("ulož konfiguraci");
-        }
+            Configuration configuration = configurationManager.saveConfiguration(newConfiguration, id);
 
+            initializeFields(configuration);
 
-        ModelAndView modelAndView = new ModelAndView();
+            modelAndView.setViewName("redirect:/configuration?configurationID=" + configuration.getId());
+        }
 
         if (bindingResult.hasErrors()) {
             // TODO: 04.05.2020 Error message
@@ -123,13 +146,7 @@ public class ConfigurationController extends BasicController{
 
 
 
-        Configuration configuration = configurationManager.saveConfiguration(newConfiguration, id);
 
-        this.sqlQueryManager.getContingencyTableRow(configuration.getAssembly().getSQLQuery());
-
-        initializeFields(configuration);
-
-        modelAndView.setViewName("redirect:/configuration?configurationID=" + configuration.getId());
 
         return modelAndView;
     }
@@ -172,4 +189,22 @@ public class ConfigurationController extends BasicController{
             }
         }
     }
+
+    /**
+     * Prepares the configuration for contingency table generation. Initializes assembly and parameters of parameters in
+     * configuration.
+     * @param configuration configuration to be prepared.
+     */
+    private void prepareForTable(Configuration configuration) {
+        Assembly assembly = assemblyManager.getAssemblyById(configuration.getAssembly().getId());
+        configuration.setAssembly(assembly);
+
+        for(int i = 0; i < configuration.getParametersInConfiguration().size(); i++) {
+            ParameterInConfiguration parameterInConfiguration = configuration.getParametersInConfiguration().get(i);
+            parameterInConfiguration.setParameter(assembly.getParameters().get(i));
+            if (parameterInConfiguration.getLocation() != null) {
+                parameterInConfiguration.setLocation(locationManager.getLocationById(parameterInConfiguration.getLocation().getId()));
+            }
+        }
+    }
 }
diff --git a/src/main/webapp/WEB-INF/templates/assembly.html b/src/main/webapp/WEB-INF/templates/assembly.html
index 32170a5b..ac3e48ba 100644
--- a/src/main/webapp/WEB-INF/templates/assembly.html
+++ b/src/main/webapp/WEB-INF/templates/assembly.html
@@ -177,7 +177,7 @@
                                                 th:field="${configuration.parametersInConfiguration[__${itemStat.index}__].functions}"
                                                 multiple>
                                             <option th:each="function : ${parameterInConfiguration.parameter.functions}"
-                                                    th:text="${function.name}" th:value="${{function.id}}"></option>
+                                                    th:text="${function.name}" th:value="${function.id}"></option>
                                         </select>
                                     </td>
                                 </tr>
@@ -212,7 +212,7 @@
                 <table class="tg table">
                     <tr th:each="contingencyTableRow : ${contingencyTableRows}">
                         <div class="tg-align" th:if="${contingencyTableRow.isHeader()}">
-                            <th class="tg-align" th:each="contingencyTableRowCell : ${contingencyTableRow.getCells()}">
+                            <th class="tg-align" th:each="contingencyTableRowCell : ${contingencyTableRow.getCells()}" th:colspan="${contingencyTableRowCell.getColSpan()}">
                                 <span th:text="${contingencyTableRowCell.getValue()}"></span>
                             </th>
                         </div>
