/*******************************************************************************
* This file is part of logisim-evolution.
*
* logisim-evolution is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* logisim-evolution 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>.
*
* Original code by Carl Burch (http://www.cburch.com), 2011.
* Subsequent modifications by :
* + Haute École Spécialisée Bernoise
* http://www.bfh.ch
* + Haute École du paysage, d'ingénierie et d'architecture de Genève
* http://hepia.hesge.ch/
* + Haute École d'Ingénierie et de Gestion du Canton de Vaud
* http://www.heig-vd.ch/
* The project is currently maintained by :
* + REDS Institute - HEIG-VD
* Yverdon-les-Bains, Switzerland
* http://reds.heig-vd.ch
*******************************************************************************/
package com.cburch.logisim.circuit;
import java.util.Collection;
import com.cburch.logisim.comp.Component;
import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.instance.StdAttr;
import com.cburch.logisim.std.wiring.Pin;
class CircuitChange {
public static CircuitChange add(Circuit circuit, Component comp) {
return new CircuitChange(circuit, ADD, comp);
}
public static CircuitChange addAll(Circuit circuit,
Collection<? extends Component> comps) {
return new CircuitChange(circuit, ADD_ALL, comps);
}
public static CircuitChange clear(Circuit circuit,
Collection<Component> oldComponents) {
return new CircuitChange(circuit, CLEAR, oldComponents);
}
public static CircuitChange remove(Circuit circuit, Component comp) {
return new CircuitChange(circuit, REMOVE, comp);
}
public static CircuitChange removeAll(Circuit circuit,
Collection<? extends Component> comps) {
return new CircuitChange(circuit, REMOVE_ALL, comps);
}
public static CircuitChange replace(Circuit circuit, ReplacementMap replMap) {
return new CircuitChange(circuit, REPLACE, null, null, null, replMap);
}
public static CircuitChange set(Circuit circuit, Component comp,
Attribute<?> attr, Object value) {
return new CircuitChange(circuit, SET, comp, attr, null, value);
}
public static CircuitChange set(Circuit circuit, Component comp,
Attribute<?> attr, Object oldValue, Object newValue) {
return new CircuitChange(circuit, SET, comp, attr, oldValue, newValue);
}
public static CircuitChange setForCircuit(Circuit circuit,
Attribute<?> attr, Object v) {
return new CircuitChange(circuit, SET_FOR_CIRCUIT, null, attr, null, v);
}
public static CircuitChange setForCircuit(Circuit circuit,
Attribute<?> attr, Object oldValue, Object newValue) {
return new CircuitChange(circuit, SET_FOR_CIRCUIT, null, attr,
oldValue, newValue);
}
static final int CLEAR = 0;
static final int ADD = 1;
static final int ADD_ALL = 2;
static final int REMOVE = 3;
static final int REMOVE_ALL = 4;
static final int REPLACE = 5;
static final int SET = 6;
static final int SET_FOR_CIRCUIT = 7;
private Circuit circuit;
private int type;
private Component comp;
private Collection<? extends Component> comps;
private Attribute<?> attr;
private Object oldValue;
private Object newValue;
private CircuitChange(Circuit circuit, int type,
Collection<? extends Component> comps) {
this(circuit, type, null, null, null, null);
this.comps = comps;
}
private CircuitChange(Circuit circuit, int type, Component comp) {
this(circuit, type, comp, null, null, null);
}
private CircuitChange(Circuit circuit, int type, Component comp,
Attribute<?> attr, Object oldValue, Object newValue) {
this.circuit = circuit;
this.type = type;
this.comp = comp;
this.attr = attr;
this.oldValue = oldValue;
this.newValue = newValue;
}
boolean concernsSupercircuit() {
switch (type) {
case CLEAR:
return true;
case ADD:
case REMOVE:
return comp.getFactory() instanceof Pin;
case ADD_ALL:
case REMOVE_ALL:
for (Component comp : comps) {
if (comp.getFactory() instanceof Pin)
return true;
}
return false;
case REPLACE:
ReplacementMap repl = (ReplacementMap) newValue;
for (Component comp : repl.getRemovals()) {
if (comp.getFactory() instanceof Pin)
return true;
}
for (Component comp : repl.getAdditions()) {
if (comp.getFactory() instanceof Pin)
return true;
}
return false;
case SET:
return comp.getFactory() instanceof Pin
&& (attr == StdAttr.WIDTH || attr == Pin.ATTR_TYPE);
case SET_FOR_CIRCUIT :
return (attr == CircuitAttributes.NAME_ATTR || attr == CircuitAttributes.NAMED_CIRCUIT_BOX);
default:
return false;
}
}
void execute(CircuitMutator mutator, ReplacementMap prevReplacements) {
switch (type) {
case CLEAR:
mutator.clear(circuit);
prevReplacements.reset();
break;
case ADD:
prevReplacements.add(comp);
break;
case ADD_ALL:
for (Component comp : comps)
prevReplacements.add(comp);
break;
case REMOVE:
prevReplacements.remove(comp);
break;
case REMOVE_ALL:
for (Component comp : comps)
prevReplacements.remove(comp);
break;
case REPLACE:
prevReplacements.append((ReplacementMap) newValue);
break;
case SET:
mutator.replace(circuit, prevReplacements);
prevReplacements.reset();
mutator.set(circuit, comp, attr, newValue);
break;
case SET_FOR_CIRCUIT:
mutator.replace(circuit, prevReplacements);
prevReplacements.reset();
mutator.setForCircuit(circuit, attr, newValue);
break;
default:
throw new IllegalArgumentException("unknown change type " + type);
}
}
public Attribute<?> getAttribute() {
return attr;
}
public Circuit getCircuit() {
return circuit;
}
public Component getComponent() {
return comp;
}
public Object getNewValue() {
return newValue;
}
public Object getOldValue() {
return oldValue;
}
CircuitChange getReverseChange() {
switch (type) {
case CLEAR:
return CircuitChange.addAll(circuit, comps);
case ADD:
return CircuitChange.remove(circuit, comp);
case ADD_ALL:
return CircuitChange.removeAll(circuit, comps);
case REMOVE:
return CircuitChange.add(circuit, comp);
case REMOVE_ALL:
return CircuitChange.addAll(circuit, comps);
case SET:
return CircuitChange.set(circuit, comp, attr, newValue, oldValue);
case SET_FOR_CIRCUIT:
return CircuitChange.setForCircuit(circuit, attr, newValue,
oldValue);
case REPLACE:
return CircuitChange.replace(circuit,
((ReplacementMap) newValue).getInverseMap());
default:
throw new IllegalArgumentException("unknown change type " + type);
}
}
public int getType() {
return type;
}
}