Topology.java

/**
 *
 * This file is part of TRIO.
 *
 * TRIO is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * TRIO is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with TRIO.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 *
 * This file is part of TRIO.
 *
 * TRIO is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * TRIO is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with TRIO. If not, see <http://www.gnu.org/licenses/>.
 */
package eu.diversify.trio.simulation;

import eu.diversify.trio.core.System;
import eu.diversify.trio.filter.All;
import eu.diversify.trio.filter.Filter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.List;

/**
 * One particular configuration of the system
 */
public class Topology {

    public static final boolean ACTIVE = true;
    public static final boolean INACTIVE = !ACTIVE;

    private final System system;
    private final BitSet isActive;
    private final BitSet isObserved;
    private final BitSet isControlled;
    private final List<Listener> listeners;

    public Topology(System system) {
        this(system, All.getInstance(), All.getInstance(), new Listener[]{});
    }

    public Topology(System system, Filter observation, Filter control) {
        this(system, observation, control, new Listener[]{});
    }

    public Topology(System system, Filter observation, Filter control, Listener... listeners) {
        this.system = system;
        this.isActive = new BitSet(system.size());
        this.isActive.set(0, system.size(), true);
        this.isObserved = new BitSet(system.size());
        for (String name: observation.resolve(system)) {
            isObserved.flip(system.indexOf(name));
        }
        this.isControlled = new BitSet(system.size());
        for (String name: control.resolve(system)) {
            isControlled.flip(system.indexOf(name));
        }
        this.listeners = new ArrayList<Listener>(Arrays.asList(listeners));
    }

    public int getCapacity() {
        return system.size();
    }

    public boolean isActive(String componentName) {
        return statusOf(componentName);
    }

    private boolean statusOf(String componentName) {
        return isActive.get(system.indexOf(componentName));
    }

    public boolean isInactive(String componentName) {
        return !isActive(componentName);
    }

    public int countActiveAndObserved() {
        BitSet isActiveCopy = activeAndObserved();
        return isActiveCopy.cardinality();
    }

    private BitSet activeAndObserved() {
        final BitSet isActiveCopy = (BitSet) isActive.clone();
        isActiveCopy.and(isObserved);
        return isActiveCopy;
    }

    public Collection<String> activeAndObservedComponents() {
        final Collection<String> selection = new ArrayList<String>(isObserved.cardinality());
        final BitSet activeAndObserved = activeAndObserved();
        for (int i = activeAndObserved.nextSetBit(0);
                i >= 0;
                i = activeAndObserved.nextSetBit(i + 1)) {
            selection.add(system.getComponent(i).getName());
        }
        return selection;
    }

    private BitSet activeAndControlled() {
        final BitSet isActiveCopy = (BitSet) isActive.clone();
        isActiveCopy.and(isControlled);
        return isActiveCopy;
    }

    public Collection<String> activeAndControlledComponents() {
        final Collection<String> selection = new ArrayList<String>(isControlled.cardinality());
        final BitSet activeAndControlled = activeAndControlled();
        for (int i = activeAndControlled.nextSetBit(0);
                i >= 0;
                i = activeAndControlled.nextSetBit(i + 1)) {
            selection.add(system.getComponent(i).getName());
        }
        return selection;
    }

    public boolean isObserved(String componentName) {
        return isObserved.get(system.indexOf(componentName));
    }

    public boolean isControlled(String componentName) {
        return isControlled.get(system.indexOf(componentName));
    }

    public boolean hasActiveAndObservedComponents() {
        return isActive.intersects(isObserved);
    }

    public boolean hasActiveAndControlledComponents() {
        return isActive.intersects(isControlled);
    }

    private void propagateChanges() {
        boolean updated = true;
        while (updated) {
            updated = false;
            final BitSet remainActive = new BitSet(system.size());
            for (int i = isActive.nextSetBit(0);
                    i >= 0;
                    i = isActive.nextSetBit(i + 1)) {
                remainActive.set(i, isActive.get(i) && system.getComponent(i).isSatisfiedIn(this));
                updated |= isActive.get(i) != remainActive.get(i);
            }
            this.isActive.and(remainActive);
        }
    }

    public void setStatusOf(String component, boolean isActive) {
        this.isActive.set(system.indexOf(component), isActive);
    }

    public void inactivate(String component) {
        setStatusOf(component, INACTIVE);
        propagateChanges();
        for (Listener each: listeners) {
            each.inactivate(component, this);
        }
    }

    public void activate(String component) {
        setStatusOf(component, ACTIVE);
        propagateChanges();
        for (Listener each: listeners) {
            each.activate(component, this);
        }
    }

}