"""Response-time analysis under the assumptions stated in the article."""
from dataclasses import dataclass
from math import ceil


@dataclass(frozen=True)
class Task:
    name: str
    cost: int
    period: int
    deadline: int
    blocking: int = 0


def analyze(tasks):
    # Input order is descending urgency; periods must match that order for RM.
    result = []
    for index, task in enumerate(tasks):
        if min(task.cost, task.period, task.deadline) <= 0 or task.blocking < 0:
            raise ValueError("invalid task parameters")
        response = task.cost + task.blocking
        while response <= task.deadline:
            following = task.cost + task.blocking + sum(
                ceil(response / higher.period) * higher.cost
                for higher in tasks[:index])
            if following == response:
                break
            response = following
        result.append((task.name, response, response <= task.deadline))
    return result


def main():
    normal = [Task("sample", 1, 4, 4), Task("process", 2, 8, 8),
              Task("upload", 2, 16, 16)]
    report = analyze(normal)
    assert [row[1] for row in report] == [1, 3, 6]
    assert all(row[2] for row in report)
    overloaded = [Task("sample", 2, 4, 4), Task("process", 3, 8, 8),
                  Task("upload", 5, 16, 16)]
    assert not all(row[2] for row in analyze(overloaded))
    blocked = [Task("sample", 1, 4, 4, blocking=4), *normal[1:]]
    assert not analyze(blocked)[0][2]
    print(f"normal={report}; overload and blocking counterexamples rejected")
    print("PASS")


if __name__ == "__main__":
    main()
