<commit_before>import 'package:taqo_common/model/experiment.dart';
import 'package:taqo_common/model/schedule.dart';
import 'package:taqo_common/util/date_time_util.dart';

class FixedScheduleGenerator {
  final DateTime startTime;
  final Experiment experiment;
  final String groupName;
  final int triggerId;
  final Schedule schedule;

  FixedScheduleGenerator(this.startTime, this.experiment, this.groupName, this.triggerId,
      this.schedule);

  List<DateTime> allAlarmTimesFromUntil(DateTime from, DateTime until) {
    if (schedule.signalTimes == null || schedule.signalTimes.isEmpty) {
      return null;
    }

    final alarms = <DateTime>[];
    var dt = cloneDateTime(from);
    while (dt.isBefore(until) || dt.isAtSameMomentAs(until)) {
      DateTime next;
      switch (schedule.scheduleType) {
        case Schedule.DAILY:
          next = _scheduleDaily(dt);
          break;
        case Schedule.WEEKDAY:
          next = _scheduleWeekday(dt);
          break;
        case Schedule.WEEKLY:
          next = _scheduleWeekly(dt);
          break;
        case Schedule.MONTHLY:
          next = _scheduleMonthly(dt);
          break;
      }
      if (next == null) {
        break;
      }
      alarms.add(next);
      dt = next.add(Duration(seconds: 1));
    }

    return alarms;
  }

  DateTime nextAlarmTimeFromNow({DateTime fromNow}) {
    if (schedule.signalTimes == null || schedule.signalTimes.isEmpty) {
      return null;
    }

    final now = fromNow ?? DateTime.now();
    switch (schedule.scheduleType) {
      case Schedule.DAILY:
        return _scheduleDaily(now);
      case Schedule.WEEKDAY:
        return _scheduleWeekday(now);
      case Schedule.WEEKLY:
        return _scheduleWeekly(now);
      case Schedule.MONTHLY:
        return _scheduleMonthly(now);
    }

    return null;
  }

  DateTime get _scheduleBeginDay =>
      getDateWithoutTime(DateTime.fromMillisecondsSinceEpoch(schedule.beginDate));

  DateTime _getNextTimeOnDay(DateTime day, DateTime fromNow) {
    // TODO (mike) investigate SignalTime.type (offset)
    if (day.isAfter(fromNow)) {
      // Return first time on day
      if (schedule.signalTimes.isNotEmpty) {
        return day.add(Duration(milliseconds: schedule.signalTimes.first.fixedTimeMillisFromMidnight));
      }
      return null;
    } else {
      // Return first time on day after fromNow
      final nowTimeOnDay = mixDateWithTime(day, fromNow);
      for (var time in schedule.signalTimes) {
        final dt = day.add(Duration(milliseconds: time.fixedTimeMillisFromMidnight));
        if (dt.isAfter(nowTimeOnDay)) {
          return dt;
        }
      }
    }
    return null;
  }

  DateTime _getNextDailyScheduleDay(DateTime fromNow) {
    final fromDay = getDateWithoutTime(fromNow);
    if (schedule.repeatRate == 1) {
      return fromDay;
    }
    final offsetToNextDay = fromDay.difference(_scheduleBeginDay).inDays % schedule.repeatRate;
    if (offsetToNextDay == 0) {
      return fromDay;
    }<commit_msg>Fix getNextTimeOnDay logic error<commit_after>import 'package:taqo_common/model/experiment.dart';
import 'package:taqo_common/model/schedule.dart';
import 'package:taqo_common/util/date_time_util.dart';

class FixedScheduleGenerator {
  final DateTime startTime;
  final Experiment experiment;
  final String groupName;
  final int triggerId;
  final Schedule schedule;

  FixedScheduleGenerator(this.startTime, this.experiment, this.groupName, this.triggerId,
      this.schedule);

  List<DateTime> allAlarmTimesFromUntil(DateTime from, DateTime until) {
    if (schedule.signalTimes == null || schedule.signalTimes.isEmpty) {
      return null;
    }

    final alarms = <DateTime>[];
    var dt = cloneDateTime(from);
    while (dt.isBefore(until) || dt.isAtSameMomentAs(until)) {
      DateTime next;
      switch (schedule.scheduleType) {
        case Schedule.DAILY:
          next = _scheduleDaily(dt);
          break;
        case Schedule.WEEKDAY:
          next = _scheduleWeekday(dt);
          break;
        case Schedule.WEEKLY:
          next = _scheduleWeekly(dt);
          break;
        case Schedule.MONTHLY:
          next = _scheduleMonthly(dt);
          break;
      }
      if (next == null) {
        break;
      }
      alarms.add(next);
      dt = next.add(Duration(seconds: 1));
    }

    return alarms;
  }

  DateTime nextAlarmTimeFromNow({DateTime fromNow}) {
    if (schedule.signalTimes == null || schedule.signalTimes.isEmpty) {
      return null;
    }

    final now = fromNow ?? DateTime.now();
    switch (schedule.scheduleType) {
      case Schedule.DAILY:
        return _scheduleDaily(now);
      case Schedule.WEEKDAY:
        return _scheduleWeekday(now);
      case Schedule.WEEKLY:
        return _scheduleWeekly(now);
      case Schedule.MONTHLY:
        return _scheduleMonthly(now);
    }

    return null;
  }

  DateTime get _scheduleBeginDay =>
      getDateWithoutTime(DateTime.fromMillisecondsSinceEpoch(schedule.beginDate));

  DateTime _getNextTimeOnDay(DateTime day, DateTime fromNow) {
    // TODO (mike) investigate SignalTime.type (offset)
    if (day.isAfter(fromNow)) {
      // Return first time on day
      if (schedule.signalTimes.isNotEmpty) {
        return day.add(Duration(milliseconds: schedule.signalTimes.first.fixedTimeMillisFromMidnight));
      }
      return null;
    } else {
      // Return first time on day after fromNow
      final nowTimeOnDay = mixDateWithTime(day, fromNow);
      for (var time in schedule.signalTimes) {
        final dt = day.add(Duration(milliseconds: time.fixedTimeMillisFromMidnight));
        if (dt.isAtSameMomentAs(nowTimeOnDay) || dt.isAfter(nowTimeOnDay)) {
          return dt;
        }
      }
    }
    return null;
  }

  DateTime _getNextDailyScheduleDay(DateTime fromNow) {
    final fromDay = getDateWithoutTime(fromNow);
    if (schedule.repeatRate == 1) {
      return fromDay;
    }
    final offsetToNextDay = fromDay.difference(_scheduleBeginDay).inDays % schedule.repeatRate;
    if (offsetToNextDay == 0) {
      return fromDay;
    }
{'fraction_non_alphanumeric': 0.09858459512837393, 'fraction_numerical': 0.0009874917709019092, 'mean_word_length': 2.8437697659709045, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3629534', 'n_tokens_mistral': 1837, 'n_tokens_neox': 1775, 'n_words': 384}