// 18_Exceptions.java - חריגות (Exceptions)

public class Exceptions {
    public static void main(String[] args) {
        // try / catch בסיסי
        try {
            int[] arr = {1, 2, 3};
            System.out.println(arr[5]);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("שגיאה: אינדקס לא קיים");
        }

        // חלוקה באפס (לשלמים)
        try {
            int result = 10 / 0;
            System.out.println(result);
        } catch (ArithmeticException e) {
            System.out.println("שגיאה: " + e.getMessage());
        }

        // NumberFormatException
        try {
            int n = Integer.parseInt("abc");
        } catch (NumberFormatException e) {
            System.out.println("שגיאה: לא מספר תקין");
        }

        // NullPointerException
        try {
            String s = null;
            int len = s.length();
        } catch (NullPointerException e) {
            System.out.println("שגיאה: נסיון לגשת ל-null");
        }

        // מספר catches
        try {
            String input = "12a";
            int value = Integer.parseInt(input);
            int[] arr = new int[2];
            arr[value] = 100;
        } catch (NumberFormatException e) {
            System.out.println("\nהמרה נכשלה: " + e.getMessage());
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("\nאינדקס לא תקין");
        } catch (Exception e) {
            System.out.println("\nשגיאה כללית");
        }

        // try / catch / finally
        try {
            System.out.println("\nבלוק try");
            throw new RuntimeException("שגיאה יזומה");
        } catch (RuntimeException e) {
            System.out.println("נתפסה: " + e.getMessage());
        } finally {
            System.out.println("finally רץ תמיד");
        }

        // קריאה לפונקציות שזורקות חריגות
        try {
            double result = divide(10, 2);
            System.out.println("\n10 / 2 = " + result);

            result = divide(10, 0);
            System.out.println("10 / 0 = " + result);
        } catch (IllegalArgumentException e) {
            System.out.println("שגיאה: " + e.getMessage());
        }

        // חריגה מותאמת אישית
        try {
            BankAccount acc = new BankAccount(100);
            acc.withdraw(50);
            System.out.println("\nיתרה: " + acc.getBalance());
            acc.withdraw(200);
        } catch (InsufficientFundsException e) {
            System.out.println("שגיאה: " + e.getMessage());
        }

        System.out.println("\nהתוכנית הסתיימה תקין");
    }

    // פונקציה שזורקת חריגה
    public static double divide(double a, double b) {
        if (b == 0) {
            throw new IllegalArgumentException("אי אפשר לחלק באפס");
        }
        return a / b;
    }
}

// חריגה מותאמת אישית
class InsufficientFundsException extends Exception {
    public InsufficientFundsException(String message) {
        super(message);
    }
}

class BankAccount {
    private double balance;

    public BankAccount(double initial) {
        this.balance = initial;
    }

    public void withdraw(double amount) throws InsufficientFundsException {
        if (amount > balance) {
            throw new InsufficientFundsException(
                "אין מספיק כסף: מבקש " + amount + ", יתרה " + balance
            );
        }
        balance -= amount;
    }

    public double getBalance() {
        return balance;
    }
}
