"""
================================================================================
File: 03_break_continue.py
Topic: Loop Control Statements - break, continue, pass
================================================================================

This file demonstrates loop control statements that alter the normal flow
of loop execution. These are essential tools for writing efficient and
readable loops.

Key Concepts:
- break: Exit the loop immediately
- continue: Skip to the next iteration
- pass: Do nothing (placeholder)
- Practical use cases for each

================================================================================
"""

# -----------------------------------------------------------------------------
# 1. The break Statement
# -----------------------------------------------------------------------------
# Immediately exits the loop, skipping any remaining iterations

print("--- The break Statement ---")

# Example 1: Exit when target is found
print("Finding first even number:")
numbers = [1, 3, 5, 8, 9, 10]

for num in numbers:
    print(f"  Checking {num}...", end=" ")
    if num % 2 == 0:
        print(f"Found! {num} is even.")
        break
    print("Odd, continuing...")

# Example 2: Exit on specific condition
print("\nSearching for name 'Charlie':")
names = ["Alice", "Bob", "Charlie", "David", "Eve"]

for name in names:
    if name == "Charlie":
        print(f"  ✓ Found '{name}'!")
        break
    print(f"  Checking '{name}'...")

# -----------------------------------------------------------------------------
# 2. The continue Statement  
# -----------------------------------------------------------------------------
# Skips the rest of the current iteration and moves to the next

print("\n--- The continue Statement ---")

# Example 1: Skip negative numbers
print("Processing only positive numbers:")
values = [5, -2, 8, -1, 10, -3, 7]

for value in values:
    if value < 0:
        print(f"  Skipping {value} (negative)")
        continue
    print(f"  Processing {value}")

# Example 2: Skip specific items
print("\nPrinting all fruits except banana:")
fruits = ["apple", "banana", "cherry", "banana", "date"]

for fruit in fruits:
    if fruit == "banana":
        continue
    print(f"  {fruit}")

# -----------------------------------------------------------------------------
# 3. The pass Statement
# -----------------------------------------------------------------------------
# Does nothing - used as a placeholder

print("\n--- The pass Statement ---")

# Example 1: Placeholder in empty function/class
class FutureFeature:
    pass  # Will implement later

def not_implemented_yet():
    pass  # Placeholder for future code

# Example 2: Explicit "do nothing" in conditionals
print("Processing numbers (ignoring zeros for now):")
numbers = [1, 0, 2, 0, 3]

for num in numbers:
    if num == 0:
        pass  # Explicitly do nothing (could be a TODO)
    else:
        print(f"  Number: {num}")

# -----------------------------------------------------------------------------
# 4. break vs continue - Side by Side Comparison
# -----------------------------------------------------------------------------

print("\n--- break vs continue Comparison ---")

data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# With break - stops at 5
print("With break (stop at 5):")
for num in data:
    if num == 5:
        break
    print(num, end=" ")
print()

# With continue - skips 5
print("With continue (skip 5):")
for num in data:
    if num == 5:
        continue
    print(num, end=" ")
print()

# -----------------------------------------------------------------------------
# 5. break with while Loops
# -----------------------------------------------------------------------------

print("\n--- break with while Loops ---")

# Breaking out of an infinite loop
print("Processing until 'quit' command:")
commands = ["start", "process", "load", "quit", "save"]
index = 0

while True:
    command = commands[index]
    print(f"  Command: {command}")
    
    if command == "quit":
        print("  ↳ Exiting loop...")
        break
    
    index += 1

# -----------------------------------------------------------------------------
# 6. continue with while Loops
# -----------------------------------------------------------------------------

print("\n--- continue with while Loops ---")

# Skip multiples of 3
print("Numbers 1-10 (skipping multiples of 3):")
i = 0
while i < 10:
    i += 1
    if i % 3 == 0:
        continue
    print(i, end=" ")
print()

# -----------------------------------------------------------------------------
# 7. Nested Loops with break
# -----------------------------------------------------------------------------
# break only exits the innermost loop

print("\n--- Nested Loops with break ---")

print("Breaking inner loop only:")
for i in range(1, 4):
    print(f"  Outer loop: i = {i}")
    for j in range(1, 4):
        if j == 2:
            print("    ↳ Breaking inner loop at j = 2")
            break
        print(f"    Inner loop: j = {j}")

# Using a flag to break outer loop
print("\nBreaking outer loop with flag:")
stop_outer = False

for i in range(1, 4):
    if stop_outer:
        break
    for j in range(1, 4):
        print(f"  i={i}, j={j}")
        if i == 2 and j == 2:
            print("  ↳ Breaking both loops!")
            stop_outer = True
            break

# -----------------------------------------------------------------------------
# 8. for-else with break
# -----------------------------------------------------------------------------
# else block runs only if loop completes without break

print("\n--- for-else with break ---")

# Example: Searching for a prime number
def is_prime(n):
    """Check if n is prime."""
    if n < 2:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False  # Found a divisor, not prime
    return True  # No divisors found, is prime

# Search for first prime in list
numbers = [4, 6, 8, 9, 11, 12]
print(f"Searching for prime in {numbers}:")

for num in numbers:
    if is_prime(num):
        print(f"  → First prime found: {num}")
        break
else:
    print("  → No primes found in the list")

# -----------------------------------------------------------------------------
# 9. Practical Example: Input Validation
# -----------------------------------------------------------------------------

print("\n--- Practical Example: Input Validation ---")

# Simulating user input validation
test_inputs = ["abc", "-5", "150", "42"]
print("Validating inputs (must be 1-100):")

for input_str in test_inputs:
    print(f"\n  Input: '{input_str}'")
    
    # Check if it's a number
    if not input_str.lstrip('-').isdigit():
        print("    ✗ Error: Not a valid number")
        continue
    
    value = int(input_str)
    
    # Check range
    if value < 1:
        print("    ✗ Error: Too low (must be >= 1)")
        continue
    
    if value > 100:
        print("    ✗ Error: Too high (must be <= 100)")
        continue
    
    print(f"    ✓ Valid input: {value}")
    break
else:
    print("\n  No valid input found!")

# -----------------------------------------------------------------------------
# 10. Practical Example: Skip Processing on Error
# -----------------------------------------------------------------------------

print("\n--- Practical Example: Error Handling ---")

# Processing a list of files (simulated)
files = [
    {"name": "data1.csv", "readable": True},
    {"name": "data2.csv", "readable": False},  # Error
    {"name": "data3.csv", "readable": True},
    {"name": "corrupt.csv", "readable": True, "corrupt": True},  # Error
    {"name": "data4.csv", "readable": True},
]

print("Processing files:")
processed_count = 0

for file in files:
    name = file["name"]
    
    # Skip unreadable files
    if not file.get("readable", False):
        print(f"  ✗ {name}: Cannot read file, skipping...")
        continue
    
    # Skip corrupt files
    if file.get("corrupt", False):
        print(f"  ✗ {name}: File is corrupt, skipping...")
        continue
    
    # Process the file
    print(f"  ✓ {name}: Processing complete")
    processed_count += 1

print(f"\nTotal files processed: {processed_count}/{len(files)}")
