"""Calculate the time for each stroke and then the SPM."""

nameplate_hz = 120.0
nameplate_rpm = 1200.0

approach_freq = 20

total_stroke_length = 60
offset_top = 2
offset_bottom = 2

accel_time = 2.0
decel_time = 2.0

thread_pitch = 0.5906


def time_for_freq_change(freq_delta, np_hz, ramp_time):
    """Calculate the time required for a frequency change."""
    return (freq_delta / np_hz) * ramp_time


def dist_for_freq_change(freq_delta, ramp_time, np_hz, np_rpm, thread_pitch):
    """Calculate the distance required for a frequency change."""
    time_required = time_for_freq_change(freq_delta, np_hz, ramp_time)
    return 0.75 * freq_delta * (np_rpm / np_hz) * (1.0 / 60.0) * time_required * thread_pitch


def time_for_uniform_freq(freq, distance, np_hz, np_rpm, thread_pitch):
    """Calculate the time required to move a distance at a frequency."""
    return distance / (freq * (np_rpm / np_hz) * (1.0 / 60.0) * thread_pitch)


def calculate_stroke_time(stroke_length, upper_offset, lower_offset, run_frequency, ramp_frequency, accel_time, decel_time):
    """Calculate the time it takes to make a full stroke."""
    ramp_up_time = time_for_freq_change(run_frequency, nameplate_hz, accel_time)
    ramp_up_dist = dist_for_freq_change(run_frequency, accel_time, nameplate_hz, nameplate_rpm, thread_pitch)

    ramp_down_time = time_for_freq_change(run_frequency - ramp_frequency, nameplate_hz, decel_time)
    ramp_down_dist = dist_for_freq_change(run_frequency - ramp_frequency, decel_time, nameplate_hz, nameplate_rpm, thread_pitch)

    turn_time = time_for_freq_change(ramp_frequency, nameplate_hz, decel_time)
    turn_dist = dist_for_freq_change(ramp_frequency, decel_time, nameplate_hz, nameplate_rpm, thread_pitch)

    run_dist = total_stroke_length - (offset_bottom + offset_top + ramp_up_dist + ramp_down_dist + turn_dist)
    run_time = time_for_uniform_freq(run_frequency, run_dist, nameplate_hz, nameplate_rpm, thread_pitch)

    stroke_time = 2.0 * (ramp_up_time + run_time + ramp_down_time + turn_time)
    return stroke_time


for ramp_i in [0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0]:
    print("-----")
    print("Ramp Rate: {}".format(ramp_i))
    for hz_i in [20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0, 120.0]:
        spm = 60 / calculate_stroke_time(total_stroke_length, offset_top, offset_bottom, hz_i, approach_freq, ramp_i, ramp_i)
        print("Freq: {} Hz., SPM: {}".format(hz_i, spm))
