import java.util.*;

/**
 * IT6003 - Advanced Java Programming
 * Practice Exercises: Collections Framework
 *
 * Instructions:
 *   - Implement each method where you see the // TODO comment.
 *   - Do NOT change the method signatures.
 *   - Run main() to test your implementations.
 */
public class ExercisesCollections {

    // ──────────────────────────────────────────────
    // Helper class used by several exercises
    // ──────────────────────────────────────────────
    static class Student {
        String name;
        String regNo;
        double gpa;

        Student(String name, String regNo, double gpa) {
            this.name = name;
            this.regNo = regNo;
            this.gpa = gpa;
        }

        @Override
        public String toString() {
            return name + " (" + regNo + ", GPA: " + gpa + ")";
        }
    }

    // ──────────────────────────────────────────────
    // Exercise 1: Remove Even Numbers Using Iterator
    // ──────────────────────────────────────────────
    /**
     * Create an ArrayList of integers containing the numbers 1 through 10.
     * Use an Iterator to remove all even numbers from the list.
     *
     * @return the list containing only odd numbers
     */
    public static List<Integer> removeEvenNumbers() {
        // TODO: Create an ArrayList with numbers 1-10,
        //       iterate using an Iterator, remove even numbers,
        //       and return the resulting list.
        return null;
    }

    // ──────────────────────────────────────────────
    // Exercise 2: Word Frequency Counter
    // ──────────────────────────────────────────────
    /**
     * Count the frequency of each word in the given sentence.
     * Convert words to lowercase before counting.
     *
     * @param sentence a string of words separated by spaces
     * @return a HashMap mapping each word to its count
     */
    public static Map<String, Integer> countWordFrequency(String sentence) {
        // TODO: Split the sentence into words, convert to lowercase,
        //       count each word's frequency using a HashMap,
        //       and return the map.
        return null;
    }

    // ──────────────────────────────────────────────
    // Exercise 3: Remove Duplicates Using HashSet
    // ──────────────────────────────────────────────
    /**
     * Remove duplicate elements from the given list while preserving
     * the original order of first occurrences.
     *
     * @param list a list that may contain duplicates
     * @return a new list with duplicates removed (order preserved)
     */
    public static <T> List<T> removeDuplicates(List<T> list) {
        // TODO: Use a LinkedHashSet (or HashSet + new list) to remove
        //       duplicates while keeping the first-occurrence order.
        return null;
    }

    // ──────────────────────────────────────────────
    // Exercise 4: Sort Students by GPA (Descending)
    // ──────────────────────────────────────────────
    /**
     * Sort the given list of Student objects by GPA in descending order.
     * Use a Comparator.
     *
     * @param students the list to sort
     * @return the sorted list (highest GPA first)
     */
    public static List<Student> sortByGpaDescending(List<Student> students) {
        // TODO: Sort the list using a Comparator that compares
        //       students by gpa in descending order. Return the list.
        return null;
    }

    // ──────────────────────────────────────────────
    // Exercise 5: Phone Book Using TreeMap
    // ──────────────────────────────────────────────
    /**
     * Build a simple phone book from the given arrays of names and phones.
     * Use a TreeMap so that entries are stored in alphabetical order by name.
     *
     * @param names  array of contact names
     * @param phones array of phone numbers (same length as names)
     * @return a TreeMap mapping name -> phone
     */
    public static TreeMap<String, String> buildPhoneBook(String[] names, String[] phones) {
        // TODO: Create a TreeMap, populate it from the two arrays,
        //       and return it.
        return null;
    }

    // ──────────────────────────────────────────────
    // Exercise 6: Intersection of Two Sets
    // ──────────────────────────────────────────────
    /**
     * Find the intersection of two sets (elements present in both).
     *
     * @param setA first set
     * @param setB second set
     * @return a new set containing only elements in both setA and setB
     */
    public static <T> Set<T> intersection(Set<T> setA, Set<T> setB) {
        // TODO: Create a new HashSet from setA, then use retainAll()
        //       to keep only elements also in setB. Return the result.
        return null;
    }

    // ──────────────────────────────────────────────
    // Exercise 7: PriorityQueue Task Processing
    // ──────────────────────────────────────────────
    /**
     * Given an array of task names and an array of priorities (lower number =
     * higher priority), process them using a PriorityQueue and return the
     * task names in priority order.
     *
     * Hint: Create a small helper class or use Map.Entry / int[] pairs.
     *
     * @param tasks      array of task names
     * @param priorities array of priority values (same length)
     * @return list of task names ordered from highest to lowest priority
     */
    public static List<String> processByPriority(String[] tasks, int[] priorities) {
        // TODO: Add tasks with their priorities into a PriorityQueue,
        //       poll them one by one, and return the ordered list of names.
        return null;
    }

    // ──────────────────────────────────────────────
    // Exercise 8: Reverse a List Manually
    // ──────────────────────────────────────────────
    /**
     * Reverse the given list without using Collections.reverse().
     *
     * @param list the list to reverse
     * @return a new list with elements in reverse order
     */
    public static <T> List<T> reverseList(List<T> list) {
        // TODO: Create a new ArrayList and populate it with elements
        //       from the input list in reverse order. Do NOT use
        //       Collections.reverse(). Return the reversed list.
        return null;
    }

