import os
import sys
import termios
import tty
import select
import time

def main():
    """Main function to run the OS Architecture slideshow."""
    
    if not sys.stdin.isatty():
        print("Error: This script must be run in an interactive terminal.")
        print("If using Docker, run the container with the '-it' flags: docker run -it ...")
        sys.exit(1)

    clear = lambda: os.system('clear')

    slides = [
        {
            "content": "OS Architecture: The Invisible Manager",
            "frames": [
r"""
   ___   ____     _                  _     
  / _ \ / ___|   / \   _ __ ___| |__  
 | | | |\___ \  / _ \ | '__/ __| '_ \ 
 | |_| | ___) |/ ___ \| | | (__| | | |
  \___/ |____//_/   \_\_|  \___|_| |_|
                                      
      The bridge between User and Metal.
""",
r"""
   ___   ____     _                  _     
  / _ \ / ___|   / \   _ __ ___| |__  
 | | | |\___ \  / _ \ | '__/ __| '_ \ 
 | |_| | ___) |/ ___ \| | | (__| | | |
  \___/ |____//_/   \_\_|  \___|_| |_|
      
      The bridge between User and Metal.
      LOADING KERNEL MODULES...
""",
r"""
   ___   ____     _                  _     
  / _ \ / ___|   / \   _ __ ___| |__  
 | | | |\___ \  / _ \ | '__/ __| '_ \ 
 | |_| | ___) |/ ___ \| | | (__| | | |
  \___/ |____//_/   \_\_|  \___|_| |_|
      
      The bridge between User and Metal.
      LOADING KERNEL MODULES... [OK]
"""
            ]
        },
        {
            "content": """The Dual Mode Operation: User vs. Kernel
    — To protect the system, the OS runs in two modes.
    — User Mode: Restricted access. Normal applications (Browser, Word).
    — Kernel Mode: Unrestricted access. Controls hardware directly.
    — The "System Call" is the gateway between the two.""",
            "frames": [
"""
    [ USER APPS ]       [   OS KERNEL   ]       [ HARDWARE ]
    +-----------+       +---------------+       +----------+
    |  Browser  |       |               |       |   DISK   |
    |           |       |               |       |   RAM    |
    +-----------+       +---------------+       +----------+
""",
"""
    [ USER APPS ]       [   OS KERNEL   ]       [ HARDWARE ]
    +-----------+       +---------------+       +----------+
    |  Browser  |  -->  |   SysCall()   |       |   DISK   |
    |  Save File|       |               |       |   RAM    |
    +-----------+       +---------------+       +----------+
""",
"""
    [ USER APPS ]       [   OS KERNEL   ]       [ HARDWARE ]
    +-----------+       +---------------+       +----------+
    |  Waiting  |       |   SysCall()   |  -->  |   DISK   |
    |    ...    |       |   Write()     |       | Spinning |
    +-----------+       +---------------+       +----------+
""",
"""
    [ USER APPS ]       [   OS KERNEL   ]       [ HARDWARE ]
    +-----------+       +---------------+       +----------+
    |  Browser  |  <--  |   Return      |  <--  |   DISK   |
    |  Success! |       |   Complete    |       |  Saved   |
    +-----------+       +---------------+       +----------+
"""
            ]
        },
        {
            "content": """Process Management: The Scheduler
    — The OS creates the illusion that many programs run at once.
    — It rapidly switches the CPU between processes (Context Switching).
    — A "Scheduler" decides who goes next.""",
            "frames": [
"""
      WAITING QUEUE             CPU (The Brain)
    +----------------+        +-----------------+
    | [P2] [P3] [P4] |        |  [ Process 1 ]  |
    +----------------+        +-----------------+
      (Music Player)             (Web Browser)
""",
"""
      WAITING QUEUE             CPU (The Brain)
    +----------------+        +-----------------+
    | [P2] [P3] [P4] |        |  [ Saving... ]  |
    +----------------+        +-----------------+
      (Music Player)             (Web Browser)
""",
"""
      * SWITCH! * CPU (The Brain)
    +----------------+        +-----------------+
    | [P3] [P4] [P1] |   <--  |  [ Process 2 ]  |
    +----------------+        +-----------------+
                           (Music Player)
""",
"""
      WAITING QUEUE             CPU (The Brain)
    +----------------+        +-----------------+
    | [P3] [P4] [P1] |        |  [ Decoding  ]  |
    +----------------+        +-----------------+
                                (Music Player)
"""
            ]
        },
        {
            "content": """Memory Management: Virtualization
    — Apps don't access RAM directly. They use "Virtual Addresses".
    — The OS (via MMU) maps these to physical RAM slots.
    — This prevents apps from crashing each other or stealing data.""",
            "frames": [
"""
    VIRTUAL MEMORY           MAP TABLE           PHYSICAL RAM
    (App's View)            (OS Logic)           (Real Chip)
    +------------+        +-------------+       +------------+
    | 0x00A: Data|   -->  |      ?      |       | Slot 1: ?? |
    +------------+        +-------------+       +------------+
""",
"""
    VIRTUAL MEMORY           MAP TABLE           PHYSICAL RAM
    (App's View)            (OS Logic)           (Real Chip)
    +------------+        +-------------+       +------------+
    | 0x00A: Data|   -->  | Check Perms |       | Slot 1: ?? |
    +------------+        +-------------+       +------------+
""",
"""
    VIRTUAL MEMORY           MAP TABLE           PHYSICAL RAM
    (App's View)            (OS Logic)           (Real Chip)
    +------------+        +-------------+       +------------+
    | 0x00A: Data|   ==>  | MAP: Slot 4 |  ==>  | Slot 4: OK |
    +------------+        +-------------+       +------------+
""",
"""
    VIRTUAL MEMORY           MAP TABLE           PHYSICAL RAM
    (App's View)            (OS Logic)           (Real Chip)
    +------------+        +-------------+       +------------+
    | 0x00A: Data|        | [  LOCKED ] |       | [STORED]   |
    +------------+        +-------------+       +------------+
"""
            ]
        }
    ]

    navigations = "Press 'n' to move to the next slide"
    animation_delay = 0.8  # Slightly slower for text readability

    for slide in slides:
        move_to_next_slide = False
        while not move_to_next_slide:
            for frame in slide["frames"]:
                clear()
                print(slide["content"])
                print(frame)
                print(navigations)

                user_input = read_input_with_timeout(animation_delay)
                
                if user_input == 'n':
                    move_to_next_slide = True
                    break
    
    clear()
    print("Presentation Finished.")

def read_input_with_timeout(timeout):
    """Waits for a single character of input for a given timeout period."""
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    try:
        tty.setcbreak(sys.stdin.fileno())
        if select.select([sys.stdin], [], [], timeout) == ([sys.stdin], [], []):
            return sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return None

if __name__ == "__main__":
    main()
