public TariffMetroCommandCalculateInterval(TariffMetroCommandCalculateInterval command)
     : base(command)
 {
     startTime         = command.StartTime;
     intervalAmount    = command.IntervalAmount;
     discrete          = command.Discrete;
     perDiscreteAmount = command.PerDiscreteAmount;
     roundToNext       = command.RountToNext;
 }
        private DateTime GetNextEndTime(TariffMetro tariff, TariffMetroCommandCalculateInterval currentCommand, ref DateTime dtEstimatedDate)
        {
            //TimeSpan t1 = currentCommand.StartTime; //t1 = t_интN
            TariffMetroCommandCalculateInterval nextCommand = tariff.Next(currentCommand); //U_к = U_к + 1

            //TimeSpan t2 = nextCommand.StartTime; //t2 = t_интN+1
            var endTime = dtEstimatedDate.Add(nextCommand.StartTime); //t_интNкон = t_опл/дата + t_интN+1

            if (nextCommand.StartTime > currentCommand.StartTime)
            {
                return(endTime);
            }
            endTime         += TimeSpan.FromDays(1); //t_интNкон = t_интNкон + 24ч
            dtEstimatedDate += TimeSpan.FromDays(1); //t_опл/дата = t_опл/дата + 24ч

            return(endTime);
        }
        /// <summary>
        /// Возвращает копию команды
        /// </summary>
        public override object Clone()
        {
            TariffMetroCommand command = null;

            switch (type)
            {
            case TariffMetroCommandType.CalculateInterval:
                command = new TariffMetroCommandCalculateInterval((TariffMetroCommandCalculateInterval)this);
                break;

            case TariffMetroCommandType.Goto:
                command = new TariffMetroCommandGoto((TariffMetroCommandGoto)this);
                break;
            }

            return(command);
        }
        private static TariffMetroCommand ParseCommand(string[] sa)
        {
            string type = sa[1];

            if (String.Compare(type, CommandTypeCalculateInterval, true) == 0)
            {
                TariffMetroCommandCalculateInterval cmdCalulateInterval = new TariffMetroCommandCalculateInterval();
                cmdCalulateInterval.StartTime      = ParseTimeSpan(sa[2]);
                cmdCalulateInterval.IntervalAmount = ConvertMoney(ParseInt32(sa[3]));
                cmdCalulateInterval.RountToNext    = (ParseInt32(sa[5]) != 0);

                string[] discretes = sa[4].Split(CommandPropertySplitter);
                if (discretes.Length != 2)
                {
                    throw new FormatException(String.Format("Неверные данные дискрета", sa[4]));
                }

                cmdCalulateInterval.PerDiscreteAmount = ConvertMoney(ParseInt32(discretes[0]));
                cmdCalulateInterval.Discrete          = ParseTimeSpan(discretes[1]);

                return(cmdCalulateInterval);
            }
            else if (String.Compare(type, CommandTypeGoto, true) == 0)
            {
                TariffMetroCommandGoto cmdGoto = new TariffMetroCommandGoto();
                cmdGoto.Destination = ParseInt32(sa[2]);

                return(cmdGoto);
            }
            else if (String.Compare(type, CommandTypeEnd, true) == 0)
            {
                return(new TariffMetroCommandEnd());
            }

            throw new FormatException(String.Format("Неизвестная команда\r\n{0}", type));
        }
        protected override decimal CalculateCore(Tariff tariff, DateTime dateEntry, DateTime dateExitAssumed, out DateTime dateExitEstimated)
        {
            locker.EnterWriteLock();
            dateExitEstimated = dateExitAssumed;
            decimal d;

            try
            {
                //проверка версии
                var tm = tariff as TariffMetro;
                if (tm == null)
                {
                    throw new InvalidOperationException(String.Format("Калькулятор не поддерживает тариф типа {0} версии {1}", tariff.GetType().Name, tariff.Version.GetString()));
                }

                //расчёт
                dateExitEstimated = dateEntry;        //t_опл = t_въезда
                d = 0;                                //S_опл = 0
                var dtEstimatedDate = dateEntry.Date; //t_опл/дата = t_въезда/дата

                //макрос1
                TariffMetroCommandCalculateInterval command = tm.First(); //U_к = 1я команда
                if (command == null)
                {
                    return(0);
                }

                DateTime endTime; //объявление t_интNкон
                while (true)
                {
                    //вызов макроса2; обновление t_интNкон и t_опл/дата
                    endTime = GetNextEndTime(tm, command, ref dtEstimatedDate);
                    if (dateExitEstimated < endTime) //t_опл < t_интNкон
                    {
                        break;
                    }

                    command = tm.Next(command); //U_к = U_к + 1
                }

                //main
                while (true)
                {
                    d += command.IntervalAmount; //S_опл = S_опл + S_интN

                    //вызов макроса2; обновление t_интNкон и t_опл/дата
                    endTime = GetNextEndTime(tm, command, ref dtEstimatedDate);

                    if (command.Discrete == TimeSpan.Zero)        //dt = 0
                    {
                        dateExitEstimated = endTime;              //t_опл = t_интNкон
                        if (dateExitEstimated >= dateExitAssumed) //t_опл >= t_тек
                        {
                            break;
                        }
                    }
                    else
                    {
                        while (true)
                        {
                            dateExitEstimated += command.Discrete;    //t_опл = t_опл + dt
                            d += command.PerDiscreteAmount;           //S_опл = S_опл + ds

                            if (dateExitEstimated >= dateExitAssumed) //t_опл >= t_тек
                            {
                                break;
                            }
                            if (dateExitEstimated >= endTime) //t_опл >= t_интNкон
                            {
                                break;
                            }
                        }

                        if (dateExitEstimated >= dateExitAssumed) //t_опл >= t_тек
                        {
                            if (dateExitEstimated < endTime)      //t_опл >= t_интNкон
                            {
                                break;
                            }
                            if (!command.RountToNext)
                            {
                                break;
                            }

                            dateExitEstimated = endTime;              //t_опл = t_интNкон
                            if (dateExitEstimated >= dateExitAssumed) //t_опл >= t_тек
                            {
                                break;
                            }
                        }
                    }

                    command = tm.Next(command); //U_к = U_к + 1
                }

                //выберем максимальное время выезда
                endTime = dateExitAssumed + tm.FreeTimeAfterPayment;
                if (endTime > dateExitEstimated)
                {
                    dateExitEstimated = endTime;
                }
            }
            finally
            {
                locker.ExitWriteLock();
            }

            return(d);
        }