commit 16f7c98b8c0c539df387fe9b2e1acb3660d32fea
Author: mlinha <mlinha@students.zcu.cz>
Date:   Sun Aug 9 18:11:27 2020 +0200

    re #8113 re #7885 changed header column generation and row indentations; re #8154 nothing; no comments

diff --git a/src/main/java/vldc/aswi/model/table/Node.java b/src/main/java/vldc/aswi/model/table/Node.java
index 3bc64e3e..8f2fd2ec 100644
--- a/src/main/java/vldc/aswi/model/table/Node.java
+++ b/src/main/java/vldc/aswi/model/table/Node.java
@@ -24,6 +24,8 @@ public class Node {
 
     private boolean isFirstMax;
 
+    private boolean isUsable;
+
     /**
      * Values of the nodes on a path the the node.
      */
@@ -33,9 +35,10 @@ public class Node {
      * Creates a node.
      */
     public Node() {
-        isFirstMin = true;
-        isFirstMax = true;
+        this.isFirstMin = true;
+        this.isFirstMax = true;
         this.values = new ArrayList<>();
+        this.isUsable = true;
     }
 
     /**
@@ -43,9 +46,10 @@ public class Node {
      * @param node node to be copied
      */
     public Node(Node node) {
-        isFirstMin = true;
-        isFirstMax = true;
+        this.isFirstMin = true;
+        this.isFirstMax = true;
         this.values = new ArrayList<>(node.values);
+        this.isUsable = true;
     }
 
     /**
@@ -127,4 +131,12 @@ public class Node {
     public void setFirstMax(boolean firstMax) {
         isFirstMax = firstMax;
     }
+
+    public boolean isUsable() {
+        return isUsable;
+    }
+
+    public void setUsable(boolean usable) {
+        isUsable = usable;
+    }
 }
diff --git a/src/main/java/vldc/aswi/model/table/contingencyTable/ContingencyTableRowCell.java b/src/main/java/vldc/aswi/model/table/contingencyTable/ContingencyTableRowCell.java
index 254929ff..17e2711c 100644
--- a/src/main/java/vldc/aswi/model/table/contingencyTable/ContingencyTableRowCell.java
+++ b/src/main/java/vldc/aswi/model/table/contingencyTable/ContingencyTableRowCell.java
@@ -45,4 +45,8 @@ public class ContingencyTableRowCell {
     public String toString() {
         return "(" + value + ", " + colSpan + ")";
     }
+
+    public void setColSpan(int colSpan) {
+        this.colSpan = colSpan;
+    }
 }
diff --git a/src/main/java/vldc/aswi/service/SqlQueryManagerImpl.java b/src/main/java/vldc/aswi/service/SqlQueryManagerImpl.java
index 74e37979..c3d15435 100644
--- a/src/main/java/vldc/aswi/service/SqlQueryManagerImpl.java
+++ b/src/main/java/vldc/aswi/service/SqlQueryManagerImpl.java
@@ -96,6 +96,10 @@ public class SqlQueryManagerImpl implements SqlQueryManager {
                 }
             }
         }
+
+        if (valueFunctions.size() == 0) {
+            valueFunctions.add(new ValueFunction("", "", "", "Seznam"));
+        }
     }
 
     private String generateFullSQLQuery(String basicSQLQuery, List<ParameterInConfiguration> parametersInConfiguration) {
diff --git a/src/main/java/vldc/aswi/utils/Converter.java b/src/main/java/vldc/aswi/utils/Converter.java
index f5717949..511e02e8 100644
--- a/src/main/java/vldc/aswi/utils/Converter.java
+++ b/src/main/java/vldc/aswi/utils/Converter.java
@@ -37,17 +37,41 @@ public class Converter {
      */
     public List<ContingencyTableRow> convertTableColumnsToContingencyTableRows() {
         long startTime = System.nanoTime();
+
+        columnNodes = new ArrayList<>();
+        List<List<String>> values = new ArrayList<>();
+        for(NameUserName nameUserName : columnNames) {
+            TableColumn column = tableColumns.get(nameUserName.getName());
+            values.add(getOriginalValuesFromList(column.getValues()));
+        }
+
+        Node startNode = new Node();
+        generateColumns(0, values, columnNodes, startNode);
+
         List<ContingencyTableRow> contingencyTableRows = new ArrayList<>();
 
         long startTime2 = System.nanoTime();
-        List<ContingencyTableRow> headerRows = createHeaderOnlyRows();
+        List<ContingencyTableRow> dataRows = createDataRows();
         long stopTime2 = System.nanoTime();
-        System.out.println("Headers:" + TimeUnit.MILLISECONDS.convert((stopTime2 - startTime2), TimeUnit.NANOSECONDS));
+        System.out.println("Rows:" + TimeUnit.MILLISECONDS.convert((stopTime2 - startTime2), TimeUnit.NANOSECONDS));
 
         long startTime3 = System.nanoTime();
-        List<ContingencyTableRow> dataRows = createDataRows();
+        for (ContingencyTableRow dataRow : dataRows) {
+            for (int i = 0; i < columnNodes.size(); i++) {
+                if (!columnNodes.get(i).isUsable()) {
+                    dataRow.getCells().remove(i + 1);
+                }
+            }
+        }
+
+        columnNodes.removeIf(node -> !node.isUsable());
         long stopTime3 = System.nanoTime();
-        System.out.println("Rows:" + TimeUnit.MILLISECONDS.convert((stopTime3 - startTime3), TimeUnit.NANOSECONDS));
+        System.out.println("Columns remove:" + TimeUnit.MILLISECONDS.convert((stopTime3 - startTime3), TimeUnit.NANOSECONDS));
+
+        long startTime4 = System.nanoTime();
+        List<ContingencyTableRow> headerRows = createHeaderOnlyRows();
+        long stopTime4 = System.nanoTime();
+        System.out.println("Headers:" + TimeUnit.MILLISECONDS.convert((stopTime4 - startTime4), TimeUnit.NANOSECONDS));
 
         contingencyTableRows.addAll(headerRows);
         contingencyTableRows.addAll(dataRows);
@@ -63,64 +87,88 @@ public class Converter {
      * @return list of contingency table rows
      */
     private List<ContingencyTableRow> createHeaderOnlyRows() {
-        List<List<String>> values = new ArrayList<>();
-        columnNodes = 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.getName());
-        }
-        values.add(valueOptions);
+//        List<String> valueOptions = new ArrayList<>();
+//
+//        for (ValueFunction valueFunction : valueFunctions) {
+//            if (!valueFunctions.get(0).getType().equals("Seznam")) {
+//                valueOptions.add(valueFunction.getFunction() + " z " + valueFunction.getName());
+//            }
+//            else if (valueFunctions.get(0).getType().equals("Seznam") && columnNames.size() > 0) {
+//                valueOptions.add("NIC z nic");
+//            }
+//        }
+
+        //values.add(valueOptions);
         headerRows.add(new ContingencyTableRow(true, 0));
 
-        for(NameUserName nameUserName : columnNames) {
-            TableColumn column = tableColumns.get(nameUserName.getName());
-            values.add(getOriginalValuesFromList(column.getValues()));
+        for (int i = 0; i < columnNames.size(); i++) {
+            //NameUserName ignored = columnNames.get(i);
+            //TableColumn column = tableColumns.get(nameUserName.getName());
             headerRows.add(new ContingencyTableRow(true, 0));
         }
 
-        for (int i = 0; i < values.size(); i++) {
-            int colSpan = 1;
-            for (int j = values.size() - 1; j > i; j--) {
-                if (values.size() - 1 == j) {
-                    colSpan = values.get(j).size();
-                }
-                else {
-                    colSpan = (colSpan + 1) * values.get(j).size();
-                }
+        if (valueFunctions.get(0).getType().equals("Seznam")) {
+            headerRows.get(0).addTableRowCell(new ContingencyTableRowCell("Seznam", 1));
+            return headerRows;
+        }
+
+        for (int i = 0; i < headerRows.size(); i++) {
+            ContingencyTableRow headerRow = headerRows.get(i);
+
+            if (i == 0) {
+                headerRow.addTableRowCell(new ContingencyTableRowCell("Tabulka", 1));
             }
-            int loopCount = 1;
-            for (int k = 0; k < i; k++) {
-                loopCount = loopCount * values.get(k).size();
+            else {
+                headerRow.addTableRowCell(new ContingencyTableRowCell("", 1));
             }
-            headerRows.get(i).addTableRowCell(new ContingencyTableRowCell("", 1));
-            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 && i != 0) {
-                        headerRows.get(i).addTableRowCell(new ContingencyTableRowCell(value + " Celkem", 1));
+        }
+
+
+        List<String> prevValues = new ArrayList<>();
+        int prevSize = 0;
+        for (ValueFunction valueFunction : valueFunctions) {
+            headerRows.get(0).addTableRowCell(new ContingencyTableRowCell(valueFunction.getFunction() + " z " + valueFunction.getName(), 0));
+            for (Node columnNode : columnNodes) {
+                for (int i = 0; i < columnNode.getValues().size(); i++) {
+                    String value = columnNode.getValues().get(i);
+                    if (!prevValues.contains(value)) {
+                        prevValues.add(value);
+                        headerRows.get(i + 1).addTableRowCell(new ContingencyTableRowCell(value, 1));
+                        headerRows.get(0).getCells().get(headerRows.get(0).getCells().size() - 1).setColSpan(headerRows.get(0).getCells().get(headerRows.get(0).getCells().size() - 1).getColSpan() + 1);
+                    } else if (columnNode.getValues().size() >= prevSize) {
+                        headerRows.get(i + 1).getCells().get(headerRows.get(i + 1).getCells().size() - 1).setColSpan(headerRows.get(i + 1).getCells().get(headerRows.get(i + 1).getCells().size() - 1).getColSpan() + 1);
                     }
                 }
 
-                for (int l = 0; l < i - 1; l++) {
-                    headerRows.get(i).addTableRowCell(new ContingencyTableRowCell("", 1));
+                if (columnNode.getValues().size() < prevSize) {
+                    for (int s = prevSize; s < headerRows.size(); s++) {
+                        headerRows.get(s).addTableRowCell(new ContingencyTableRowCell("", 1));
+                    }
+                    for (int s = 1; s < columnNode.getValues().size(); s++) {
+                        headerRows.get(s).getCells().get(headerRows.get(s).getCells().size() - 1).setColSpan(headerRows.get(s).getCells().get(headerRows.get(s).getCells().size() - 1).getColSpan() + 1);
+                    }
+                    headerRows.get(columnNode.getValues().size()).addTableRowCell(new ContingencyTableRowCell(columnNode.getValues().get(columnNode.getValues().size() - 1) + " Celkem", 1));
                 }
+
+                prevSize = columnNode.getValues().size();
+                prevValues.remove(prevValues.size() - 1);
             }
-            for(ValueFunction valueFunction: valueFunctions) {
-                if (i == 0) {
-                    headerRows.get(i).addTableRowCell(new ContingencyTableRowCell("Celkový " + valueFunction.getFunction() +
-                            " z " + valueFunction.getName(), 1));
-                } else {
-                    headerRows.get(i).addTableRowCell(new ContingencyTableRowCell("", 1));
-                }
+        }
+
+        for (ValueFunction valueFunction : valueFunctions) {
+            for (int i = 1; i < headerRows.size(); i++) {
+                headerRows.get(i).addTableRowCell(new ContingencyTableRowCell("", 1));
             }
+            headerRows.get(0).addTableRowCell(new ContingencyTableRowCell("Celkový " + valueFunction.getFunction() +
+                    " z " + valueFunction.getName(), 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));
 
@@ -163,51 +211,20 @@ public class Converter {
         long stopTime = System.nanoTime();
         System.out.println("Rows List:" + TimeUnit.MILLISECONDS.convert((stopTime - startTime), TimeUnit.NANOSECONDS));
 
-        boolean[] usableColumns = new boolean[(valueFunctions.size() * columnNodes.size())];
-
         List<ContingencyTableRow> rowsToBeRemoved = new ArrayList<>();
         for (int i = 0; i < dataRows.size(); i++) {
-            if (!fillRowWithData(dataRows.get(i), rowNodes.get(i), usableColumns)) {
+            if (!fillRowWithData(dataRows.get(i), rowNodes.get(i))) {
                 rowsToBeRemoved.add(dataRows.get(i));
             }
         }
 
         dataRows.removeAll(rowsToBeRemoved);
 
-//        for (ContingencyTableRow row : dataRows) {
-//            List<ContingencyTableRowCell> cellsToRemove = new ArrayList<>();
-//            for (int i = 1; i < usableColumns.length; i++) {
-//                if (!usableColumns[i - 1]) {
-//                    cellsToRemove.add(row.getCells().get(i));
-//                }
-//            }
-//            row.getCells().removeAll(cellsToRemove);
-//            cellsToRemove.clear();
-//        }
-
-        ContingencyTableRow finalRow = new ContingencyTableRow(false, 0);
-        finalRow.addTableRowCell(new ContingencyTableRowCell("Celkem", 1));
-
-        int columnIndex = 0;
-        List<ContingencyTableRowCell> valueCells = new ArrayList<>();
-        for (ValueFunction valueFunction : valueFunctions) {
-            for (Node columnNode : columnNodes) {
-                if (true) {
-                    finalRow.addTableRowCell(generateFilledCell(valueFunction.getFunction(), columnNode.getTotalResult(), columnNode.getTotalResultSum(),
-                            columnNode.getTotalMin(), columnNode.getTotalMax(), columnNode.getTotalResultAvgSum(),
-                            columnNode.getTotalResultAvg()));
-                    columnIndex++;
-                }
-            }
-            valueCells.add(generateFilledCell(valueFunction.getFunction(), valueFunction.getTotalResult(), valueFunction.getTotalResultSum(),
-                    valueFunction.getTotalMin(), valueFunction.getTotalMax(), valueFunction.getTotalResultAvgSum(),
-                    valueFunction.getTotalResultAvg()));
+        if (!valueFunctions.get(0).getType().equals("Seznam") ||
+                (valueFunctions.get(0).getType().equals("Seznam") && columnNames.size() > 0)) {
+            dataRows.add(createFinalRow());
         }
 
-        finalRow.addTableRowCells(valueCells);
-
-        dataRows.add(finalRow);
-
         return dataRows;
     }
 
@@ -226,7 +243,7 @@ public class Converter {
             for (String s : list) {
                 StringBuilder levelString = new StringBuilder();
                 for (int i = 0; i < index; i++) {
-                    levelString.append("----");
+                    levelString.append("      ");
                 }
                 levelString.append(s);
                 ContingencyTableRow row = new ContingencyTableRow(false, index);
@@ -254,9 +271,11 @@ public class Converter {
             for (String s : list) {
                 Node node = new Node(prevNode);
                 node.getValues().add(s);
-                int newIndex = index + 1;
-                generateColumns(newIndex, values, columnNodes, node);
-                columnNodes.add(node);
+                if (checkIfColumnIsUsable(node.getValues())) {
+                    int newIndex = index + 1;
+                    generateColumns(newIndex, values, columnNodes, node);
+                    columnNodes.add(node);
+                }
             }
         }
     }
@@ -266,7 +285,7 @@ public class Converter {
      * @param row row to ne filled with data
      * @param node node of the row
      */
-    private boolean fillRowWithData(ContingencyTableRow row, Node node, boolean[] usableColumns) {
+    private boolean fillRowWithData(ContingencyTableRow row, Node node) {
         if (valueFunctions.size() == 0) {
             return true;
         }
@@ -284,6 +303,10 @@ public class Converter {
 
         List<Integer> usableIDs = getUsableIDs(node);
 
+        if (valueFunctions.get(0).getType().equals("Seznam") && !usableIDs.isEmpty()) {
+            return true;
+        }
+
         DoubleWrapper[] totals = new DoubleWrapper[valueFunctions.size()];
         initializeWrapperField(totals);
 
@@ -315,14 +338,14 @@ public class Converter {
                             break;
                         }
                     }
+
                     // zvoleny sloupec z hodnot
                     if (tableColumns.get(valueFunction.getNameOfSelect()).getValues().get(usableID) == null) {
                         isUsable = false;
                     }
 
-                    usableColumns[columnIndex] = isUsable;
-
                     if (isUsable) { // pokud lze hodnotu pouzit, prunik vsech hodnot sedi (ma nejakou hodnotu)
+                        columnNode.setUsable(true);
                         isRowUsable = true;
                         isFilledCell = true;
                         computeValues(valueFunction, result, resultAvgSum, columnNode, isFirstMinMax,
@@ -345,6 +368,9 @@ public class Converter {
             }
         }
         for (int i = 0; i < valueFunctions.size(); i++) {
+            if (valueFunctions.get(i).getType().equals("Seznam")) {
+                break;
+            }
             if (!isFilledValueCells[i]) {
                 row.addTableRowCell(new ContingencyTableRowCell("", 0));
             }
@@ -381,6 +407,24 @@ public class Converter {
         return ids;
     }
 
+    private boolean checkIfColumnIsUsable(List<String> columnNodeValues) {
+        for (int i = 0; i < tableColumns.get(columnNames.get(0).getName()).getValues().size(); i++) {
+            boolean isUsable = true;
+            for (int j = 0; j < columnNodeValues.size(); j++) {
+                if (!tableColumns.get(columnNames.get(j).getName()).getValues().get(i).equals(columnNodeValues.get(j))) {
+                    isUsable = false;
+                    break;
+                }
+            }
+
+            if (isUsable) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     private void computeValues(ValueFunction valueFunction, DoubleWrapper result, DoubleWrapper resultAvgSum, Node columnNode,
                                BooleanWrapper isFirstMinMax, int usableID, boolean isValueTotal, boolean isSingleValueRow) {
         switch (valueFunction.getFunction()) {
@@ -534,4 +578,25 @@ public class Converter {
             }
         }
     }
+
+    private ContingencyTableRow createFinalRow() {
+        ContingencyTableRow finalRow = new ContingencyTableRow(false, 0);
+        finalRow.addTableRowCell(new ContingencyTableRowCell("Celkem", 1));
+
+        List<ContingencyTableRowCell> valueCells = new ArrayList<>();
+        for (ValueFunction valueFunction : valueFunctions) {
+            for (Node columnNode : columnNodes) {
+                    finalRow.addTableRowCell(generateFilledCell(valueFunction.getFunction(), columnNode.getTotalResult(), columnNode.getTotalResultSum(),
+                            columnNode.getTotalMin(), columnNode.getTotalMax(), columnNode.getTotalResultAvgSum(),
+                            columnNode.getTotalResultAvg()));
+            }
+            valueCells.add(generateFilledCell(valueFunction.getFunction(), valueFunction.getTotalResult(), valueFunction.getTotalResultSum(),
+                    valueFunction.getTotalMin(), valueFunction.getTotalMax(), valueFunction.getTotalResultAvgSum(),
+                    valueFunction.getTotalResultAvg()));
+        }
+
+        finalRow.addTableRowCells(valueCells);
+
+        return finalRow;
+    }
 }
diff --git a/src/main/webapp/WEB-INF/templates/assembly.html b/src/main/webapp/WEB-INF/templates/assembly.html
index 0211a90a..29a30527 100644
--- a/src/main/webapp/WEB-INF/templates/assembly.html
+++ b/src/main/webapp/WEB-INF/templates/assembly.html
@@ -210,14 +210,19 @@
                 <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:colspan="${contingencyTableRowCell.getColSpan()}">
+                            <th class="tg-align-center" th:each="contingencyTableRowCell : ${contingencyTableRow.getCells()}" th:colspan="${contingencyTableRowCell.getColSpan()}">
                                 <span th:text="${contingencyTableRowCell.getValue()}"></span>
                             </th>
                         </div>
                         <div th:unless="${contingencyTableRow.isHeader()}">
-                            <td class="tg-align" th:each="contingencyTableRowCell : ${contingencyTableRow.getCells()}">
-                                <span th:text="${contingencyTableRowCell.getValue()}"></span>
-                            </td>
+                            <optional th:each="contingencyTableRowCell, iterStat : ${contingencyTableRow.getCells()}">
+                                <td th:if="${iterStat.index == 0}" class="tg-align-left">
+                                    <span class="tg-left-span" th:text="${contingencyTableRowCell?.getValue()}"></span>
+                                </td>
+                                <td th:unless="${iterStat.index == 0}" class="tg-align-center">
+                                    <span th:text="${contingencyTableRowCell?.getValue()}"></span>
+                                </td>
+                            </optional>
                         </div>
                     </tr>
                 </table>
diff --git a/src/main/webapp/css/style.css b/src/main/webapp/css/style.css
index dd48c05a..0c550749 100644
--- a/src/main/webapp/css/style.css
+++ b/src/main/webapp/css/style.css
@@ -297,7 +297,7 @@ table .col-3-p { width:10%; }
   border: 1px solid #d2d6de;
   box-shadow: 0 0 1px #b3b3b3;
 }
-.tg td{
+.tg td {
   font-family:Arial, sans-serif;
   font-size:14px;
   padding:10px 5px;
@@ -305,7 +305,7 @@ table .col-3-p { width:10%; }
   word-break:normal;
   border: 1px solid #d2d6de;
 }
-.tg th{
+.tg th {
   font-family:Arial, sans-serif;
   font-size:14px;
   font-weight:normal;
@@ -314,7 +314,7 @@ table .col-3-p { width:10%; }
   word-break:normal;
   border: 1px solid #d2d6de;
 }
-.tg-align{
+.tg-align-center {
   text-align:center;
   vertical-align:middle !important;
 }
@@ -331,4 +331,18 @@ table .col-3-p { width:10%; }
 
 .exported-table {
   overflow: auto;
+}
+
+.tg-align-left {
+  text-align:left;
+  vertical-align:middle !important;
+}
+
+pre {
+  font-family:Arial, sans-serif;
+  font-size:14px;
+}
+
+.tg-left-span {
+  white-space: pre;
 }
\ No newline at end of file
