public static DateTime?Project(this DateTime?dt, SubtotalLevel level)
 {
     if (!dt.HasValue)
     {
         return(null);
     }
     if (!level.HasFlag(SubtotalLevel.Day))
     {
         return(null);
     }
     if (!level.HasFlag(SubtotalLevel.Week))
     {
         return(dt);
     }
     if (level.HasFlag(SubtotalLevel.Year))
     {
         return(new(dt !.Value.Year, 1, 1));
     }
     if (level.HasFlag(SubtotalLevel.Month))
     {
         return(new(dt !.Value.Year, dt !.Value.Month, 1));
     }
     // if (level.HasFlag(SubtotalLevel.Week))
     return(dt.Value.DayOfWeek switch
     {
         DayOfWeek.Monday => dt.Value.AddDays(-0),
         DayOfWeek.Tuesday => dt.Value.AddDays(-1),
         DayOfWeek.Wednesday => dt.Value.AddDays(-2),
         DayOfWeek.Thursday => dt.Value.AddDays(-3),
         DayOfWeek.Friday => dt.Value.AddDays(-4),
         DayOfWeek.Saturday => dt.Value.AddDays(-5),
         DayOfWeek.Sunday => dt.Value.AddDays(-6),
         _ => throw new ArgumentOutOfRangeException(),
     });
        private ISubtotalResult BuildAggrPhase(SubtotalResult sub, IEnumerable <Balance> raw)
        {
            switch (m_Par.AggrType)
            {
            case AggregationType.None:
                sub.Fund = BuildEquiPhase(raw);
                if (m_Flags.HasFlag(SubtotalLevel.NonZero) &&
                    sub.Fund.IsZero() &&
                    !(sub is ISubtotalRoot))
                {
                    return(null);
                }

                return(sub);

            case AggregationType.ChangedDay:
                sub.TheItems = raw.GroupBy(b => b.Date).OrderBy(grp => grp.Key)
                               .Select(
                    grp => new SubtotalDate(grp.Key, m_Par.AggrInterval)
                {
                    Fund = sub.Fund += BuildEquiPhase(grp),
                }).Cast <ISubtotalResult>().ToList();
                return(sub);

            case AggregationType.EveryDay:
                sub.TheItems = new List <ISubtotalResult>();
                var initial = Prev(m_Par.EveryDayRange.Range.StartDate);
                var ed      = Next(Prev(m_Par.EveryDayRange.Range.EndDate));
                var last    = initial;

                void Append(DateTime?curr, double oldFund, double fund)
                {
                    if (last.HasValue &&
                        curr.HasValue)
                    {
                        while (last < curr)
                        {
                            last = Next(last.Value);
                            sub.TheItems.Add(
                                new SubtotalDate(last, m_Par.AggrInterval)
                            {
                                Fund = last == curr ? fund : oldFund,
                            });
                        }
                    }
                    else
                    {
                        sub.TheItems.Add(
                            new SubtotalDate(curr, m_Par.AggrInterval)
                        {
                            Fund = fund
                        });
                    }

                    if (DateHelper.CompareDate(last, curr) < 0)
                    {
                        last = curr;
                    }
                }

                var flag       = true;
                var tmp0       = 0D;
                var forcedNull =
                    (m_Par.EveryDayRange.Range.StartDate.HasValue || m_Par.EveryDayRange.Range.NullOnly) &&
                    m_Par.EveryDayRange.Range.Nullable;
                foreach (var grp in raw.GroupBy(b => b.Date).OrderBy(grp => grp.Key))
                {
                    if (flag &&
                        grp.Key != null &&
                        forcedNull)
                    {
                        sub.TheItems.Add(
                            new SubtotalDate(null, m_Par.AggrInterval)
                        {
                            Fund = 0
                        });
                    }
                    flag = false;

                    var tmp = sub.Fund;
                    sub.Fund += BuildEquiPhase(grp);

                    if (DateHelper.CompareDate(grp.Key, ed) <= 0)
                    {
                        tmp0 = sub.Fund;
                    }
                    if (grp.Key.Within(m_Par.EveryDayRange.Range))
                    {
                        Append(grp.Key, tmp, sub.Fund);
                    }
                }

                if (flag && forcedNull)
                {
                    sub.TheItems.Add(
                        new SubtotalDate(null, m_Par.AggrInterval)
                    {
                        Fund = 0
                    });
                }
                if (ed.HasValue &&
                    DateHelper.CompareDate(last, ed) < 0)
                {
                    Append(ed, tmp0, tmp0);
                }
                else if (initial.HasValue &&
                         last == initial)
                {
                    Append(Next(initial.Value), sub.Fund, sub.Fund);
                }

                return(sub);

            default:
                throw new ArgumentOutOfRangeException();
            }
        }