function fun = tl2mat(infile)
%TL2MAT Import Test.Lab file
% DATA = TL2MAT(FILENAME) reads a textfile FILENAME exported from Test.Lab
% into the structure array DATA.
% If the input file contains multiple functions, then the output DATA will
% be a structure array, each structure describing a single function.
% In this case, the number of lines need to be the same in all functions,
% and all functions need to be complex valued or not.
%
% Example:
%   data = tl2mat('data.txt');
%   plot(data(1).x, abs(data(1).y));

% Last updated: 27.11.2009.
% Peter Fiala

%% Argument check
error(nargchk(1, 1, nargin, 'struct'));
error(nargoutchk(1, 1, nargout, 'struct'));

%% Open Test.Lab file
fin = fopen(infile, 'r');
if fin == -1
    error('tl2mat:fopen', 'Cannot open input file ''%s''', infile);
end

%% Read the file header
firstrow = true;    % #functions determined from first row
while true
    line = fgetl(fin);
    if line == -1
        error('tl2mat:nihuFile', 'Possibly corrupt file.');
    end
    % the fields are separated by TAB (chr(9)) characters
    g = [0 find(abs(line) == 9)];
    if firstrow
        nFunc = (length(g)-1) / 4;
        fun = struct('x', cell(nFunc,1));   % create structure array
        firstrow = false;
    end

    % The header is over if the first entry in the line is a number
    if ~isempty(sscanf(line, '%g'))
        break;
    end

    % Insert header fields into the data structure
    for k = 1 : nFunc
        NameStr = line(g(4*(k-1)+1)+1:g(4*(k-1)+2)-1);
        ValueStr = line(g(4*(k-1)+2)+1:g(4*(k-1)+3)-1);
        if ~isempty(ValueStr)
            % try to convert value string to numeric data
            Value = str2double(ValueStr);
            if isnan(Value)
                Value = ValueStr;
            end
            % insert field and value into the structure array
            fun(k).(strrep(lower(NameStr), ' ', '_')) = Value;
        end
    end
end

% check whether all the functions have the same number of lines and they
% are all complex or not
nLines = fun(1).number_of_lines;
iscomplex = strcmp(fun(1).value_type, 'Complex');
for k = 2 : nFunc
    if fun(k).number_of_lines ~= nLines ||...
            strcmp(fun(k).value_type, 'Complex') ~= iscomplex
        fclose(fin);
        error('tl2mat:nihuInput', '%s\n%s\n%s',...
            'Possibly bad input file!',...
            'Input file contains both real and complex functions.',...
            'Different number of samples!!');
    end
end

if nLines == 0
    nLines = Inf;
end

%% Read numeric data from the file
if iscomplex
    data = [sscanf(line, '%f', 2*nFunc),...
        fscanf(fin, '%f', [3*nFunc, nLines-1])].';
    nFunc = size(data,2)/3;
    for k = 1 : nFunc
        fun(k).x = data(:,3*(k-1)+1,:);
        fun(k).y = complex(data(:,3*(k-1)+2,:), data(:,3*(k-1)+3,:));
    end
else
    data = [sscanf(line, '%f', 2*nFunc),...
        fscanf(fin, '%f', [2*nFunc, nLines-1])].';
    nFunc = size(data,2)/3;
    for k = 1 : nFunc
        fun(k).x = data(:,2*(k-1)+1,:);
        fun(k).y = data(:,2*(k-1)+2,:);
    end
end

%% And finally...
fclose(fin);
fun = orderfields(fun);
end
