/* Copyright (c) 2010, Carl Burch. License information is located in the
* com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */
package com.cburch.logisim.circuit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Set;
import com.cburch.logisim.comp.Component;
import com.cburch.logisim.comp.EndData;
import com.cburch.logisim.data.BitWidth;
import com.cburch.logisim.data.Location;
class CircuitPoints {
private static class LocationData {
BitWidth width = BitWidth.UNKNOWN;
ArrayList<Component> components = new ArrayList<Component>(4);
ArrayList<EndData> ends = new ArrayList<EndData>(4);
// these lists are parallel - ends corresponding to wires are null
}
private HashMap<Location,LocationData> map
= new HashMap<Location,LocationData>();
private HashMap<Location,WidthIncompatibilityData> incompatibilityData
= new HashMap<Location,WidthIncompatibilityData>();
public CircuitPoints() { }
//
// access methods
//
Set<Location> getSplitLocations() {
return map.keySet();
}
BitWidth getWidth(Location loc) {
LocationData locData = map.get(loc);
return locData == null ? BitWidth.UNKNOWN : locData.width;
}
int getComponentCount(Location loc) {
LocationData locData = map.get(loc);
return locData == null ? 0 : locData.components.size();
}
Component getExclusive(Location loc) {
LocationData locData = map.get(loc);
if (locData == null) {
return null;
}
int i = -1;
for (EndData endData : locData.ends) {
i++;
if (endData != null && endData.isExclusive()) {
return locData.components.get(i);
}
}
return null;
}
Collection<? extends Component> getComponents(Location loc) {
LocationData locData = map.get(loc);
if (locData == null) {
return Collections.emptySet();
}
else {
return locData.components;
}
}
Collection<? extends Component> getSplitCauses(Location loc) {
return getComponents(loc);
}
Collection<Wire> getWires(Location loc) {
@SuppressWarnings("unchecked")
Collection<Wire> ret = (Collection<Wire>) find(loc, true);
return ret;
}
Collection<? extends Component> getNonWires(Location loc) {
return find(loc, false);
}
private Collection<? extends Component> find(Location loc, boolean isWire) {
LocationData locData = map.get(loc);
if (locData == null) {
return Collections.emptySet();
}
// first see how many elements we have; we can handle some simple
// cases without creating any new lists
ArrayList<Component> list = locData.components;
int retSize = 0;
Component retValue = null;
for (Component o : list) {
if ((o instanceof Wire) == isWire) {
{ retValue = o;
}
retSize++; }
}
if (retSize == list.size()) {
return list;
}
if (retSize == 0) {
return Collections.emptySet();
}
if (retSize == 1) {
return Collections.singleton(retValue);
}
// otherwise we have to create our own list
Component[] ret = new Component[retSize];
int retPos = 0;
for (Component o : list) {
if ((o instanceof Wire) == isWire) {
{ ret[retPos] = o;
}
retPos++; }
}
return Arrays.asList(ret);
}
Collection<WidthIncompatibilityData> getWidthIncompatibilityData() {
return incompatibilityData.values();
}
boolean hasConflict(Component comp) {
if (comp instanceof Wire) {
return false;
} else {
for (EndData endData : comp.getEnds()) {
if (endData != null && endData.isExclusive()
&& getExclusive(endData.getLocation()) != null) {
return true;
}
}
return false;
}
}
//
// update methods
//
void add(Component comp) {
if (comp instanceof Wire) {
Wire w = (Wire) comp;
addSub(w.getEnd0(), w, null);
addSub(w.getEnd1(), w, null);
} else {
for (EndData endData : comp.getEnds()) {
if (endData != null) {
addSub(endData.getLocation(), comp, endData);
}
}
}
}
void add(Component comp, EndData endData) {
if (endData != null) {
addSub(endData.getLocation(), comp, endData);
}
}
void remove(Component comp) {
if (comp instanceof Wire) {
Wire w = (Wire) comp;
removeSub(w.getEnd0(), w);
removeSub(w.getEnd1(), w);
} else {
for (EndData endData : comp.getEnds()) {
if (endData != null) {
removeSub(endData.getLocation(), comp);
}
}
}
}
void remove(Component comp, EndData endData) {
if (endData != null) {
removeSub(endData.getLocation(), comp);
}
}
private void addSub(Location loc, Component comp, EndData endData) {
LocationData locData = map.get(loc);
if (locData == null) {
locData = new LocationData();
map.put(loc, locData);
}
locData.components.add(comp);
locData.ends.add(endData);
computeIncompatibilityData(loc, locData);
}
private void removeSub(Location loc, Component comp) {
LocationData locData = map.get(loc);
if (locData == null) {
return;
}
int index = locData.components.indexOf(comp);
if (index < 0) {
return;
}
if (locData.components.size() == 1) {
map.remove(loc);
incompatibilityData.remove(loc);
} else {
locData.components.remove(index);
locData.ends.remove(index);
computeIncompatibilityData(loc, locData);
}
}
private void computeIncompatibilityData(Location loc, LocationData locData) {
WidthIncompatibilityData error = null;
if (locData != null) {
BitWidth width = BitWidth.UNKNOWN;
for (EndData endData : locData.ends) {
if (endData != null) {
BitWidth endWidth = endData.getWidth();
if (width == BitWidth.UNKNOWN) {
width = endWidth;
} else if (width != endWidth && endWidth != BitWidth.UNKNOWN) {
if (error == null) {
error = new WidthIncompatibilityData();
error.add(loc, width);
}
error.add(loc, endWidth);
}
}
}
locData.width = width;
}
if (error == null) {
incompatibilityData.remove(loc);
} else {
incompatibilityData.put(loc, error);
}
}
}