//using InABox.Core;
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Linq.Expressions;
//using System.Reflection;
//using System.Text;
//using System.Threading.Tasks;

//namespace InABox.Database
//{

//    public enum AggregateType
//    {
//        Sum,
//        Count
//    }

//    public enum AggregateAction
//    {
//        Add,
//        Subtract
//    }

//    public interface IAggregate<TSource, TTarget> where TSource : Entity, new() where TTarget : Entity, new()
//    {
//        bool Calculate(TSource source, TTarget previous, TTarget current);

//        //void Reduce(TTarget target);
//        //void Increase(TTarget target, bool TargetChanged);

//        String AggregateValue(TTarget target);
//    }

//    public abstract class Aggregate<TSource, TTarget, TType> : IAggregate<TSource, TTarget> where TSource : Entity, new() where TTarget : Entity, new()
//    {

//        public Expression<Func<TSource, TType>> Source { get; set; }
//        public TType CurrentValue { get; set; }
//        public TType OriginalValue { get; set; }
//        public Expression<Func<TTarget, TType>> Target { get; set; }

//        public AggregateType Type { get; private set; }

//        private Aggregate()
//        {

//        } 

//        public Aggregate(Expression<Func<TSource, TType>> source, Expression<Func<TTarget, TType>> target, AggregateType type) : base()
//        {
//            Type = type;
//            Source = source; // source != null ? CoreUtils.GetPropertyFromExpression<TSource, TType>(source) : null;
//            Target = target; // target != null ? CoreUtils.GetPropertyFromExpression<TTarget, TType>(target) : null;
//        }

//        protected virtual TType ConvertValue(object value)
//        {
//            return (TType)Convert.ChangeType(value, typeof(TType));
//        }

//        public bool CalculateSum(TSource source, TTarget previous, TTarget current)
//        {
//            var src = CoreUtils.GetPropertyFromExpression<TSource, TType>(Source);
//            CurrentValue = (TType)src.GetValue(source);

//            //OriginalValue = ((source.OriginalValues != null) && (source.OriginalValues.ContainsKey(Source.Name))) ? ConvertValue(source.OriginalValues[Source.Name]) : CurrentValue;
//            OriginalValue = source.HasOriginalValue(Source) ? source.GetOriginalValue(Source) : CurrentValue;

//            if ((previous != current) || (!Equals(CurrentValue, OriginalValue)))
//            {
//                var tgt = CoreUtils.GetPropertyFromExpression<TTarget, TType>(Target);
//                if (previous != null)
//                {

//                    TType PreviousAggregrate = (TType)tgt.GetValue(previous);
//                    tgt.SetValue(previous, Accumulate(AggregateAction.Subtract, PreviousAggregrate, OriginalValue));
//                }

//                if (current != null)
//                {
//                    TType CurrentAggregate = (TType)tgt.GetValue(current);
//                    tgt.SetValue(current, Accumulate(AggregateAction.Add, CurrentAggregate, CurrentValue));
//                }

//                return true;
//            }
//            return false;

//        }

//        public bool CalculateCount(TSource source, TTarget previous, TTarget current)
//        {

//            if (previous != current)
//            {
//                TType value = (TType)Convert.ChangeType(1, typeof(TType));

//                var tgt = CoreUtils.GetPropertyFromExpression<TTarget, TType>(Target);
//                if (previous != null)
//                {

//                    TType PreviousAggregrate = (TType)tgt.GetValue(previous);
//                    tgt.SetValue(previous, Accumulate(AggregateAction.Subtract, PreviousAggregrate, Counter()));
//                }

//                if (current != null)
//                {
//                    TType CurrentAggregate = (TType)tgt.GetValue(current);
//                    tgt.SetValue(current, Accumulate(AggregateAction.Add, CurrentAggregate, Counter()));
//                }

//                return true;
//            }
//            return false;

//        }

//        public bool Calculate(TSource source, TTarget previous, TTarget current)
//        {
//            return Type.Equals(AggregateType.Sum)
//                ? CalculateSum(source, previous, current)
//                : CalculateCount(source, previous, current);
//        }

//        protected abstract TType Accumulate(AggregateAction calculation, TType currentValue, TType originalValue);

//        public abstract TType Counter();

//        public String AggregateValue(TTarget target)
//        {
//            var tgt = CoreUtils.GetPropertyFromExpression<TTarget, TType>(Target);
//            return String.Format("{0}: {1}", tgt.Name, tgt.GetValue(target));
//        }

//    }

//    public class DoubleAggregate<TSource, TTarget> : Aggregate<TSource, TTarget, Double> where TSource : Entity, new() where TTarget : Entity, new()
//    {
//        public DoubleAggregate(Expression<Func<TSource, Double>> source, Expression<Func<TTarget, Double>> target, AggregateType type) : base(source, target, type) { }

//        public override double Counter()
//        {
//            return 1.00F;
//        }

//        protected override double Accumulate(AggregateAction calculation, double currentValue, double originalValue)
//        {
//            return calculation == AggregateAction.Subtract ? currentValue - originalValue : currentValue + originalValue;
//        }
//    }

//    public class TimeSpanAggregate<TSource, TTarget> : Aggregate<TSource, TTarget, TimeSpan> where TSource : Entity, new() where TTarget : Entity, new()
//    {
//        public TimeSpanAggregate(Expression<Func<TSource, TimeSpan>> source, Expression<Func<TTarget, TimeSpan>> target, AggregateType type) : base(source, target, type) { }

//        public override TimeSpan Counter()
//        {
//            return new TimeSpan(1);
//        }
//        protected override TimeSpan ConvertValue(object value)
//        {
//            if (value is String)
//                return TimeSpan.Parse((String)value);
//            return base.ConvertValue(value);
//        }

//        protected override TimeSpan Accumulate(AggregateAction calculation, TimeSpan currentValue, TimeSpan originalValue)
//        {
//            return calculation == AggregateAction.Subtract ? currentValue - originalValue : currentValue + originalValue;
//        }
//    }

//    public class IntegerAggregate<TSource, TTarget> : Aggregate<TSource, TTarget, int> where TSource : Entity, new() where TTarget : Entity, new()
//    {
//        public IntegerAggregate(Expression<Func<TSource, int>> source, Expression<Func<TTarget, int>> target, AggregateType type) : base(source, target, type) { }

//        public override int Counter()
//        {
//            return 1;
//        }

//        protected override int Accumulate(AggregateAction calculation, int currentValue, int originalValue)
//        {
//            return calculation == AggregateAction.Subtract ? currentValue - originalValue : currentValue + originalValue;
//        }
//    }

//}

