using System; using System.Collections.Generic; using System.Collections; namespace FastReport.AdvMatrix { /// /// Hold the list of registered aggregate functions. /// public static class Aggregates { private static Dictionary registeredAggregates = new Dictionary(); private static List names = new List(); /// /// Gets names of aggregates registered. /// public static string[] Names { get { return names.ToArray(); } } /// /// Registers the aggregate function. /// /// The function name. /// The type of aggregate class. public static void Register(string name, Type aggregateType) { if (!aggregateType.IsSubclassOf(typeof(AggregateBase))) throw new Exception("The 'aggregateType' parameter must be of AggregateBase type."); if (!registeredAggregates.ContainsKey(name)) { registeredAggregates[name] = aggregateType; names.Add(name); } } /// /// Returns an aggregate with specified name. /// /// The name of aggregate function. /// The aggregate class type. public static Type Find(string name) { Type aggregateType; if (registeredAggregates.TryGetValue(name, out aggregateType)) return aggregateType; return null; } static Aggregates() { Register("Sum", typeof(SumAggregate)); Register("Avg", typeof(AvgAggregate)); Register("Min", typeof(MinAggregate)); Register("Max", typeof(MaxAggregate)); Register("Count", typeof(CountAggregate)); Register("CountDistinct", typeof(CountDistinctAggregate)); Register("StDev", typeof(StDevAggregate)); Register("StDevP", typeof(StDevPAggregate)); Register("Var", typeof(VarAggregate)); Register("VarP", typeof(VarPAggregate)); Register("First", typeof(FirstAggregate)); Register("Last", typeof(LastAggregate)); Register("ValuesList", typeof(ValuesListAggregate)); } } /// /// Represents base class for AdvMatrixObject aggregates. /// public abstract class AggregateBase { /// /// Adds a value to aggregate. /// /// The value. public abstract void AddValue(object value); /// /// Gets aggregate value. /// /// Aggregate value. public abstract object GetValue(); /// /// Merges value from another, similar aggregate. /// /// Aggregate to merge value from. public abstract void Merge(AggregateBase aggr); } /// /// Represents the "Sum" aggregate. /// public class SumAggregate : AggregateBase { private object value; /// public override void AddValue(object value) { if (this.value == null) this.value = value; else this.value = (dynamic)this.value + (dynamic)value; } /// public override object GetValue() { return value; } /// public override void Merge(AggregateBase aggr) { SumAggregate a = aggr as SumAggregate; if (a != null) { AddValue(a.value); } } } /// /// Represents the "Avg" aggregate. /// public class AvgAggregate : AggregateBase { private object value; private int count; /// public override void AddValue(object value) { if (this.value == null) this.value = value; else this.value = (dynamic)this.value + (dynamic)value; count++; } /// public override object GetValue() { if (count == 0) return null; if (value is float || value is double || value is decimal) return (dynamic)value / count; return (dynamic)value / (double)count; } /// public override void Merge(AggregateBase aggr) { AvgAggregate a = aggr as AvgAggregate; if (a != null && a.value != null) { value = (dynamic)value + (dynamic)a.value; count += a.count; } } } /// /// Represents the "Min" aggregate. /// public class MinAggregate : AggregateBase { private object value; /// public override void AddValue(object value) { if (this.value == null) this.value = value; else { if ((dynamic)value < (dynamic)this.value) this.value = value; } } /// public override object GetValue() { return value; } /// public override void Merge(AggregateBase aggr) { MinAggregate a = aggr as MinAggregate; if (a != null) { AddValue(a.value); } } } /// /// Represents the "Max" aggregate. /// public class MaxAggregate : AggregateBase { private object value; /// public override void AddValue(object value) { if (this.value == null) this.value = value; else { if ((dynamic)value > (dynamic)this.value) this.value = value; } } /// public override object GetValue() { return value; } /// public override void Merge(AggregateBase aggr) { MaxAggregate a = aggr as MaxAggregate; if (a != null) { AddValue(a.value); } } } /// /// Represents the "Count" aggregate. /// public class CountAggregate : AggregateBase { private int count; /// public override void AddValue(object value) { count++; } /// public override object GetValue() { return count; } /// public override void Merge(AggregateBase aggr) { CountAggregate a = aggr as CountAggregate; if (a != null) { count += a.count; } } } /// /// Represents the "CountDistinct" aggregate. /// public class CountDistinctAggregate : AggregateBase { private Hashtable values = new Hashtable(); /// public override void AddValue(object value) { values[value] = 1; } /// public override object GetValue() { return values.Keys.Count; } /// public override void Merge(AggregateBase aggr) { CountDistinctAggregate a = aggr as CountDistinctAggregate; if (a != null) { foreach (DictionaryEntry e in a.values) { values[e.Key] = 1; } } } } /// /// Represents the "Var" aggregate. /// public class VarAggregate : AggregateBase { private List values = new List(); /// public override void AddValue(object value) { values.Add(value); } /// public override object GetValue() { if (values.Count < 2) return null; // calculate average double average = 0; foreach (dynamic v in values) { average += (double)v; } average = average / values.Count; // sum each difference double diff = 0; foreach (dynamic v in values) { diff += Math.Pow((double)v - average, 2); } return diff / (values.Count - 1); } /// public override void Merge(AggregateBase aggr) { VarAggregate a = aggr as VarAggregate; if (a != null) { values.AddRange(a.values); } } } /// /// Represents the "VarP" aggregate. /// public class VarPAggregate : AggregateBase { private List values = new List(); /// public override void AddValue(object value) { values.Add(value); } /// public override object GetValue() { if (values.Count == 0) return null; // calculate average double average = 0; foreach (dynamic v in values) { average += (double)v; } average = average / values.Count; // sum each difference double diff = 0; foreach (dynamic v in values) { diff += Math.Pow((double)v - average, 2); } return diff / values.Count; } /// public override void Merge(AggregateBase aggr) { VarPAggregate a = aggr as VarPAggregate; if (a != null) { values.AddRange(a.values); } } } /// /// Represents the "StDev" aggregate. /// public class StDevAggregate : VarAggregate { /// public override object GetValue() { return Math.Sqrt((double)base.GetValue()); } } /// /// Represents the "StDevP" aggregate. /// public class StDevPAggregate : VarPAggregate { /// public override object GetValue() { return Math.Sqrt((double)base.GetValue()); } } /// /// Represents the "First" aggregate. /// public class FirstAggregate : AggregateBase { private object value; /// public override void AddValue(object value) { if (this.value == null) this.value = value; } /// public override object GetValue() { return value; } /// public override void Merge(AggregateBase aggr) { FirstAggregate a = aggr as FirstAggregate; if (a != null) { AddValue(a.value); } } } /// /// Represents the "Last" aggregate. /// public class LastAggregate : AggregateBase { private object value; /// public override void AddValue(object value) { this.value = value; } /// public override object GetValue() { return value; } /// public override void Merge(AggregateBase aggr) { LastAggregate a = aggr as LastAggregate; if (a != null) { AddValue(a.value); } } } /// /// Represents the "ValuesList" aggregate. /// public class ValuesListAggregate : UserAggregate { } /// /// Represents the "User" aggregate. /// public class UserAggregate : AggregateBase { private List values = new List(); /// public override void AddValue(object value) { values.Add(value); } /// public override object GetValue() { return values; } /// public override void Merge(AggregateBase aggr) { UserAggregate a = aggr as UserAggregate; if (a != null) { values.AddRange(a.values); } } } }