001package org.javamoney.moneta.function;
002
003import java.util.Objects;
004
005import javax.money.CurrencyUnit;
006import javax.money.MonetaryAmount;
007
008import org.javamoney.moneta.FastMoney;
009
010/**
011 * A state object for collecting statistics such as count, min, max, sum, and
012 * average.
013 * @author otaviojava
014 * @author Anatole Tresch
015 */
016public class MonetarySummaryStatistics {
017
018        private final MonetaryAmount empty;
019
020        private long count;
021
022        private MonetaryAmount min;
023
024        private MonetaryAmount max;
025
026        private MonetaryAmount sum;
027
028        private MonetaryAmount average;
029
030    /**
031     * Creates a new instance, targeting the given {@link javax.money.CurrencyUnit}.
032     * @param currencyUnit the target currency, not null.
033     */
034    MonetarySummaryStatistics(CurrencyUnit currencyUnit) {
035                empty = FastMoney.of(0, Objects.requireNonNull(currencyUnit));
036                setSameMonetary(empty);
037        }
038
039        /**
040         * Records another value into the summary information.
041     *
042     * @param amount
043     *            the input amount value to be addeed, not null.
044     */
045    public void accept(MonetaryAmount amount) {
046
047                if (!empty.getCurrency().equals(
048                                Objects.requireNonNull(amount).getCurrency())) {
049                        return;
050                }
051        if (isEmpty()) {
052            setSameMonetary(amount);
053            count++;
054                } else {
055            doSummary(amount);
056        }
057        }
058
059        /**
060         * Combines the state of another {@code MonetarySummaryStatistics} into this
061     * one.
062     * @param summaryStatistics
063     *            another {@code MonetarySummaryStatistics}, not null.
064     */
065    public MonetarySummaryStatistics combine(MonetarySummaryStatistics summaryStatistics) {
066        Objects.requireNonNull(summaryStatistics);
067
068                if (!equals(summaryStatistics)) {
069                return this;
070        }
071        min = MonetaryFunctions.min(min, summaryStatistics.min);
072        max = MonetaryFunctions.max(max, summaryStatistics.max);
073        sum = sum.add(summaryStatistics.sum);
074        count += summaryStatistics.count;
075        average = sum.divide(count);
076                return this;
077        }
078
079        private void doSummary(MonetaryAmount moneraty) {
080                min = MonetaryFunctions.min(min, moneraty);
081                max = MonetaryFunctions.max(max, moneraty);
082                sum = sum.add(moneraty);
083                average = sum.divide(++count);
084        }
085
086        private boolean isEmpty() {
087                return count == 0;
088        }
089
090        private void setSameMonetary(MonetaryAmount monetary) {
091                min = monetary;
092                max = monetary;
093                sum = monetary;
094                average = monetary;
095    }
096
097    /**
098     * Get the number of items added to this summary instance.
099     * @return the number of summarized items, >= 0.
100     */
101    public long getCount() {
102                return count;
103    }
104
105    /**
106     * Get the minimal amount found within this summary.
107     * @return the minimal amount, or null if no amount was added to this summary instance.
108     */
109    public MonetaryAmount getMin() {
110                return min;
111    }
112
113    /**
114     * Get the maximal amount found within this summary.
115     * @return the minimal amount, or null if no amount was added to this summary instance.
116     */
117    public MonetaryAmount getMax() {
118                return max;
119    }
120
121    /**
122     * Get the sum of all amounts within this summary.
123     * @return the total amount, or null if no amount was added to this summary instance.
124     */
125    public MonetaryAmount getSum() {
126                return sum;
127    }
128
129    /**
130     * Get the mean average of all amounts added.
131     * @return the mean average amount, or null if no amount was added to this summary instance.
132     */
133    public MonetaryAmount getAverage() {
134                return average;
135        }
136
137        /**
138         * will equals when the currency utils were equals
139         */
140        @Override
141    public boolean equals(Object obj) {
142        if (MonetarySummaryStatistics.class.isInstance(obj)) {
143                MonetarySummaryStatistics other = MonetarySummaryStatistics.class.cast(obj);
144                        return Objects.equals(empty.getCurrency(),
145                                        other.empty.getCurrency());
146        }
147        return false;
148    }
149        @Override
150        public int hashCode() {
151                return empty.getCurrency().hashCode();
152        }
153
154        @Override
155        public String toString() {
156                StringBuilder sb = new StringBuilder();
157                sb.append("[currency: ").append(empty.getCurrency()).append(",");
158                sb.append("count:").append(count).append(",");
159                sb.append("min:").append(min).append(",");
160                sb.append("max:").append(max).append(",");
161                sb.append("sum:").append(sum).append(",");
162                sb.append("average:").append(average).append("]");
163                return sb.toString();
164        }
165
166}