@*
MatlabOctaveImport.tmpl

Created by Joe Hope on 2009-01-07.
Modified by Gregory Bogomiagkov and Liam Madge on 2013-07-18.

Copyright (c) 2009-2013, Joe Hope and Graham Dennis

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

*@

@def description: Creates text to import data from XSIL files into Matlab or Octave (where they are identical).

@attr $defaultExtension = 'm'
@attr $stringFormat = '.12e'
@attr $name = 'MATLAB/Octave'

@def printMatlabListOrElement(listOrElement, currentDepth)
  @# This is a function to turn an array into a Matlab list.  Called recursively, and assumes the elements are floats or lists.
  @if isinstance(listOrElement,float):
${format(float(listOrElement),$stringFormat)}@slurp
  @else:
cat($currentDepth, ${', '.join([$printMatlabListOrElement(element, currentDepth - 1) for element in listOrElement])})@slurp
  @end if
@end def

@def permuteDimensionsOfMATLABVariable(varName)
${varName} = permute(${varName}, ndims(${varName}):-1:1);
@end def

@def generateVariableName(xsilVariable, xsilObjectNumber)
  @return c'${xsilVariable.name}_${xsilObjectNumber+1}'
@end def

@def loadXSILFile($xsilFile)
  @for objectNum, xsilObject in enumerate(xsilFile.xsilObjects):
    @if xsilObject.data.format == 'ascii':
${handleASCIIXSILObject(objectNum, xsilObject)}@slurp
    @elif xsilObject.data.format == 'binary':
${handleBinaryXSILObject(objectNum, xsilObject)}@slurp
    @elif xsilObject.data.format == 'hdf5'
${handleHDF5XSILObject(objectNum, xsilObject)}@slurp
    @else
      @raise Exception("No support for Matlab/Octave output for XSIL format '%s'." % xsilObject.data.format)
    @end if
  @end for
@end def

@def handleASCIIXSILObject(objectNum, xsilObject)
  @set nIndepVar = len(xsilObject.independentVariables)
  @for var in xsilObject.independentVariables:
    @set varName = $generateVariableName(var, objectNum)
clear $varName
$varName = [${', '.join([format(float(e),$stringFormat) for e in var["array"]])}];
  @end for
  @for var in xsilObject.dependentVariables:
    @set varName = $generateVariableName(var, objectNum)
clear $varName
    @if nIndepVar == 1:
$varName = [${', '.join([format(float(e), $stringFormat) for e in var["array"]])}];
    @else if nIndepVar == 2:
$varName = [${';'.join([(','.join([format(float(val), $stringFormat) for val in subArray])) for subArray in var["array"]])}];
    @else
$varName = $printMatlabListOrElement($var["array"], $nIndepVar);
    @end if
${permuteDimensionsOfMATLABVariable(varName)}@slurp
  @end for
@end def

@def handleBinaryXSILObject(objectNum, xsilObject)
  @set variablesToClear = ['fpDat', 'xmds_variableShape']
  @set nIndepVar = len(xsilObject.independentVariables)
  @set machineFormat = {'BigEndian': 'ieee-be', 'LittleEndian': 'ieee-le'}.get(xsilObject.data.encoding, 'native')
  @set uLongFormat = {'uint32': 'uint32', 'uint64': 'uint64'}.get(xsilObject.data.uLong, 'uint64')
  @set outputPrecision = {'single': 'single', 'double': 'double'}.get(xsilObject.data.precision, 'double')
fpDat = fopen('$xsilObject.data.filename','r', '$machineFormat');
if (fpDat < 0)
  disp('Cannot open binary data file: ${xsilObject.data.filename}');
  return;
end
xmds_variableShape = [];
  @for var in xsilObject.independentVariables:
    @set varName = $generateVariableName(var, objectNum)
    @silent variablesToClear.append(c'${varName}Len')
$(varName)Len = fread(fpDat, 1, '$uLongFormat');
$(varName) = fread(fpDat, $(varName)Len, '$outputPrecision');
xmds_variableShape = [${varName}Len xmds_variableShape];
  @end for
if (length(xmds_variableShape) == 0)
  xmds_variableShape = [1 1];
elseif (length(xmds_variableShape) == 1)
  xmds_variableShape(end+1) = 1;
end
  @for varD in xsilObject.dependentVariables:
    @set varName = $generateVariableName(varD, objectNum)
    @silent variablesToClear.append(c'${varName}Len')
$(varName)Len = fread(fpDat, 1, '$uLongFormat', 0, '$machineFormat');
$varName = fread(fpDat, $(varName)Len, '$outputPrecision');
$varName = reshape($varName, xmds_variableShape);
${permuteDimensionsOfMATLABVariable(varName)}@slurp
  @end for
fclose(fpDat);
clear ${' '.join(variablesToClear)}
@end def

@def handleHDF5XSILObject(objectNum, xsilObject)
if (exist('OCTAVE_VERSION', 'builtin')) % Octave
  ${handleHDF5XSILObjectForOctave(objectNum, xsilObject), autoIndent=True}@slurp
else % MATLAB
  ${handleHDF5XSILObjectForMATLAB(objectNum, xsilObject), autoIndent=True}@slurp
end
@end def


@def handleHDF5XSILObjectForMATLAB(objectNum, xsilObject)
  @set $filename = xsilObject.data.filename
  @set $groupName = xsilObject.data.groupName
  @for var in xsilObject.independentVariables:
    @set outName = $generateVariableName(var, objectNum)
${outName} = hdf5read('${filename}', '${groupName}/${var.name}');
  @end for
  @for var in xsilObject.dependentVariables:
    @set outName = $generateVariableName(var, objectNum)
${outName} = hdf5read('${filename}', '${groupName}/${var.name}');
${permuteDimensionsOfMATLABVariable(outName)}@slurp
  @end for
@end def

@def handleHDF5XSILObjectForOctave(objectNum, xsilObject)
  @set $filename = xsilObject.data.filename
  @set $variables = xsilObject.independentVariables[:]
load ${filename}
  @for var in xsilObject.independentVariables:
    @set outName = $generateVariableName(var, objectNum)
    @# We have to do an eval here because variables with leading underscores are not valid in MATLAB
    @# (although accepted by Octave), and the MATLAB parser dies if there are expressions with leading underscores.
${outName} = eval('_${objectNum+1}.${var.name}');
  @end for
  @for var in xsilObject.dependentVariables:
    @set outName = $generateVariableName(var, objectNum)
${outName} = eval('_${objectNum+1}.${var.name}');
${permuteDimensionsOfMATLABVariable(outName)}@slurp
  @end for
clear _${objectNum+1};
@end def

