package application.editor;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.mxgraph.layout.mxCircleLayout;
import com.mxgraph.layout.mxCompactTreeLayout;
import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxGraphModel;
import com.mxgraph.model.mxIGraphModel;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.swing.view.mxICellEditor;
import com.mxgraph.util.mxConstants;
import com.mxgraph.view.mxCellState;
import com.mxgraph.util.mxRectangle;
import com.mxgraph.view.mxGraph;
import com.mxgraph.view.mxGraphView;
import algorithms.DataTransferModelAnalyzer;
import algorithms.Validation;
import application.editor.stages.ControlFlowDelegationStage;
import application.editor.stages.DataFlowCellEditor;
import application.editor.stages.DataFlowModelingStage;
import application.editor.stages.PushPullSelectionStage;
import application.layouts.*;
import code.ast.CompilationUnit;
import models.Edge;
import models.EdgeAttribute;
import models.Node;
import models.dataConstraintModel.ChannelGenerator;
import models.dataConstraintModel.IdentifierTemplate;
import models.dataFlowModel.DataTransferModel;
import models.dataFlowModel.DataTransferChannelGenerator;
import models.dataFlowModel.PushPullAttribute;
import models.dataFlowModel.DataFlowEdge;
import models.dataFlowModel.DataFlowGraph;
import models.dataFlowModel.ResourceNode;
import models.visualModel.FormulaChannelGenerator;
import parser.Parser;
import parser.exceptions.ExpectedAssignment;
import parser.exceptions.ExpectedChannel;
import parser.exceptions.ExpectedChannelName;
import parser.exceptions.ExpectedEquals;
import parser.exceptions.ExpectedFormulaChannel;
import parser.exceptions.ExpectedGeometry;
import parser.exceptions.ExpectedInOrOutOrRefKeyword;
import parser.exceptions.ExpectedIoChannel;
import parser.exceptions.ExpectedLeftCurlyBracket;
import parser.exceptions.ExpectedModel;
import parser.exceptions.ExpectedNode;
import parser.exceptions.ExpectedRHSExpression;
import parser.exceptions.ExpectedResource;
import parser.exceptions.ExpectedRightBracket;
import parser.exceptions.ExpectedStateTransition;
import parser.exceptions.WrongLHSExpression;
import parser.exceptions.WrongRHSExpression;
import parser.ParserDTRAM;
public class Editor {
public DataTransferModel model = null;
public mxGraph graph = null;
private mxGraphComponent graphComponent = null;
protected Stage curStage = null;
protected List<Stage> stageQueue = null;
private List<IStageChangeListener> stageChangeListeners = null;
protected String curFileName = null;
protected String curFilePath = null;
protected ArrayList<CompilationUnit> codes = null;
public static DataFlowModelingStage STAGE_DATA_FLOW_MODELING = null;
public static PushPullSelectionStage STAGE_PUSH_PULL_SELECTION = null;
public static ControlFlowDelegationStage STAGE_CONTROL_FLOW_DELEGATION = null;
public Editor(mxGraphComponent graphComponent) {
this.graphComponent = graphComponent;
this.graph = graphComponent.getGraph();
STAGE_DATA_FLOW_MODELING = new DataFlowModelingStage(graph);
STAGE_PUSH_PULL_SELECTION = new PushPullSelectionStage(graph);
STAGE_CONTROL_FLOW_DELEGATION = new ControlFlowDelegationStage(graph);
graphComponent.setCellEditor(STAGE_DATA_FLOW_MODELING.createCellEditor(graphComponent));
stageQueue = new ArrayList<>();
stageQueue.add(STAGE_DATA_FLOW_MODELING);
stageQueue.add(STAGE_PUSH_PULL_SELECTION);
stageQueue.add(STAGE_CONTROL_FLOW_DELEGATION);
curStage = STAGE_DATA_FLOW_MODELING;
stageChangeListeners = new ArrayList<>();
}
public mxGraph getGraph() {
return graph;
}
public mxGraphComponent getGraphComponent() {
return this.graphComponent;
}
public DataTransferModel getModel() {
model = curStage.getModel();
return model;
}
public Stage getCurStage() {
return curStage;
}
public boolean canChange(Stage nextStage) {
return nextStage.canChangeFrom(curStage);
}
public boolean nextStage() {
int curStageNo = stageQueue.indexOf(curStage);
if (curStageNo + 1 >= stageQueue.size()) return false;
return changeStage(stageQueue.get(curStageNo + 1));
}
public boolean changeStage(Stage nextStage) {
if (!nextStage.canChangeFrom(curStage)) return false;
nextStage.init(curStage);
graphComponent.setCellEditor(nextStage.createCellEditor(graphComponent));
curStage = nextStage;
return true;
}
public void addStageChangeListener(IStageChangeListener stageChangeListener) {
stageChangeListeners.add(stageChangeListener);
}
private void notifyStageChangeListeners() {
for (IStageChangeListener l: stageChangeListeners) {
l.stageChanged(curStage);
}
}
public DataFlowGraph getDataFlowGraph() {
if (curStage instanceof PushPullSelectionStage) {
return ((PushPullSelectionStage) curStage).getDataFlowGraph();
}
return null;
}
public ArrayList<CompilationUnit> getCodes() {
return codes;
}
public void setCodes(ArrayList<CompilationUnit> codes) {
this.codes = codes;
}
public String getCurFileName() {
return curFileName;
}
public String getCurFilePath() {
return curFilePath;
}
public void setCurFilePath(String curFilePath) {
this.curFilePath = curFilePath;
this.curFileName = new File(curFilePath).getName();
}
public void clear() {
// Force to change to the data-flow modeling stage.
boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING);
if (!stageChanged) return;
model = null;
((DataFlowModelingStage) curStage).clear();
notifyStageChangeListeners();
curFilePath = null;
curFileName = null;
codes = null;
}
/**
* Open a given file, parse the file, construct a DataFlowModel and a mxGraph
* @param file given file
* @return a constructed DataFlowModel
*/
public DataTransferModel open(File file) {
// Force to change to the data-flow modeling stage.
boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING);
if (!stageChanged) return null;
try {
String extension ="";
if(file != null && file.exists()) {
// get file's name
String name = file.getName();
// get file's extension
extension = name.substring(name.lastIndexOf("."));
}
if(extension.contains(".model")) {
openModel(file);
} else {
// Parse the .dtram file.
ParserDTRAM parserDTRAM = new ParserDTRAM(new BufferedReader(new FileReader(file)));
try {
model = parserDTRAM.doParseModel();
if (curStage instanceof DataFlowModelingStage) {
// Update the mxGraph.
((DataFlowModelingStage) curStage).setModel(model);
}
// Restore the geometry.
parserDTRAM.doParseGeometry(graph);
// Change to the push/pull selection stage, analyze the data transfer model and construct a data-flow graph.
changeStage(STAGE_PUSH_PULL_SELECTION);
notifyStageChangeListeners();
curFilePath = file.getAbsolutePath();
curFileName = file.getName();
return model;
} catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword
| ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression
| WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedModel | ExpectedGeometry | ExpectedNode | ExpectedResource | ExpectedFormulaChannel | ExpectedIoChannel e) {
e.printStackTrace();
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
public DataTransferModel openModel(File file) {
// Force to change to data-flow modeling stage.
boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING);
if (!stageChanged) return null;
try {
// Parse the .model file.
Parser parser = new Parser(new BufferedReader(new FileReader(file)));
try {
model = parser.doParse();
if (curStage instanceof DataFlowModelingStage) {
// Update the mxGraph.
((DataFlowModelingStage) curStage).setModel(model);
}
// Set DAG layout.
setDAGLayout();
// Change to the push/pull selection stage, analyze the data transfer model and construct a data-flow graph.
changeStage(STAGE_PUSH_PULL_SELECTION);
notifyStageChangeListeners();
curFilePath = file.getAbsolutePath();
curFileName = file.getName();
return model;
} catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword
| ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression
| WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**--------------------------------------------------------------------------------
* save
/**--------------------------------------------------------------------------------
*
*/
public void save() {
if (curFilePath != null) {
try {
File file = new File(curFilePath);
String extension = "";
if(file != null && file.exists()) {
// get a file's name
String name = file.getName();
// get a file's extension
extension = name.substring(name.lastIndexOf("."));
}
if(extension.contains(".model")) {
saveModel(file);
} else {
FileWriter filewriter = new FileWriter(file);
filewriter.write(toOutputString());
filewriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void saveModel(File file) {
if (curFilePath != null) {
try {
FileWriter filewriter = new FileWriter(file);
filewriter.write(model.getSourceText());
filewriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**--------------------------------------------------------------------------------
* get writing texts "dtram" file information is written.
*
* @return formatted "dtram" info texts.
*/
protected String toOutputString() {
String fileString = "";
fileString += "model {\n";
fileString += this.model.getSourceText();
fileString += "}\n";
fileString += "geometry {\n";
Object root = graph.getDefaultParent();
for (int i = 0; i < graph.getModel().getChildCount(root); i++) {
Object cell = graph.getModel().getChildAt(root, i);
if (graph.getModel().isVertex(cell)) {
mxGraphView view = graph.getView();
mxCellState state = view.getState(cell);
int x = (int) state.getX();
int y = (int) state.getY();
int w = (int) state.getWidth();
int h = (int) state.getHeight();
for(ChannelGenerator ch: model.getChannelGenerators()) {
if(ch instanceof FormulaChannelGenerator && state.getLabel().equals(ch.getChannelName())) {
fileString += "\tnode fc " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h+"\n";
} else if(ch instanceof ChannelGenerator && state.getLabel().equals(ch.getChannelName())) {
fileString +="\tnode c " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h+"\n";
}
}
for (IdentifierTemplate res: model.getIdentifierTemplates()){
if(res instanceof IdentifierTemplate && state.getLabel().equals(res.getResourceName()))
fileString += "\tnode r " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h + "\n";
}
for (ChannelGenerator ioC: model.getIOChannelGenerators()) {
if(ioC instanceof ChannelGenerator && state.getLabel().equals(ioC.getChannelName())) {
fileString += "\tnode ioc " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h + "\n";
}
}
}
}
fileString += "}\n";
return fileString;
}
public void setDAGLayout() {
Object parent = graph.getDefaultParent();
graph.getModel().beginUpdate();
try {
DAGLayout ctl = new DAGLayout(graph);
ctl.execute(parent);
} finally {
graph.getModel().endUpdate();
}
}
public void setTreeLayout() {
Object parent = graph.getDefaultParent();
graph.getModel().beginUpdate();
try {
mxCompactTreeLayout ctl = new mxCompactTreeLayout(graph);
ctl.setLevelDistance(100);
// ctl.setHorizontal(false);
ctl.setEdgeRouting(false);
ctl.execute(parent);
} finally {
graph.getModel().endUpdate();
}
}
public void setCircleLayout() {
Object parent = graph.getDefaultParent();
graph.getModel().beginUpdate();
try {
mxCircleLayout ctl = new mxCircleLayout(graph);
ctl.execute(parent);
} finally {
graph.getModel().endUpdate();
}
}
public void addIdentifierTemplate(IdentifierTemplate res) {
// Force to change to the data-flow modeling stage.
boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING);
if (!stageChanged) return;
((DataFlowModelingStage) curStage).addIdentifierTemplate(res);
model = ((DataFlowModelingStage) curStage).getModel();
notifyStageChangeListeners();
}
public void addChannelGenerator(DataTransferChannelGenerator channelGen) {
// Force to change to the data-flow modeling stage.
boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING);
if (!stageChanged) return;
((DataFlowModelingStage) curStage).addChannelGenerator(channelGen);
model = ((DataFlowModelingStage) curStage).getModel();
notifyStageChangeListeners();
}
public void addIOChannelGenerator(DataTransferChannelGenerator ioChannelGen) {
// Force to change to the data-flow modeling stage.
boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING);
if (!stageChanged) return;
((DataFlowModelingStage) curStage).addIOChannelGenerator(ioChannelGen);
model = ((DataFlowModelingStage) curStage).getModel();
notifyStageChangeListeners();
}
public void addFormulaChannelGenerator(FormulaChannelGenerator formulaChannelGen) {
// Force to change to the data-flow modeling stage.
boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING);
if (!stageChanged) return;
((DataFlowModelingStage) curStage).addFormulaChannelGenerator(formulaChannelGen);
model = ((DataFlowModelingStage) curStage).getModel();
notifyStageChangeListeners();
}
public boolean connectEdge(mxCell edge, mxCell src, mxCell dst) {
// Force to change to the data-flow modeling stage.
boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING);
if (!stageChanged) return false;
boolean isConnected = ((DataFlowModelingStage) curStage).connectEdge(edge, src, dst);
notifyStageChangeListeners();
return isConnected;
}
public void delete() {
// Force to change to the data-flow modeling stage.
boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING);
if (!stageChanged) return;
((DataFlowModelingStage) curStage).delete();
notifyStageChangeListeners();
}
public static class SrcDstAttribute extends EdgeAttribute {
private Object src;
private Object dst;
public SrcDstAttribute(Object src, Object dst) {
this.src = src;
this.dst = dst;
}
public Object getSrouce() {
return src;
}
public Object getDestination() {
return dst;
}
public String toString() {
return "";
}
}
}