
// MultiValuedMapTester.java
// https://www.baeldung.com/apache-commons-multi-valued-mvMap
// Andrew Davison, ad@coe.psu.ac.th, May 2023

/* MultiValuedMap maps a key to a collection of values.
   It's the successor to MultiMap, 
   which was deprecated in Commons Collection 4.1.

  Usage:
    > compile MultiValuedMapTester.java
    > run MultiValuedMapTester

   Other multi-map examples:
      * BidiMapTester.java
      * MultiKeyMapTester.java
      * PartialMultiKeyMapTester.java


   Also see:
     LRUMapTester.java
     OrderedMapTester.java
     ExpiringMapTester
     TransformedMapTester
     SplitMapTester
     PredicateMapTester.java
   and
     MapUtilsTester.java

*/

import java.util.*;

import org.apache.commons.collections4.*;
import org.apache.commons.collections4.multimap.*;


public class MultiValuedMapTester
{

  public static void main(String[] args) 
  {
    MultiValuedMap<String, String> mvMap = new ArrayListValuedHashMap<>();
    mvMap.put("fruit", "apple");
    mvMap.put("fruit", "orange");
    mvMap.putAll("vehicles", Arrays.asList("car", "bike"));
    System.out.println("mvMap: " + mvMap);
    System.out.println("Get all fruits: " + mvMap.get("fruit"));
    System.out.println("Get all vehicles: " + mvMap.get("vehicles"));

    // --------------------

    MultiSet<String> keysSet = mvMap.keys();
    System.out.println("\nMultiset of keys: " + keysSet);

    Set<String> keys = mvMap.keySet();
    System.out.println("\nSet of keys: " + keys);

    System.out.println("\nKey access to each value:");
    for(String k : mvMap.keySet()) {
       System.out.print(" " + k + ": ");
       Collection<String> vals = mvMap.get(k);
       for(String val : vals)
         System.out.print(val + " ");
       System.out.println();
    }

    // --------------------
    // get `java.util.Map` view of the `MultiValuedMap`
    Map<String, Collection<String>> jmap = mvMap.asMap();
    System.out.println("\nJava Map version: " + jmap);
    // add more fruit
    System.out.println("Add fruit-pear:");
    jmap.get("fruit").add("pear");
    System.out.println("java map Fruits: " + jmap.get("fruit"));
    // mvMap also updated
    System.out.println("mvMap also changed Fruits: " + mvMap.get("fruit"));

    // --------------------

    System.out.println("\nCopy the map");
    HashMap<String, List<String>> copyMap = new HashMap<>();
    for(String k : mvMap.keySet()) {
       List<String> vals = new ArrayList<>(
                     MultiMapUtils.getValuesAsList(mvMap, k));
       copyMap.put(k, vals);
    }
    System.out.println("Add fruit-lemon to copy:");
    copyMap.get("fruit").add("lemon");
    System.out.println("copyMap Fruits: " + copyMap.get("fruit"));
    // mvMap NOT updated
    System.out.println("mvMap NOT changed Fruits: " + mvMap.get("fruit"));

    // --------------------

    System.out.println("\nRemoving values from mvMap");
    System.out.println("Remove fruit-apple");
    mvMap.removeMapping("fruit", "apple");
    System.out.println("All values in mvMap: " + mvMap.values());

    System.out.println("Remove all fruits");
    mvMap.remove("fruit");
    System.out.println("Values: " + mvMap.values());

    System.out.println("\nClear mvMap");
    mvMap.clear();
    System.out.println("Is map empty: " + mvMap.isEmpty());
    System.out.println("Contains fruit? " + mvMap.containsKey("fruit"));
    System.out.println("Size: " + mvMap.size());

    // --------------------

    System.out.println("\nCreate a new map");
    MultiValuedMap<String, String> map2 = new HashSetValuedHashMap<>();
    map2.put("fruit", "apple");
    map2.put("fruit", "peach");
    System.out.println("map2: " + map2);

    System.out.println("Make unmodifiable, and try to add fruit-banana");
    MultiValuedMap<String, String> immutableMap =
      MultiMapUtils.unmodifiableMultiValuedMap(map2);

    try { immutableMap.put("fruit", "banana");  }
    catch(UnsupportedOperationException e)
    {  System.out.println(e);  }

    // --------------------

    List<Employee> emps = Arrays.asList(
            new Employee("Bob", "male", "USA"),
            new Employee("Larry", "male", "USA"),
            new Employee("Bill", "male", "USA"),
            new Employee("Sue", "female", "UK"),
            new Employee("Jim", "male", "USA"),
            new Employee("Jane", "female", "UK"),
            new Employee("Joe", "male", "UK"),
            new Employee("Zoe", "female", "MI"));
    System.out.println("\nemployees list: " + emps);

    // map is country --> multiple employees
    MultiValuedMap<String, Employee> locsMap = 
                          new ArrayListValuedHashMap<>();
    for (Employee emp : emps)
      locsMap.put(emp.getCountry(), emp);

    System.out.println("People grouped by country:");
    Set<String> countries = locsMap.keySet();
    for (String loc : countries)
      System.out.println(loc + ":  " + locsMap.get(loc));

  }  // end of main()

}  // end of MultiValuedMapTester class
