import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.*;

public class MisuseProperties {

    void propertiesToHashtable(Properties p) {
        // :: error: (argument.type.incompatible)
        p.setProperty("line.separator", null);
        // :: error: (argument.type.incompatible)
        p.put("line.separator", null);
        Hashtable h = p;
        // Error, because HashTable value has NonNull bound.
        // TODO: false negative. See #365.
        //// :: error: (argument.type.incompatible) :: warning: [unchecked] unchecked call to
        //// put(K,V) as a member of the raw type java.util.Hashtable
        // :: warning: [unchecked] unchecked call to put(K,V) as a member of the raw type
        // java.util.Hashtable
        h.put("line.separator", null);
        // :: error: (argument.type.incompatible)
        System.setProperty("line.separator", null);

        Dictionary d1 = p;
        // No error, because Dictionary value has Nullable bound.
        // :: warning: [unchecked] unchecked call to put(K,V) as a member of the raw type
        // java.util.Dictionary
        d1.put("line.separator", null);

        // :: error: (assignment.type.incompatible)
        Dictionary<Object, @Nullable Object> d2 = p;
        d2.put("line.separator", null);

        System.setProperties(p); // OK; p has no null values

        System.clearProperty("foo.bar"); // OK

        // Each of the following should cause an error, because it leaves
        // line.separator null.

        // These first few need to be special-cased, I think:

        System.clearProperty("line.separator");

        p.remove("line.separator");
        p.clear();

        // These are OK because they seem to only add, not remove, properties:
        // p.load(InputStream), p.load(Reader), p.loadFromXML(InputStream)

        // The following problems are a result of treating a Properties as one
        // of its supertypes.  Here are some solutions:
        //  * Forbid treating a Properties object as any of its supertypes.
        //  * Create an annotation on a Properties object, such as
        //    @HasSystemProperties, and forbid some operations (or any
        //    treatment as a supertype) for such properties.

        Set<@KeyFor("p") Object> keys = p.keySet();
        // now remove  "line.separator" from the set
        keys.remove("line.separator");
        keys.removeAll(keys);
        keys.clear();
        keys.retainAll(Collections.EMPTY_SET);

        Set<Map.Entry<@KeyFor("p") Object, Object>> entries = p.entrySet();
        // now remove the pair containing "line.separator" from the set, as above

        Collection<Object> values = p.values();
        // now remove the line separator value from values, as above

        Hashtable h9 = p;
        h9.remove("line.separator");
        h9.clear();
        // also access via entrySet, keySet, values

        Dictionary d9 = p;
        d9.remove("line.separator");
    }
}
