package io.citrine.jpif.obj.merge;

import io.citrine.jpif.obj.common.Pio;

import java.util.ArrayList;
import java.util.List;

/**
 * An enumeration of supported merge strategies.
 *
 * @author Sean Paradiso
 */
public enum MergeStrategy {

    // Conflicting objects are replaced if the merge source
    // is non-null and all objects in matching lists are appended
    REPLACE_NON_NULL_AND_APPEND {
        /**
         * Merge two lists.
         * @param mergeInto the destination list.
         * @param mergeFrom the source list.
         * @return the merge result.
         */
        @Override
        public List<Object> mergeLists(List<Object> mergeInto, List<Object> mergeFrom) {
            List<Object> result = new ArrayList<>();

            if (mergeInto != null) {
                result.addAll(mergeInto);
            }

            if (mergeFrom != null) {
                result.addAll(mergeFrom);
            }
            return result;
        }

        /**
         * Merge two Pio objects.
         *
         * @param mergeInto the destination object.
         * @param mergeFrom the source object.
         * @return the merge result.
         */
        @Override
        public Pio mergePio(Pio mergeInto, Pio mergeFrom) {
            if (mergeFrom != null) {
                return mergeFrom;
            }
            return mergeInto;
        }

        /**
         * Merge two objects.
         *
         * @param mergeInto the destination object.
         * @param mergeFrom the source object.
         * @return the merge result.
         */
        @Override
        protected Object mergeObject(Object mergeInto, Object mergeFrom) {
            if (mergeFrom != null) {
                return mergeFrom;
            }
            return mergeInto;
        }
    };

    /**
     * Merge two lists.
     *
     * @param mergeInto the destination list.
     * @param mergeFrom the source list.
     * @return the merge result.
     */
    public abstract List<Object> mergeLists(List<Object> mergeInto, List<Object> mergeFrom);

    /**
     * Merge two Pio objects.
     *
     * @param mergeInto the destination object.
     * @param mergeFrom the source object.
     * @return the merge result.
     */
    protected abstract Pio mergePio(Pio mergeInto, Pio mergeFrom);

    /**
     * Merge two objects that are _not_ Pio instances.
     *
     * @param mergeInto the destination object.
     * @param mergeFrom the source object.
     * @return the merge result.
     */
    protected abstract Object mergeObject(Object mergeInto, Object mergeFrom);

    /**
     * Merge two objects as fields from Pio instances.
     *
     * @param mergeInto the destination object.
     * @param mergeFrom the source object.
     * @return the merge result.
     */
    public Object merge(Object mergeInto, Object mergeFrom) {
        if (mergeInto instanceof Pio) {
            return mergePio((Pio) mergeInto, (Pio) mergeFrom);
        } else {
            return mergeObject(mergeInto, mergeFrom);
        }
    }
}

@@ -114,20 +114,68 @@
 va.util.
-List
+HashMap;%0Aimport java.util.List;%0Aimport java.util.Map
 ;%0A%0A/**%0A 
@@ -447,192 +447,8 @@
 D %7B%0A
-        /**%0A         * Merge two lists.%0A         * @param mergeInto the destination list.%0A         * @param mergeFrom the source list.%0A         * @return the merge result.%0A         */%0A
     
@@ -486,37 +486,32 @@
 st%3CObject%3E merge
-Lists
 (List%3CObject%3E me
@@ -828,213 +828,8 @@
  %7D%0A%0A
-        /**%0A         * Merge two Pio objects.%0A         *%0A         * @param mergeInto the destination object.%0A         * @param mergeFrom the source object.%0A         * @return the merge result.%0A         */%0A
     
@@ -858,35 +858,32 @@
 public Pio merge
-Pio
 (Pio mergeInto, 
@@ -1037,152 +1037,260 @@
     
-/**%0A         * Merge two objects.%0A         *%0A         * @param mergeInto the destination object.%0A         * @param mergeFrom the source object.%0A
+@Override%0A        public Map%3CString, Object%3E merge(Map%3CString, Object%3E mergeInto, Map%3CString, Object%3E mergeFrom) %7B%0A            Map%3CString, Object%3E result = new HashMap%3C%3E();%0A            result.putAll(mergeInto);%0A            result.putAll(mergeFrom);%0A   
     
@@ -1298,35 +1298,22 @@
     
-* @
 return 
-the merge 
 result
-.
+;
 %0A   
@@ -1313,27 +1313,26 @@
 lt;%0A        
- */
+%7D%0A
 %0A        @Ov
@@ -1347,24 +1347,21 @@
        p
-rotected
+ublic
  Object 
@@ -1357,38 +1357,32 @@
 lic Object merge
-Object
 (Object mergeInt
@@ -1746,13 +1746,8 @@
 erge
-Lists
 (Lis
@@ -1971,32 +1971,29 @@
     */%0A    p
-rotected
+ublic
  abstract Pi
@@ -1999,19 +1999,16 @@
 io merge
-Pio
 (Pio mer
@@ -2061,43 +2061,11 @@
 two 
-objects that are _not_ Pio instance
+Map
 s.%0A 
@@ -2211,16 +2211,13 @@
    p
-rotected
+ublic
  abs
@@ -2225,34 +2225,54 @@
 ract
+ Map%3CString,
  Object
+%3E
  merge
-Object(
+(Map%3CString, 
 Object
+%3E
  mer
@@ -2270,39 +2270,52 @@
 ject%3E mergeInto,
+ Map%3CString,
  Object
+%3E
  mergeFrom);%0A%0A  
@@ -2349,22 +2349,22 @@
 cts 
-as fields from
+that are _not_
  Pio
@@ -2521,37 +2521,33 @@
 %0A    public 
-Object merge(
+abstract 
 Object merge
@@ -2538,38 +2538,33 @@
 act Object merge
-Into, 
+(
 Object mergeFrom
@@ -2563,204 +2563,31 @@
 erge
-From) %7B%0A        if (mergeInto instanceof Pio) %7B%0A            return mergePio((Pio) mergeInto, (Pio) mergeFrom);%0A        %7D else %7B%0A            return mergeObject(mergeInto, mergeFrom);%0A        %7D%0A    %7D
+Into, Object mergeFrom);
 %0A%7D%0A

Add support for map merging