/*******************************************************************************
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package hr.fer.zemris.vhdllab.applets.editor.schema2.model.commands;
import hr.fer.zemris.vhdllab.applets.editor.schema2.enums.EErrorTypes;
import hr.fer.zemris.vhdllab.applets.editor.schema2.exceptions.DuplicateKeyException;
import hr.fer.zemris.vhdllab.applets.editor.schema2.exceptions.InvalidCommandOperationException;
import hr.fer.zemris.vhdllab.applets.editor.schema2.exceptions.OverlapException;
import hr.fer.zemris.vhdllab.applets.editor.schema2.exceptions.UnknownKeyException;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ICommand;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ICommandResponse;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaComponent;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaComponentCollection;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaInfo;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaWire;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.Caseless;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.IntList;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.PlacedComponent;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.SchemaError;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.SchemaPort;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.WireSegment;
import hr.fer.zemris.vhdllab.applets.editor.schema2.model.CommandResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* Povezuje dvije zice skupa. Pritom jedna zica nestaje sa sheme
* i svi portovi na koje je bila povezana nisu vise povezani na nju,
* vec na zicu s kojom se spojila.
*
* @author brijest
*
*/
public class BindWireCommand implements ICommand {
/* static fields */
public static final String COMMAND_NAME = "BindWireCommand";
/* private fields */
private Caseless wtobind, tobindto;
private Map<Caseless, IntList> cachedports;
private List<WireSegment> cachedsegments;
private ISchemaWire cachedwire;
/* ctors */
/**
* Stvara komandu koja ce spojiti dvije zice u jednu.
* Pritom novostvorena zica ima ime jedne od zica.
* Svi portovi komponenata na koje su bile spojene zice bit ce nakon
* izvodenja komande spojeni na novonastalu zicu.
*
* @param wireToBind
* Zica koja ce nestati - bit ce pretvorena u drugu zicu.
* @param wireToBeBoundTo
* Zica na koju ce prethodna zica biti povezana.
*/
public BindWireCommand(Caseless wireToBind, Caseless wireToBeBoundTo) {
wtobind = wireToBind;
tobindto = wireToBeBoundTo;
cachedports = new HashMap<Caseless, IntList>();
cachedsegments = new ArrayList<WireSegment>();
}
/* methods */
public String getCommandName() {
return COMMAND_NAME;
}
public boolean isUndoable() {
return true;
}
public ICommandResponse performCommand(ISchemaInfo info) {
ISchemaWire oldwire = info.getWires().fetchWire(wtobind);
ISchemaWire tobindtowire = info.getWires().fetchWire(tobindto);
if (oldwire == null) return new CommandResponse(new SchemaError(EErrorTypes.NONEXISTING_WIRE_NAME,
"Wire with name '" + wtobind + "' does not exist."));
if (tobindtowire == null) return new CommandResponse(new SchemaError(EErrorTypes.NONEXISTING_WIRE_NAME,
"Wire with name '" + tobindto + "' does not exist."));
// find all components mapped to oldwire, map them to tobeboundwire and cache ports
for (PlacedComponent placed : info.getComponents()) {
if (placed.comp.isInvalidated()) continue;
IntList portindices = null;
int i = 0;
for (SchemaPort sp : placed.comp.getSchemaPorts()) {
Caseless mappedto = sp.getMapping();
if (wtobind.equals(mappedto)) {
if (portindices == null) portindices = new IntList();
portindices.add(i);
sp.setMapping(tobindto);
}
i++;
}
if (portindices != null) cachedports.put(placed.comp.getName(), portindices);
}
// cache old wire
cachedwire = oldwire;
// remove old wire
try {
info.getWires().removeWire(wtobind);
} catch (UnknownKeyException e) {
throw new IllegalStateException("Wire '" + wtobind.toString() + "' could not be removed, but it exists!", e);
}
// add all segments from old wire to tobindtowire, caching them
for (WireSegment ws : oldwire.getSegments()) {
tobindtowire.insertSegment(ws);
cachedsegments.add(ws);
}
// add all nodes from old wire to tobintowire if they can be added, caching them
// List<XYLocation> nodelist = tobindtowire.getNodes();
// for (XYLocation node : oldwire.getNodes()) {
// if (!(nodelist.contains(node))) {
// nodelist.add(node);
// cachednodes.add(node);
// }
// }
return new CommandResponse(true);
}
public ICommandResponse undoCommand(ISchemaInfo info)
throws InvalidCommandOperationException
{
ISchemaWire oldwire = cachedwire;
ISchemaWire tobindtowire = info.getWires().fetchWire(tobindto);
if (oldwire == null) return new CommandResponse(new SchemaError(EErrorTypes.NONEXISTING_WIRE_NAME,
"Wire with name '" + wtobind + "' does not exist."));
if (tobindtowire == null) return new CommandResponse(new SchemaError(EErrorTypes.NONEXISTING_WIRE_NAME,
"Wire with name '" + tobindto + "' does not exist."));
// remove cached segments from tobindtowire
for (WireSegment ws : cachedsegments) {
tobindtowire.removeSegment(ws);
}
// remove cached node from tobindtowire
// List<XYLocation> nodelist = tobindtowire.getNodes();
// for (XYLocation node : cachednodes) {
// nodelist.remove(node);
// }
// add old wire
try {
info.getWires().addWire(oldwire);
} catch (DuplicateKeyException e) {
throw new IllegalStateException("Wire '" + oldwire.getName() + "' could not be added due to duplicate key.");
} catch (OverlapException e) {
throw new IllegalStateException("Wire '" + oldwire.getName() + "' could not be added due to overlap.");
}
// find all cached ports and map them to old wire
ISchemaComponentCollection components = info.getComponents();
for (Entry<Caseless, IntList> entry : cachedports.entrySet()) {
ISchemaComponent cmp = components.fetchComponent(entry.getKey());
List<SchemaPort> splist = cmp.getSchemaPorts();
IntList portindices = entry.getValue();
int sz = portindices.size();
for (int i = 0; i < sz; i++) {
splist.get(portindices.get(i)).setMapping(wtobind);
}
}
// clear cache
cachedports.clear();
cachedsegments.clear();
cachedwire = null;
return new CommandResponse(true);
}
}