    // ──────────────────────────────────────────────
    // Exercise 9: Most Frequent Element
    // ──────────────────────────────────────────────
    /**
     * Find the most frequently occurring element in the given list.
     * If there is a tie, return any one of the most frequent elements.
     *
     * @param list the input list
     * @return the element that appears most often
     */
    public static <T> T mostFrequent(List<T> list) {
        // TODO: Use a HashMap to count occurrences of each element,
        //       then find and return the element with the highest count.
        return null;
    }

    // ──────────────────────────────────────────────
    // Exercise 10: Sort Map Entries by Value
    // ──────────────────────────────────────────────
    /**
     * Convert the given map to a list of Map.Entry objects sorted by
     * value in ascending order.
     *
     * @param map a map with comparable values
     * @return list of entries sorted by value ascending
     */
    public static <K, V extends Comparable<V>> List<Map.Entry<K, V>> sortByValue(Map<K, V> map) {
        // TODO: Create a list from map.entrySet(), sort it using a
        //       Comparator that compares entries by their values,
        //       and return the sorted list.
        return null;
    }

    // ──────────────────────────────────────────────
    // Main – test your implementations here
    // ──────────────────────────────────────────────
    public static void main(String[] args) {

        System.out.println("=== Exercise 1: Remove Even Numbers ===");
        List<Integer> odds = removeEvenNumbers();
        System.out.println("Odd numbers: " + odds);
        // Expected: [1, 3, 5, 7, 9]

        System.out.println("\n=== Exercise 2: Word Frequency ===");
        String sentence = "the cat sat on the mat the cat";
        Map<String, Integer> freq = countWordFrequency(sentence);
        System.out.println("Frequencies: " + freq);
        // Expected: {the=3, cat=2, sat=1, on=1, mat=1}

        System.out.println("\n=== Exercise 3: Remove Duplicates ===");
        List<Integer> withDups = Arrays.asList(1, 3, 5, 3, 1, 7, 5, 9);
        List<Integer> noDups = removeDuplicates(withDups);
        System.out.println("Without duplicates: " + noDups);
        // Expected: [1, 3, 5, 7, 9]

        System.out.println("\n=== Exercise 4: Sort Students by GPA ===");
        List<Student> students = new ArrayList<>(Arrays.asList(
            new Student("Ali", "SUZA-001", 3.2),
            new Student("Fatma", "SUZA-002", 3.8),
            new Student("Hassan", "SUZA-003", 2.9),
            new Student("Zainab", "SUZA-004", 3.5)
        ));
        List<Student> sorted = sortByGpaDescending(students);
        System.out.println("Sorted by GPA (desc): " + sorted);
        // Expected: Fatma, Zainab, Ali, Hassan

        System.out.println("\n=== Exercise 5: Phone Book (TreeMap) ===");
        String[] names = {"Zainab", "Ali", "Hassan", "Fatma"};
        String[] phones = {"0777-111", "0777-222", "0777-333", "0777-444"};
        TreeMap<String, String> phoneBook = buildPhoneBook(names, phones);
        System.out.println("Phone book: " + phoneBook);
        // Expected: {Ali=0777-222, Fatma=0777-444, Hassan=0777-333, Zainab=0777-111}

        System.out.println("\n=== Exercise 6: Set Intersection ===");
        Set<Integer> setA = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
        Set<Integer> setB = new HashSet<>(Arrays.asList(3, 4, 5, 6, 7));
        Set<Integer> common = intersection(setA, setB);
        System.out.println("Intersection: " + common);
        // Expected: [3, 4, 5]

        System.out.println("\n=== Exercise 7: PriorityQueue Tasks ===");
        String[] tasks = {"Write report", "Fix bug", "Deploy", "Code review"};
        int[] priorities = {3, 1, 4, 2};
        List<String> ordered = processByPriority(tasks, priorities);
        System.out.println("Tasks by priority: " + ordered);
        // Expected: [Fix bug, Code review, Write report, Deploy]

        System.out.println("\n=== Exercise 8: Reverse List ===");
        List<String> original = Arrays.asList("A", "B", "C", "D", "E");
        List<String> reversed = reverseList(original);
        System.out.println("Reversed: " + reversed);
        // Expected: [E, D, C, B, A]

        System.out.println("\n=== Exercise 9: Most Frequent Element ===");
        List<String> items = Arrays.asList("apple", "banana", "apple", "cherry", "banana", "apple");
        String mostFreq = mostFrequent(items);
        System.out.println("Most frequent: " + mostFreq);
        // Expected: apple

        System.out.println("\n=== Exercise 10: Sort Map by Value ===");
        Map<String, Integer> scores = new HashMap<>();
        scores.put("Ali", 75);
        scores.put("Fatma", 92);
        scores.put("Hassan", 68);
        scores.put("Zainab", 85);
        List<Map.Entry<String, Integer>> sortedEntries = sortByValue(scores);
        System.out.println("Sorted by value: " + sortedEntries);
        // Expected: Hassan=68, Ali=75, Zainab=85, Fatma=92
    }
}
