/*******************************************************************************
* 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;
import hr.fer.zemris.vhdllab.applets.editor.schema2.constants.Constants;
import hr.fer.zemris.vhdllab.applets.editor.schema2.enums.EComponentType;
import hr.fer.zemris.vhdllab.applets.editor.schema2.enums.EOrientation;
import hr.fer.zemris.vhdllab.applets.editor.schema2.exceptions.InvalidParameterValueException;
import hr.fer.zemris.vhdllab.applets.editor.schema2.exceptions.NotImplementedException;
import hr.fer.zemris.vhdllab.applets.editor.schema2.exceptions.ParameterNotFoundException;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.IComponentDrawer;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.IParameter;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.IParameterCollection;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaComponent;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaInfo;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.IVHDLSegmentProvider;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.Caseless;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.PortRelation;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.SMath;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.SchemaPort;
import hr.fer.zemris.vhdllab.applets.editor.schema2.model.drawers.DefaultComponentDrawer;
import hr.fer.zemris.vhdllab.applets.editor.schema2.model.drawers.InOutComponentDrawer;
import hr.fer.zemris.vhdllab.applets.editor.schema2.model.parameters.CaselessParameter;
import hr.fer.zemris.vhdllab.applets.editor.schema2.model.parameters.GenericParameter;
import hr.fer.zemris.vhdllab.applets.editor.schema2.model.parameters.ParameterFactory;
import hr.fer.zemris.vhdllab.applets.editor.schema2.model.parameters.events.InOutPortChanger;
import hr.fer.zemris.vhdllab.applets.editor.schema2.model.parameters.events.NameAndPortNameChanger;
import hr.fer.zemris.vhdllab.applets.editor.schema2.model.parameters.generic.Orientation;
import hr.fer.zemris.vhdllab.applets.editor.schema2.model.parameters.generic.ParamPort;
import hr.fer.zemris.vhdllab.applets.editor.schema2.model.serialization.PortFactory;
import hr.fer.zemris.vhdllab.applets.editor.schema2.predefined.beans.ComponentWrapper;
import hr.fer.zemris.vhdllab.applets.editor.schema2.predefined.beans.ParameterWrapper;
import hr.fer.zemris.vhdllab.applets.editor.schema2.predefined.beans.PortWrapper;
import hr.fer.zemris.vhdllab.applets.editor.schema2.predefined.beans.SchemaPortWrapper;
import hr.fer.zemris.vhdllab.service.ci.CircuitInterface;
import hr.fer.zemris.vhdllab.service.ci.Port;
import hr.fer.zemris.vhdllab.service.ci.PortDirection;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
/**
* Klasa modelira komponentu koja predstavlja
* ulaz ili izlaz na modeliranom sklopu.
*
* @author brijest
*
*/
public class InOutSchemaComponent implements ISchemaComponent {
protected class InOutVHDLSegmentProvider implements IVHDLSegmentProvider {
private Map<Caseless, Caseless> renamed;
public String getInstantiation(ISchemaInfo info, Map<Caseless, Caseless> renamedSignals) {
Caseless cmpname = getName();
StringBuilder sb = new StringBuilder();
Port port = portrel.port;
renamed = renamedSignals;
if (port.isScalar()) {
Caseless mappedto = schemaports.get(0).getMapping();
if (!Caseless.isNullOrEmpty(mappedto)) {
mappedto = rename(mappedto);
if (!mappedto.equals(cmpname)) {
PortDirection dir = port.getDirection();
if (dir.equals(PortDirection.IN)) {
sb.append(rename(mappedto)).append(" <= ");
sb.append(getName()).append(";\n"); // TODO vidi portrel.port.getName()
} else if (dir.equals(PortDirection.OUT)) {
sb.append(getName()).append(" <= "); // TODO vidi portrel.port.getName()
sb.append(rename(mappedto)).append(";\n");
} else {
throw new NotImplementedException("Direction '" + dir.toString() +
"' not implemented.");
}
}
}
} else {
if (port.isIN()) {
int i = port.getFrom();
boolean downto = port.isDOWNTO();
for (SchemaPort schport : schemaports) {
Caseless mappedto = schport.getMapping();
if (!Caseless.isNullOrEmpty(mappedto)) {
mappedto = rename(mappedto);
Caseless vecwpos = new Caseless(cmpname + "(" + i + ")");
if (!mappedto.equals(vecwpos)) {
sb.append(rename(mappedto)).append(" <= ");
sb.append(cmpname).append("(").append(i).append(");\n");
// TODO vidi portrel.port.getName()
}
}
if (downto) i--; else i++;
}
} else if (port.isOUT()) {
int i = port.getFrom();
boolean downto = port.isDOWNTO();
for (SchemaPort schport : schemaports) {
Caseless mappedto = schport.getMapping();
if (!Caseless.isNullOrEmpty(mappedto)) {
mappedto = rename(mappedto);
Caseless vecwpos = new Caseless(cmpname + "(" + i + ")");
if (!mappedto.equals(vecwpos)) {
sb.append(getName()).append("(").append(i).append(")");
sb.append(" <= ").append(rename(mappedto)).append(";\n");
// TODO vidi portrel.port.getName()
}
}
if (downto) i--; else i++;
}
} else {
throw new NotImplementedException("Direction '" + port.getDirection() + "' not implemented.");
}
}
return sb.toString();
}
public String getSignalDefinitions(ISchemaInfo info) {
return "";
}
private Caseless rename(Caseless mappedto) {
Caseless updated = renamed.get(mappedto);
return (updated == null) ? (mappedto) : (updated);
}
}
/* static fields */
private static final String STD_LOGIC_IN = "Input_scalar";
private static final String STD_LOGIC_OUT = "Output_scalar";
private static final String STD_LOGIC_VECTOR_IN = "Input_vector";
private static final String STD_LOGIC_VECTOR_OUT = "Output_vector";
public static final String KEY_PORT = "Port";
public static final int WIDTH = Constants.GRID_SIZE * 8;
public static final int HEIGHT_PER_PORT = Constants.GRID_SIZE * 2;
public static final int EDGE_OFFSET = Constants.GRID_SIZE * 2;
/* private fields */
protected PortRelation portrel;
private List<SchemaPort> schemaports;
private IParameterCollection parameters;
private IComponentDrawer drawer;
private Caseless cmptypename;
private int width, height;
/* ctors */
public InOutSchemaComponent(Port modelledPort) {
parameters = new SchemaParameterCollection();
portrel = new PortRelation(modelledPort,
(modelledPort.isIN()) ? (EOrientation.EAST) : (EOrientation.WEST));
schemaports = new ArrayList<SchemaPort>();
width = WIDTH;
setComponentTypeName();
initDefaultParameters();
rebuildSchemaPorts();
initDrawer();
}
private void initDrawer() {
drawer = new InOutComponentDrawer(this);
}
private void setComponentTypeName() {
if (portrel.port.isScalar()) {
if (portrel.port.isIN()) {
cmptypename = new Caseless(STD_LOGIC_IN);
} else {
cmptypename = new Caseless(STD_LOGIC_OUT);
}
} else {
if (portrel.port.isIN()) {
cmptypename = new Caseless(STD_LOGIC_VECTOR_IN);
} else {
cmptypename = new Caseless(STD_LOGIC_VECTOR_OUT);
}
}
}
public void rebuildSchemaPorts() {
schemaports.clear();
portrel.relatedTo.clear();
Port port = portrel.port;
if (port.isIN()) {
if (port.isScalar()) {
buildInStdLogic();
} else {
buildStdLogicVector(width);
}
} else if (port.isOUT()) {
if (port.isScalar()) {
buildOutStdLogic();
} else {
buildStdLogicVector(0);
}
} else {
throw new NotImplementedException("Direction '" + port.getDirection() + "' not implemented.");
}
}
private void buildInStdLogic() {
SchemaPort sp = new SchemaPort(width, EDGE_OFFSET + HEIGHT_PER_PORT,
new Caseless(portrel.port.getName()));
sp.setPortindex(0);
portrel.relatedTo.add(sp);
schemaports.add(sp);
height = (EDGE_OFFSET + HEIGHT_PER_PORT) * 2;
}
private void buildOutStdLogic() {
SchemaPort sp = new SchemaPort(0, EDGE_OFFSET + HEIGHT_PER_PORT,
new Caseless(portrel.port.getName()));
sp.setPortindex(0);
portrel.relatedTo.add(sp);
schemaports.add(sp);
height = (EDGE_OFFSET + HEIGHT_PER_PORT) * 2;
}
private void buildStdLogicVector(int xpos) {
Port port = portrel.port;
int from = port.getFrom(), to = port.getTo();
int j;
SchemaPort schport = null;
if (port.isTO()) {
j = 1;
for (int i = from; i <= to; i++, j++) {
schport = new SchemaPort(xpos, EDGE_OFFSET + HEIGHT_PER_PORT * j,
new Caseless(port.getName() + "(" + i + ")"));
schport.setPortindex(0);
portrel.relatedTo.add(schport);
schemaports.add(schport);
}
} else {
j = 1;
for (int i = to; i <= from; i++, j++) {
schport = new SchemaPort(xpos, EDGE_OFFSET + HEIGHT_PER_PORT * j,
new Caseless(port.getName() + "(" + i + ")"));
schport.setPortindex(0);
portrel.relatedTo.add(schport);
schemaports.add(schport);
}
}
height = EDGE_OFFSET * 2 + HEIGHT_PER_PORT * j;
}
private void initDefaultParameters() {
// default parameter - name
CaselessParameter cslpar =
new CaselessParameter(ISchemaComponent.KEY_NAME, false, new Caseless(portrel.port.getName()));
cslpar.setParameterEvent(new NameAndPortNameChanger());
parameters.addParameter(cslpar);
// default parameter - component orientation
GenericParameter<Orientation> orientpar =
new GenericParameter<Orientation>(ISchemaComponent.KEY_ORIENTATION, false,
new Orientation());
orientpar.getConstraint().setPossibleValues(Orientation.allAllowed);
parameters.addParameter(orientpar);
// default parameter - component port
GenericParameter<ParamPort> portpar =
new GenericParameter<ParamPort>(KEY_PORT, false, new ParamPort(portrel.port));
portpar.setParameterEvent(new InOutPortChanger());
parameters.addParameter(portpar);
}
private void initDrawer(String drawerName) {
try {
Class cls = Class.forName(drawerName);
Class[] partypes = new Class[1];
partypes[0] = ISchemaComponent.class;
Constructor<IComponentDrawer> ct = cls.getConstructor(partypes);
Object[] params = new Object[1];
params[0] = this;
drawer = ct.newInstance(params);
} catch (Exception e) {
drawer = new DefaultComponentDrawer(this);
}
}
/**
* Za deserijalizaciju.
*
* @param wrapper
*/
public InOutSchemaComponent(ComponentWrapper wrapper) {
schemaports = new ArrayList<SchemaPort>();
parameters = new SchemaParameterCollection();
deserialize(wrapper);
setComponentTypeName();
}
/**
* Za copyCtor().
*
*/
private InOutSchemaComponent() {
parameters = new SchemaParameterCollection();
schemaports = new ArrayList<SchemaPort>();
}
/* methods */
/**
* Vraca jedini port inout komponente.
*/
public Port getPort() {
return portrel.port;
}
/**
* Postavlja jedini port inout komponente.
* @param p
*/
public void setPort(Port p) {
portrel.port = p;
}
public ISchemaComponent copyCtor() {
InOutSchemaComponent inout = new InOutSchemaComponent();
// copy parameters
for (IParameter param : this.parameters) {
inout.parameters.addParameter(param.copyCtor());
}
// copy schema ports
for (SchemaPort sp : this.schemaports) {
inout.schemaports.add(new SchemaPort(sp));
}
// copy port relation
inout.portrel = new PortRelation(new Port(this.portrel.port), this.portrel.orientation);
for (SchemaPort sp : inout.schemaports) {
inout.portrel.relatedTo.add(sp);
}
// init drawer
if (this.drawer != null) inout.initDrawer(this.drawer.getClass().getName());
// other
inout.width = this.width;
inout.height = this.height;
inout.setComponentTypeName();
return inout;
}
public void deserialize(ComponentWrapper compwrap) {
// handle parameters
parameters.clear();
for (ParameterWrapper paramwrap : compwrap.getParamWrappers()) {
parameters.addParameter(ParameterFactory.createParameter(paramwrap));
}
// handle port
List<PortWrapper> ports = compwrap.getPortWrappers();
if (ports.size() < 1) throw new IllegalStateException("At least one port needed for in-out component.");
PortWrapper pw = ports.get(0);
Port p = PortFactory.createPort(pw);
portrel = new PortRelation(p, EOrientation.parse(pw.getOrientation()));
// create schema ports
schemaports.clear();
for (SchemaPortWrapper spw : compwrap.getSchemaPorts()) {
SchemaPort sp = new SchemaPort(spw);
portrel.relatedTo.add(sp);
schemaports.add(sp);
}
// init drawer
initDrawer(compwrap.getDrawerName());
// other
width = compwrap.getWidth();
height = compwrap.getHeight();
}
public String getCategoryName() {
return Constants.Categories.INOUT;
}
public CircuitInterface getCircuitInterface() {
return new CircuitInterface(getName().toString(), new Port(portrel.port));
}
public String getCodeFileName() {
return null;
}
public EOrientation getComponentOrientation() {
throw new NotImplementedException();
}
public IComponentDrawer getDrawer() {
return drawer;
}
public int getHeight() {
return height;
}
public Caseless getName() {
try {
return (Caseless)(parameters.getValue(ISchemaComponent.KEY_NAME));
} catch (ParameterNotFoundException e) {
throw new RuntimeException("Name parameter not found.");
}
}
public IParameterCollection getParameters() {
return parameters;
}
public SchemaPort getSchemaPort(Caseless name) {
for (SchemaPort sp : schemaports) {
if (sp.getName().equals(name)) return sp;
}
return null;
}
public SchemaPort getSchemaPort(int xoffset, int yoffset, int dist) {
int ind = SMath.calcClosestPort(xoffset, yoffset, dist, schemaports);
if (ind == SMath.ERROR) return null;
return schemaports.get(ind);
}
public SchemaPort getSchemaPort(int index) {
return schemaports.get(index);
}
public List<SchemaPort> getSchemaPorts() {
return schemaports;
}
public Caseless getTypeName() {
return cmptypename;
}
public IVHDLSegmentProvider getVHDLSegmentProvider() {
return new InOutVHDLSegmentProvider();
}
public int getWidth() {
return width;
}
public boolean isGeneric() {
return false;
}
public int schemaPortCount() {
return schemaports.size();
}
public Port getPort(int index) {
if (index != 0) throw new IndexOutOfBoundsException();
return portrel.port;
}
public EOrientation getPortOrientation(int index) {
if (index != 0) throw new IndexOutOfBoundsException();
return portrel.orientation;
}
public void setPort(int index, Port port) {
if (index != 0) throw new IndexOutOfBoundsException();
schemaports.clear();
portrel.port = port;
rebuildSchemaPorts();
}
public int portCount() {
return 1;
}
public Iterator<Port> portIterator() {
return new Iterator<Port>() {
private boolean first = true;
public boolean hasNext() {
return first;
}
public Port next() {
if (first) {
first = false;
return portrel.port;
}
throw new NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public Iterator<SchemaPort> schemaPortIterator() {
return schemaports.iterator();
}
public void setComponentOrientation(EOrientation orient) {
throw new NotImplementedException();
}
public void setName(Caseless name) {
try {
parameters.setValue(ISchemaComponent.KEY_NAME, name);
portrel.port.setName(name.toString());
} catch (InvalidParameterValueException e) {
throw new RuntimeException("Name could not be set - invalid value.", e);
} catch (ParameterNotFoundException e) {
throw new RuntimeException("Name could not be set.", e);
}
}
public EComponentType getComponentType() {
return EComponentType.IN_OUT;
}
public boolean isInvalidated() {
return false;
}
public List<SchemaPort> getRelatedTo(int portIndex) {
if (portIndex != 0) throw new IndexOutOfBoundsException();
return portrel.relatedTo;
}
}