package com.revolsys.util.count; import java.io.StringWriter; import java.io.Writer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import com.revolsys.datatype.DataTypes; import com.revolsys.io.PathNameProxy; import com.revolsys.record.io.RecordWriter; import com.revolsys.record.io.format.tsv.Tsv; import com.revolsys.record.io.format.tsv.TsvWriter; import com.revolsys.record.schema.RecordDefinition; import com.revolsys.record.schema.RecordDefinitionBuilder; import com.revolsys.util.Emptyable; import com.revolsys.util.Strings; public class CategoryLabelCountMap implements Emptyable { private boolean logCounts; private String prefix; private String labelTitle = "Type"; private int providerCount = 0; private final Map<String, LabelCountMap> labelCountMapByCategory = new TreeMap<>(); public CategoryLabelCountMap() { } public CategoryLabelCountMap(final Map<String, LabelCountMap> counts) { if (counts != null) { this.labelCountMapByCategory.putAll(counts); } } public CategoryLabelCountMap(final String prefix) { this.prefix = prefix; } public void addCount(final CharSequence category, final CharSequence label) { final LabelCountMap labelCountMap = getLabelCountMap(category); labelCountMap.addCount(label); } public void addCount(final CharSequence category, final CharSequence label, final long count) { final LabelCountMap labelCountMap = getLabelCountMap(category); labelCountMap.addCount(label, count); } public void addCount(final CharSequence category, final PathNameProxy pathNameProxy) { final LabelCountMap labelCountMap = getLabelCountMap(category); labelCountMap.addCount(pathNameProxy); } public void addCount(final CharSequence category, final PathNameProxy pathNameProxy, final long count) { final LabelCountMap labelCountMap = getLabelCountMap(category); labelCountMap.addCount(pathNameProxy, count); } public void addCounts(final CategoryLabelCountMap counts) { synchronized (counts) { for (final Entry<String, LabelCountMap> entry : counts.labelCountMapByCategory.entrySet()) { final String category = entry.getKey(); final LabelCountMap labelCountMap = entry.getValue(); addCounts(category, labelCountMap); } } } public void addCounts(final String category, final LabelCountMap labelCountMap) { final LabelCountMap thisLabelCountMap = getLabelCountMap(category); thisLabelCountMap.addCounts(labelCountMap); } public synchronized void addCountsText(final StringBuilder sb) { for (final LabelCountMap labelCountMap : this.labelCountMapByCategory.values()) { labelCountMap.addCountsText(sb); } } public void clear() { this.labelCountMapByCategory.clear(); } @PostConstruct public synchronized void connect() { this.providerCount++; } @PreDestroy public synchronized void disconnect() { this.providerCount--; if (this.providerCount <= 0) { for (final LabelCountMap labelCountMap : this.labelCountMapByCategory.values()) { labelCountMap.disconnect(); } } } public synchronized Set<String> getCategories() { return this.labelCountMapByCategory.keySet(); } public Long getCount(final CharSequence category, final CharSequence label) { final LabelCountMap labelCountMap = getLabelCountMap(category); if (labelCountMap == null) { return null; } else { return labelCountMap.getCount(label); } } public synchronized String getCountsText() { final StringBuilder sb = new StringBuilder(); addCountsText(sb); return sb.toString(); } public synchronized LabelCountMap getLabelCountMap(final CharSequence category) { if (category == null) { return null; } else { final String categoryString = Strings.toString(" ", this.prefix, category); LabelCountMap labelCountMap = this.labelCountMapByCategory.get(categoryString); if (labelCountMap == null) { labelCountMap = new LabelCountMap(categoryString); labelCountMap.setLogCounts(this.logCounts); this.labelCountMapByCategory.put(categoryString, labelCountMap); } return labelCountMap; } } public String getLabelTitle() { return this.labelTitle; } public String getPrefix() { return this.prefix; } @Override public boolean isEmpty() { return this.labelCountMapByCategory.isEmpty(); } public synchronized void setLabelCountMap(final CharSequence category, final LabelCountMap labelCountMap) { if (category != null) { final String categoryName = Strings.toString(" ", this.prefix, category); labelCountMap.setLogCounts(this.logCounts); this.labelCountMapByCategory.put(categoryName, labelCountMap); } } public void setLabelTitle(final String labelTitle) { this.labelTitle = labelTitle; } public synchronized void setLogCounts(final boolean logCounts) { this.logCounts = logCounts; for (final LabelCountMap labelCountMap : this.labelCountMapByCategory.values()) { labelCountMap.setLogCounts(logCounts); } } public void setPrefix(final String prefix) { this.prefix = prefix; } public String toTsv() { return toTsv("CATEGORY", "NAME", "COUNT"); } public String toTsv(final String... titles) { final StringWriter out = new StringWriter(); toTsv(out, titles); return out.toString(); } public void toTsv(final Writer out, final String... titles) { try ( TsvWriter tsv = Tsv.plainWriter(out)) { tsv.write(Arrays.asList(titles)); long total = 0; for (final Entry<String, LabelCountMap> entry : this.labelCountMapByCategory.entrySet()) { final String category = entry.getKey(); final LabelCountMap labelCountMap = entry.getValue(); for (final String label : labelCountMap.getLabels()) { final long count = labelCountMap.getCount(label); total += count; tsv.write(category, label, count); } } tsv.write(null, "Total", total); } } public void writeCounts(final Object target) { writeCounts(target, this.labelTitle, this.labelCountMapByCategory.keySet()); } public void writeCounts(final Object target, final String labelTitle, final Iterable<String> categoryNames) { final RecordDefinitionBuilder recordDefinitionBuilder = new RecordDefinitionBuilder("Counts"); recordDefinitionBuilder.addField(labelTitle, DataTypes.STRING, 50); final Set<String> allLabels = new TreeSet<>(); final List<String> matchedCategoryNames = new ArrayList<>(); for (final String categoryName : categoryNames) { final LabelCountMap labelCountMap = this.labelCountMapByCategory.get(categoryName); if (labelCountMap != null) { matchedCategoryNames.add(categoryName); recordDefinitionBuilder.addField(categoryName, DataTypes.LONG, 10); final Set<String> labels = labelCountMap.getLabels(); allLabels.addAll(labels); } } final RecordDefinition recordDefinition = recordDefinitionBuilder.getRecordDefinition(); try ( RecordWriter recordWriter = RecordWriter.newRecordWriter(recordDefinition, target)) { final List<Object> row = new ArrayList<>(matchedCategoryNames.size() + 1); for (final String label : allLabels) { row.clear(); row.add(label); for (final String categoryName : matchedCategoryNames) { final Long count = getCount(categoryName, label); row.add(count); } recordWriter.write(row); } } } }