/*******************************************************************************
* Copyright (c) 2010, 2014, Embraer S.A., Budapest University of Technology and Economics
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Abel Hegedus - initial API and implementation
*******************************************************************************/
package hu.bme.mit.massif.communication.matlabcontrol;
import hu.bme.mit.massif.communication.CommandEvaluationException;
import hu.bme.mit.massif.communication.ICommandEvaluator;
import hu.bme.mit.massif.communication.datatype.CellMatlabData;
import hu.bme.mit.massif.communication.datatype.Handle;
import hu.bme.mit.massif.communication.datatype.IVisitableMatlabData;
import hu.bme.mit.massif.communication.datatype.Logical;
import hu.bme.mit.massif.communication.datatype.MatlabString;
import hu.bme.mit.massif.communication.datatype.StructMatlabData;
import java.util.HashMap;
import java.util.Map;
import matlabcontrol.MatlabConnectionException;
import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabProxy;
import matlabcontrol.MatlabProxyFactory;
import matlabcontrol.MatlabProxyFactoryOptions;
import matlabcontrol.MatlabProxyFactoryOptions.Builder;
/**
* Class responsible for the low level operations with MATLAB
*
* (The successor class of BasicOperationsApi utility class)
*/
public class CommandEvaluatorMCImpl implements ICommandEvaluator {
private static MatlabProxyFactory factory = null;
private static MatlabProxy proxy = null;
private Builder optionsBuilder = new MatlabProxyFactoryOptions.Builder();
private MatlabProxyFactoryOptions options = null;
public CommandEvaluatorMCImpl(String matlabPath) {
if (matlabPath != "") {
optionsBuilder = optionsBuilder.setMatlabLocation(matlabPath);
}
options = optionsBuilder.build();
factory = new MatlabProxyFactory(options);
try {
proxy = factory.getProxy();
} catch (MatlabConnectionException e) {
}
}
@Override
public IVisitableMatlabData evaluateCommand(String command, int nargout) {
IVisitableMatlabData result = null;
try {
if (nargout > 1) {
String resultString = "[";
for (Integer i = 0; i < nargout; i++) {
resultString = resultString.concat("r" + i.toString() + ",");
}
resultString = resultString.replaceAll(",$", "").concat("]");
proxy.returningEval(resultString + " = " + command, 0);
proxy.returningEval("ImporterTmpResult = " + resultString.replace("[", "{").replace("]", "}"), 0);
result = dataRetriever();
} else if (nargout == 1) {
proxy.returningEval("ImporterTmpResult = " + command, 0);
result = dataRetriever();
} else {
proxy.returningEval(command, 0);
result = null;
}
} catch (MatlabInvocationException e) {
throw new CommandEvaluationException("Exception occurred while evaluating command!", e);
}
return result;
}
private IVisitableMatlabData processStruct(String structName, Object[] data) throws MatlabInvocationException {
// //////
// DEBUG
// Get all data in the struct with the fieldnames
Object[] _data = (Object[]) proxy.returningEval(structName + "(1:end)", 1)[0];
// In case of a struct data[0] is always a String[] containing the field names
Map<String, IVisitableMatlabData> fieldsToValues = new HashMap<String, IVisitableMatlabData>();
Object[] structDatas = ((Object[]) _data[1]);
IVisitableMatlabData result = null;
if (structDatas.length <= 0) {
// TODO null length array of struct
return null;
} else if (structDatas.length == 1) {
StructMatlabData structResult = new StructMatlabData();
for (int i = 0; i < structDatas.length; i++) {
for (int j = 0; j < ((String[]) _data[0]).length; j++) {
String fieldName = ((String[]) _data[0])[j];
// Get the reference name for the field. Caution: MATLAB indexing
String currVarName = structName + "(" + (i + 1) + ")." + fieldName;
// Determine the type of each field
String type = (String) proxy.returningEval("class(" + currVarName + ")", 1)[0];
// Branch according to the type
IVisitableMatlabData fieldValue = null;
if ("struct".equals(type)) {
fieldValue = processStruct(currVarName, (Object[]) (((Object[]) structDatas[i])[j]));
} else {
fieldValue = processNonStruct(currVarName, type, ((Object[]) structDatas[i])[j]);
}
fieldsToValues.put(fieldName, fieldValue);
}
}
structResult.setDatas(fieldsToValues);
result = structResult;
} else {
CellMatlabData cellResult = new CellMatlabData();
for (int i = 0; i < structDatas.length; i++) {
StructMatlabData structResult = new StructMatlabData();
for (int j = 0; j < ((String[]) _data[0]).length; j++) {
String fieldName = ((String[]) _data[0])[j];
// fieldNames.add(fieldName);
// Get the reference name for the field. Caution: MATLAB indexing
String currVarName = structName + "(" + (i + 1) + ")." + fieldName;
// Determine the type of each field
String type = (String) proxy.returningEval("class(" + currVarName + ")", 1)[0];
// Branch according to the type
IVisitableMatlabData fieldValue = null;
if ("struct".equals(type)) {
fieldValue = processStruct(currVarName, (Object[]) (((Object[]) structDatas[i])[j]));
} else {
fieldValue = processNonStruct(currVarName, type, ((Object[]) structDatas[i])[j]);
}
fieldsToValues.put(fieldName, fieldValue);
}
structResult.setDatas(fieldsToValues);
fieldsToValues = new HashMap<String, IVisitableMatlabData>();
cellResult.addData(structResult);
result = cellResult;
}
}
return result;
}
private IVisitableMatlabData dataRetriever() throws MatlabInvocationException {
IVisitableMatlabData result = null;
String type = (String) proxy.returningEval("class(ImporterTmpResult)", 1)[0];
Object[] data = proxy.returningEval("ImporterTmpResult(1:end)", 1);
// Switch according to the result of type = class(ImporterTmpResult)
if (type.equals("struct")) {
result = processStruct("ImporterTmpResult", data);
} else {
result = processNonStruct("ImporterTmpResult", type, data[0]);
}
return result;
}
private IVisitableMatlabData processNonStruct(String name, String type, Object data) {
IVisitableMatlabData result = null;
if (type.equals("double")) {
if (data instanceof double[]) {
if (((double[]) data).length == 1) {
Handle handle = new Handle();
handle.setData((((double[]) data)[0]));
result = handle;
} else {
double[] handles = (double[]) data;
CellMatlabData compositeData = new CellMatlabData();
for (int i = 0; i < handles.length; i++) {
Handle handle = new Handle();
handle.setData((((double[]) (data))[i]));
compositeData.addData(handle);
}
result = compositeData;
}
} else if (((Object[]) (data)).length > 1) {
CellMatlabData compositeData = new CellMatlabData();
for (int j = 0; j < ((Object[]) (data)).length; j++) {
// Most of the times values are stored in an array of one element
// TODO check if iteration with i is really needed, or can be indexed with 0
for (int i = 0; i < ((double[]) ((Object[]) (data))[j]).length; i++) {
Handle handle = new Handle();
handle.setData(((double[]) ((Object[]) (data))[j])[i]);
compositeData.addData(handle);
}
}
result = compositeData;
}
} else if (type.equals("logical")) {
if (data instanceof boolean[]) {
if (((boolean[]) data).length == 1) {
Logical logical = new Logical();
logical.setData((((boolean[]) data)[0]));
result = logical;
}
}
} else if (type.equals("char")) {
// TODO handle char arrays
MatlabString string = new MatlabString();
String charData = (String) data;
string.setData(charData.replaceAll("\n", " "));
// string.setData(((String) (data[0])).replace("\n"," "));
result = string;
} else if (type.equals("cell")) {
CellMatlabData cellData = new CellMatlabData();
result = processCell((Object[]) data, cellData);
}
return result;
}
private CellMatlabData processCell(Object[] datas, CellMatlabData cellData) {
for (Object data : datas) {
if (data instanceof Object[]) {
CellMatlabData containedCellData = new CellMatlabData();
containedCellData = processCell(((Object[]) data), containedCellData);
cellData.addData(containedCellData);
} else if (data instanceof double[]) {
double[] doubleData = (double[]) data;
if (doubleData.length == 1) {
Handle handle = new Handle();
handle.setData(doubleData[0]);
cellData.addData(handle);
} else {
CellMatlabData containedArrayData = new CellMatlabData();
for (int i = 0; i < doubleData.length; i++) {
Handle handle = new Handle();
handle.setData(doubleData[i]);
containedArrayData.addData(handle);
}
cellData.addData(containedArrayData);
}
} else if (data instanceof String[]) {
String[] stringData = (String[]) data;
if (stringData.length == 1) {
MatlabString string = new MatlabString();
string.setData(stringData[0]);
cellData.addData(string);
} else {
CellMatlabData containedArrayData = new CellMatlabData();
for (int i = 0; i < stringData.length; i++) {
MatlabString string = new MatlabString();
string.setData(stringData[i]);
containedArrayData.addData(string);
}
cellData.addData(containedArrayData);
}
} else if (data instanceof String) {
MatlabString string = new MatlabString();
string.setData((String) data);
cellData.addData(string);
}
}
return cellData;
}
@Override
public IVisitableMatlabData evaluateCommands(String[] commandStrings, int outputArgumentCount) {
IVisitableMatlabData result = null;
if (commandStrings.length > 1) {
result = new CellMatlabData();
for (String commandString : commandStrings) {
CellMatlabData.asCellMatlabData(result).getDatas()
.add(evaluateCommand(commandString, outputArgumentCount));
}
} else if (commandStrings.length == 1){
result = evaluateCommand(commandStrings[0], outputArgumentCount);
}
return result;
}
}