text: // Copyright 2018 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "chrome/browser/ui/views/relaunch_notification/relaunch_required_timer.h"
  
  #include <utility>
  
  #include "chrome/browser/ui/views/relaunch_notification/relaunch_required_timer_internal.h"
  #include "chrome/grit/chromium_strings.h"
  #include "chrome/grit/generated_resources.h"
  #include "ui/base/l10n/l10n_util.h"
  
  RelaunchRequiredTimer::RelaunchRequiredTimer(base::Time deadline,
                                               base::RepeatingClosure callback)
      : deadline_(deadline), callback_(std::move(callback)) {
    ScheduleNextTitleRefresh();
  }
  
  RelaunchRequiredTimer::~RelaunchRequiredTimer() {}
  
  void RelaunchRequiredTimer::ScheduleNextTitleRefresh() {
    // Refresh at the next second, minute, hour, or day boundary; depending on the
    // relaunch deadline.
    const base::Time now = base::Time::Now();
    const base::TimeDelta deadline_offset = deadline_ - now;
  
    // Don't start the timer if the deadline is in the past or right now.
    if (deadline_offset <= base::TimeDelta())
      return;
  
    const base::TimeDelta refresh_delta =
        relaunch_notification::ComputeNextRefreshDelta(deadline_offset);
  
    refresh_timer_.Start(FROM_HERE, now + refresh_delta, this,
                         &RelaunchRequiredTimer::OnTitleRefresh);
  }
  
  void RelaunchRequiredTimer::SetDeadline(base::Time deadline) {
    if (deadline != deadline_) {
      deadline_ = deadline;
      // Refresh the title immediately.
      OnTitleRefresh();
    }
  }
  
  base::string16 RelaunchRequiredTimer::GetWindowTitle() const {
    // Round the time-to-relaunch to the nearest "boundary", which may be a day,
    // hour, minute, or second. For example, two days and eighteen hours will be
    // rounded up to three days, while two days and one hour will be rounded down
    // to two days. This rounding is significant for only the initial showing of
    // the dialog. Each refresh of the title thereafter will take place at the
    // moment when the boundary value changes. For example, the title will be
    // refreshed from three days to two days when there are exactly two days
    // remaning. This scales nicely to the final seconds, when one would expect a
    // "3..2..1.." countdown to change precisely on the per-second boundaries.
    const base::TimeDelta rounded_offset =
        relaunch_notification::ComputeDeadlineDelta(deadline_ -
                                                    base::Time::Now());
  
    int amount = rounded_offset.InSeconds();
    int message_id = IDS_RELAUNCH_REQUIRED_TITLE_SECONDS;
    if (rounded_offset.InDays() >= 2) {
      amount = rounded_offset.InDays();
      message_id = IDS_RELAUNCH_REQUIRED_TITLE_DAYS;
    } else if (rounded_offset.InHours() >= 1) {
      amount = rounded_offset.InHours();
      message_id = IDS_RELAUNCH_REQUIRED_TITLE_HOURS;
    } else if (rounded_offset.InMinutes() >= 1) {
      amount = rounded_offset.InMinutes();
      message_id = IDS_RELAUNCH_REQUIRED_TITLE_MINUTES;
    }
  
    return l10n_util::GetPluralStringFUTF16(message_id, amount);
  }
  
  void RelaunchRequiredTimer::OnTitleRefresh() {
    callback_.Run();
    ScheduleNextTitleRefresh();
  }
  