class Fluent::PluginHelper::RetryState::RetryStateMachine

def calc_next_time

def calc_next_time
  if @forever || !@secondary # primary
    naive = naive_next_time(@steps)
    if @forever
      naive
    elsif naive >= @timeout_at
      @timeout_at
    else
      naive
    end
  elsif @current == :primary && @secondary
    naive = naive_next_time(@steps)
    if naive >= @secondary_transition_at
      @secondary_transition_at
    else
      naive
    end
  elsif @current == :secondary
    naive = naive_next_time(@steps - @secondary_transition_steps + 1)
    if naive >= @timeout_at
      @timeout_at
    else
      naive
    end
  else
    raise "BUG: it's out of design"
  end
end

def current_time

def current_time
  Time.now
end

def initialize(title, wait, timeout, forever, max_steps, randomize, randomize_width, secondary, secondary_threshold)

def initialize(title, wait, timeout, forever, max_steps, randomize, randomize_width, secondary, secondary_threshold)
  @title = title
  @start = current_time
  @steps = 0
  @next_time = nil # should be initialized for first retry by child class
  @timeout = timeout
  @timeout_at = @start + timeout
  @current = :primary
  if randomize_width < 0 || randomize_width > 0.5
    raise "BUG: randomize_width MUST be between 0 and 0.5"
  end
  @randomize = randomize
  @randomize_width = randomize_width
  @forever = forever
  @max_steps = max_steps
  @secondary = secondary
  @secondary_threshold = secondary_threshold
  if @secondary
    raise "BUG: secondary_transition_threshold MUST be between 0 and 1" if @secondary_threshold <= 0 || @secondary_threshold >= 1
    max_retry_timeout = timeout
    if max_steps
      timeout_by_max_steps = calc_max_retry_timeout(max_steps)
      max_retry_timeout = timeout_by_max_steps if timeout_by_max_steps < max_retry_timeout
    end
    @secondary_transition_at = @start + max_retry_timeout * @secondary_threshold
    @secondary_transition_steps = nil
  end
end

def limit?

def limit?
  if @forever
    false
  else
    @next_time >= @timeout_at || !!(@max_steps && @steps >= @max_steps)
  end
end

def naive_next_time(retry_times)

def naive_next_time(retry_times)
  raise NotImplementedError
end

def randomize(interval)

def randomize(interval)
  return interval unless @randomize
  interval + (interval * @randomize_width * (2 * rand - 1.0))
end

def secondary?

def secondary?
  !@forever && @secondary && (@current == :secondary || current_time >= @secondary_transition_at)
end

def step

def step
  @steps += 1
  if !@forever && @secondary && @current != :secondary && current_time >= @secondary_transition_at
    @current = :secondary
    @secondary_transition_steps = @steps
  end
  @next_time = calc_next_time
  nil
end