/*******************************************************************************
* 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.enums.EPropertyChange;
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.interfaces.ISchemaWireCollection;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.Caseless;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.ChangeTuple;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.IntList;
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.misc.XYLocation;
import hr.fer.zemris.vhdllab.applets.editor.schema2.model.CommandResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
/**
* Mice komponentu danog imena na specificirano mjesto.
*
* @version 1.0
* Ako je na neki port komponente bila spojena neka zica,
* komanda nece biti izvrsena.
*
* @author brijest
*
*/
public class MoveComponentCommand implements ICommand {
/* static fields */
public static final String COMMAND_NAME = "MoveComponentCommand";
/* private fields */
private Caseless cmpname;
private XYLocation loc;
private XYLocation oldloc;
private Map<Integer, Caseless> unplugged;
private IntList plugged;
/* ctors */
/**
* Konstruktor komande.
*
* @param componentName
* Ime komponente koju se zeli pomaknuti.
* @param moveTarget
* Mjesto na koje se zeli pomaknuti komponentu.
*/
public MoveComponentCommand(Caseless componentName, XYLocation moveTarget) {
cmpname = componentName;
loc = moveTarget;
}
/* methods */
public String getCommandName() {
return COMMAND_NAME;
}
public boolean isUndoable() {
return true;
}
public ICommandResponse performCommand(ISchemaInfo info) {
ISchemaComponentCollection components = info.getComponents();
ISchemaComponent cmp = components.fetchComponent(cmpname);
if (cmp == null) {
return new CommandResponse(new SchemaError(EErrorTypes.NONEXISTING_COMPONENT_NAME,
"Component '" + cmpname.toString() + "' does not exist."));
}
if (cmp.isInvalidated()) return new CommandResponse(
new SchemaError(EErrorTypes.COMPONENT_INVALIDATED, "Component '" + cmpname.toString() +
"' is invalidated."));
// find old location
oldloc = components.getComponentLocation(cmpname);
// find mapped ports and unmap them
int count = -1;
for (SchemaPort sp : cmp.getSchemaPorts()) {
count++;
Caseless mapping = sp.getMapping();
if (Caseless.isNullOrEmpty(mapping)) continue;
if (unplugged == null) unplugged = new HashMap<Integer, Caseless>();
/* unplug and cache */
sp.setMapping(null);
unplugged.put(count, mapping);
}
// find wires at port locations and map them, caching them
ISchemaWireCollection wires = info.getWires();
XYLocation cmploc = components.getComponentLocation(cmpname);
count = -1;
for (SchemaPort sp : cmp.getSchemaPorts()) {
count++;
XYLocation spxy = sp.getOffset();
int xsp = cmploc.x + spxy.x, ysp = cmploc.y + spxy.y;
Set<ISchemaWire> wat = wires.fetchAllWires(xsp, ysp);
if (wat != null && !wat.isEmpty()) {
ISchemaWire w = wat.iterator().next();
Set<WireSegment> segs = w.segmentsAt(xsp, ysp);
if (segs != null && !segs.isEmpty()) {
sp.setMapping(w.getName());
if (plugged == null) plugged = new IntList();
plugged.add(count);
}
}
}
// add component to new location
try {
components.reinsertComponent(cmpname, loc.x, loc.y);
} catch (OverlapException e) {
return new CommandResponse(new SchemaError(EErrorTypes.COMPONENT_OVERLAP,
"Component overlaps other components at desired location."));
} catch (UnknownKeyException e) {
throw new IllegalStateException("Component could not found, although it has been before.");
}
return new CommandResponse(new ChangeTuple(EPropertyChange.CANVAS_CHANGE));
}
public ICommandResponse undoCommand(ISchemaInfo info) throws InvalidCommandOperationException {
ISchemaComponentCollection components = info.getComponents();
ISchemaComponent cmp = components.fetchComponent(cmpname);
if (cmp == null) {
throw new IllegalStateException("Component '" + cmpname + "' cannot be found while " +
"performing undo.");
}
for (SchemaPort sp : cmp.getSchemaPorts()) {
Caseless mapping = sp.getMapping();
if (Caseless.isNullOrEmpty(mapping)) continue;
throw new IllegalStateException("Component has mapped ports while performing undo.");
}
/* unplug plugged ports */
if (plugged != null) {
for (int i = 0, sz = plugged.size(); i < sz; i++) {
cmp.getSchemaPort(plugged.get(i)).setMapping(null);
}
plugged = null;
}
/* plug back in cached mappings */
if (unplugged != null) {
for (Entry<Integer, Caseless> ntry : unplugged.entrySet()) {
cmp.getSchemaPort(ntry.getKey()).setMapping(ntry.getValue());
}
unplugged = null;
}
// add component to new location
try {
components.reinsertComponent(cmpname, oldloc.x, oldloc.y);
} catch (OverlapException e) {
throw new IllegalStateException("Component overlaps other components at desired location " +
"while performing undo.");
} catch (UnknownKeyException e) {
throw new IllegalStateException("Component could not found, although it has been before.");
}
return new CommandResponse(new ChangeTuple(EPropertyChange.CANVAS_CHANGE));
}
}