package org.activityinfo.legacy.shared.reports.content; /* * #%L * ActivityInfo Server * %% * Copyright (C) 2009 - 2013 UNICEF * %% * 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 3 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, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ import org.activityinfo.legacy.shared.reports.model.Dimension; import java.io.Serializable; import java.util.*; import java.util.Map.Entry; public class PivotTableData implements Serializable { private Axis rootRow; private Axis rootColumn; public interface CellVisitor { void onVisit(Axis row, Axis column, Cell cell); } public PivotTableData() { rootRow = new Axis(); rootColumn = new Axis(); } public boolean isEmpty() { return rootRow.isLeaf() && rootColumn.isLeaf(); } public Axis getRootRow() { return rootRow; } public Axis getRootColumn() { return rootColumn; } public Axis getRootCategory() { return getRootRow(); } public Axis getRootSeries() { return getRootColumn(); } public static class Cell implements Serializable { private Double value; /** * Required for GWT serialization */ private Cell() { } public Cell(Double value) { this.value = value; } public Double getValue() { return value; } public void setValue(Double value) { this.value = value; } } public static List<String> flattenLabels(List<Axis> list) { List<String> labels = new ArrayList<String>(); for (Axis axis : list) { labels.add(axis.flattenLabel()); } return labels; } public void visitAllCells(CellVisitor visitor) { rootRow.visitAllCells(visitor); } public static class Axis extends TreeNode<Axis> implements Serializable { private Axis parent; private Dimension dimension; private DimensionCategory category; private String label; private Map<DimensionCategory, Axis> childMap = new HashMap<DimensionCategory, Axis>(); private Map<Axis, Cell> cells = new HashMap<Axis, Cell>(); private List<Axis> children = new ArrayList<Axis>(); public Axis() { } public Axis(Axis parent, Dimension dimension, DimensionCategory category, String label) { this.parent = parent; this.dimension = dimension; this.category = category; this.label = label; } public Axis getChild(DimensionCategory category) { return childMap.get(category); } public Axis addChild(Dimension childDimension, DimensionCategory category, String categoryLabel, Comparator<Axis> comparator) { Axis child = new Axis(this, childDimension, category, categoryLabel); childMap.put(category, child); if (comparator == null) { children.add(child); } else { insertChildSorted(child, comparator); } return child; } private void insertChildSorted(Axis child, Comparator<Axis> comparator) { for (int i = 0; i != children.size(); ++i) { if (comparator.compare(child, children.get(i)) < 0) { children.add(i, child); return; } } children.add(child); } public Axis nextSibling() { if (parent == null) { return null; } int i = parent.children.indexOf(this); if (i < 1) { return null; } else { return parent.children.get(i - 1); } } public Axis prevSibling() { if (parent == null) { return null; } int i = parent.children.indexOf(this); if (i == parent.children.size() - 1) { return null; } else { return parent.children.get(i + 1); } } public Axis firstChild() { return children.get(0); } public Axis lastChild() { return children.get(children.size() - 1); } public void setValue(Axis column, Double value) { cells.put(column, new Cell(value)); } public Cell getCell(Axis column) { return cells.get(column); } public Dimension getDimension() { return dimension; } public DimensionCategory getCategory() { return category; } @Override public String getLabel() { return label; } public Map<Axis, Cell> getCells() { return cells; } public int getChildCount() { return childMap.size(); } public Axis getParent() { return parent; } @Override public List<Axis> getChildren() { return children; } public String flattenLabel() { StringBuilder sb = new StringBuilder(); Axis axis = this; do { if (axis.getLabel() != null) { if (sb.length() != 0) { sb.append(" "); } sb.append(axis.getLabel()); } axis = axis.getParent(); } while (axis != null); return sb.toString(); } public void appendString(int depth, StringBuilder sb) { for (int i = 0; i != depth; ++i) { sb.append(" "); } sb.append(dimension).append(":").append(label); for (Entry<Axis, Cell> column : cells.entrySet()) { sb.append(" | "); sb.append(column.getKey().label).append("=").append(column.getValue().getValue()); } sb.append("\n"); for (Axis child : getChildren()) { child.appendString(depth + 1, sb); } } protected void visitAllCells(CellVisitor visitor) { for (Map.Entry<Axis, Cell> entry : cells.entrySet()) { visitor.onVisit(this, entry.getKey(), entry.getValue()); } for (Axis childRow : this.children) { childRow.visitAllCells(visitor); } } private Map<DimensionCategory, Axis> getChildMap() { return childMap; } private void setChildMap(Map<DimensionCategory, Axis> childMap) { this.childMap = childMap; } private void setParent(Axis parent) { this.parent = parent; } private void setDimension(Dimension dimension) { this.dimension = dimension; } private void setCategory(DimensionCategory category) { this.category = category; } private void setLabel(String label) { this.label = label; } private void setCells(Map<Axis, Cell> cells) { this.cells = cells; } private void setChildren(List<Axis> children) { this.children = children; } public double getMaxValue() { return findMaxValue(0.0); } private double findMaxValue(double max) { for (Cell cell : cells.values()) { if (cell.getValue() != null && cell.getValue() > max) { max = cell.getValue(); } } for (Axis child : children) { max = child.findMaxValue(max); } return max; } } public static class RangeCalculator implements CellVisitor { private double minValue = Double.MAX_VALUE; private double maxValue = -Double.MAX_VALUE; @Override public void onVisit(Axis row, Axis column, Cell cell) { if (cell.getValue() != null) { if (cell.getValue() < minValue) { minValue = cell.getValue(); } if (cell.getValue() > maxValue) { maxValue = cell.getValue(); } } } public double getMinValue() { return minValue; } public double getMaxValue() { return maxValue; } } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(" COLUMNS:\n"); for (Axis col : rootColumn.getChildren()) { col.appendString(1, sb); } sb.append(" ROWS:\n"); for (Axis row : rootRow.getChildren()) { row.appendString(1, sb); } return sb.toString(); } }