/*
 * Written by Dawid Kurzyniec and released to the public domain, as explained
 * at http://creativecommons.org/licenses/publicdomain
 */

package edu.emory.mathcs.util.gc;

import java.lang.ref.*;
import java.util.*;

public class FinalizationEngine {
    final ReferenceCleaner cleaner;
    final boolean manageLifetime;


    // important, yet non-obvious, role of this set (in addition to keeping
    // count of groups to stop queue polling if it gets to 0) is to keep strong
    // references to active groups (i.e. groups with pending finalizers).
    // Otherwise, the groups could become subject to gc, and all their pending
    // finalizers could also be gc'ed and never invoked.
    private final Set activeGroupSet = new HashSet();

    public FinalizationEngine() {
        this(new ReferenceCleaner(), true);
    }

    public FinalizationEngine(ReferenceCleaner cleaner, boolean manageLifetime) {
        this.cleaner = cleaner;
        this.manageLifetime = manageLifetime;
    }

    public FinalizationGroup createGroup() {
        return createGroup(null);
    }

    public FinalizationGroup createGroup(String name) {
        return new FinalizationGroup(this, name);
    }

    void groupActivated(FinalizationGroup group) {
        synchronized (this) {
            assert (!activeGroupSet.contains(group));
            boolean wasEmpty = activeGroupSet.isEmpty();
            activeGroupSet.add(group);
            if (manageLifetime && wasEmpty) {
                cleaner.start();
            }
        }
    }

    void groupDeactivated(FinalizationGroup group) {
        synchronized (this) {
            boolean existed = activeGroupSet.remove(group);
            assert (existed);
            if (manageLifetime && activeGroupSet.isEmpty()) {
                cleaner.stop();
            }
        }
    }

    ReferenceQueue getQueue() {
        return cleaner.getQueue();
    }
}
