/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package net.rrm.ehour.ui.report.model; import net.rrm.ehour.report.reports.element.ReportElement; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * Tree structure of abstract nodes for reporting purposes. * Each node can have multiple reportnode children, for example customer -> projects -> users */ public abstract class ReportNode implements Serializable { private static final long serialVersionUID = 8722465589611086312L; protected Serializable[] columnValues; private List<ReportNode> reportNodes = new ArrayList<>(); private final Serializable id; private final boolean empty; protected ReportNode(Serializable id) { this(id, false); } protected ReportNode(Serializable id, boolean empty) { this.id = id; this.empty = empty; } public boolean isEmpty() { return empty; } /** * Create node matrix flattening the whole tree. */ public List<TreeReportElement> getNodeMatrix(int matrixWidth) { List<TreeReportElement> matrix = new ArrayList<>(); createNodeMatrix(0, new Serializable[matrixWidth], matrix); return matrix; } private Serializable[] createNodeMatrix(int currentColumn, Serializable[] columns, List<TreeReportElement> matrix) { if (isLeaf()) { Serializable[] returnCols = columns.clone(); setMatrixColumns(columns, currentColumn); matrix.add(new TreeReportElement(columns, isEmpty())); return returnCols; } else { currentColumn = setMatrixColumns(columns, currentColumn); for (ReportNode reportNode : reportNodes) { columns = reportNode.createNodeMatrix(currentColumn, columns, matrix); } } return columns; } /** * @param columns * @param currentColumn */ private int setMatrixColumns(Serializable[] columns, int currentColumn) { for (Serializable columnValue : columnValues) { columns[currentColumn++] = columnValue; } return currentColumn; } /** * Process aggregate * * @param aggregate * @return */ @SuppressWarnings("unchecked") public boolean processElement(ReportElement reportElement, int hierarchyLevel, ReportNodeFactory nodeFactory) { boolean processed = false; // first check if we need to add the aggregate to his node if (shouldProcessElement(reportElement) && !(processed = processChildNodes(reportElement, hierarchyLevel + 1, nodeFactory))) { // if not make a new child node for this aggregate ReportNode node = nodeFactory.createReportNode(reportElement, ++hierarchyLevel); // if the new node is not the last child, check whether one // of it's subschildren can process it if (!node.isLeaf()) { node.processElement(reportElement, hierarchyLevel, nodeFactory); } reportNodes.add(node); processed = true; } return processed; } /** * Is the aggregate processed by the childnodes? * * @param element * @return */ private boolean processChildNodes(ReportElement element, int hierarchyLevel, ReportNodeFactory nodeFactory) { boolean processed = false; for (ReportNode node : reportNodes) { // if the children are last nodes don't bother checking if (node.isLeaf()) { break; } if (node.processElement(element, hierarchyLevel, nodeFactory)) { processed = true; break; } } return processed; } /** * Get id for importer * * @param element * @return */ protected abstract Serializable getElementId(ReportElement element); /** * Process aggregate for this value? Only process aggregates that got the same id * * @param aggregate * @param forId * @return */ private boolean shouldProcessElement(ReportElement reportElement) { return getId().equals(getElementId(reportElement)); } /** * Is last node in the hierarchy ? Override for leaf * * @return */ protected boolean isLeaf() { return false; } /** * Get hours * * @return */ public Number getHours() { float totalHours = 0; for (ReportNode reportNode : reportNodes) { Number hours = reportNode.getHours(); if (hours != null) { totalHours += hours.floatValue(); } } return totalHours; } /** * Get turnover * * @return */ public Number getTurnover() { float totalTurnover = 0; for (ReportNode reportNode : reportNodes) { Number turnOver = reportNode.getTurnover(); if (turnOver != null) { totalTurnover += turnOver.floatValue(); } } return totalTurnover; } /** * @return */ public Serializable getId() { return id; } }