function hud = ReadPOSPacASCII2Hud(fileName)
% ---------------------------------------------------------- 
% [ hud ] = ReadPOSPacASCII2Hud (fileName)
% ----------------------------------------------------------
% SAMPLE SYNTAX
%
% hud  = ReadPOSPacASCII2Hud('20151119_RefTrajPOSPac.txt')
%
% DESCRIPTION 
% ========================================================== 
% Loads data from the input POSPac ASCII file and returns 
% a HUD struct
%
% INPUT PARAMETERS 
% ==========================================================
%    fileName:    Name of the POSPac ASCII file to load
%
% OUTPUT 
% ==========================================================
%    hud:  [1x1]  [struct]   Struct holding three fields:
%
%                 .h    [cx1]  [cell] Data headers 
%                 .u    [cx1]  [cell] Data unit 
%                 .d    [nxc]  [dbl]  Data matrix
%
% ADDITIONAL NOTES 
% ========================================================== 
% The maximum number of header lines in the POSPac file is 
% set to 30 in the variable -maxHeaderLines. Function throws
% an error and terminates if the threshold is exceeded
%
% ========================================================== 
% COPYRIGHT © Trimble Terrasat GmbH
% ==========================================================

%% Default parameters 

% set default filename if none specified
if nargin == 0
    error('ReadPOSPacASCII2Hud:InputArg','Please provide a filename');
end

% Maximum number of header lines expected
maxHeaderLines = 30;
lineNum        = 0;

% Constants for the units
meterUnit    = 'm';
degreeUnit   = 'deg';
velocityUnit = 'm/s';
noUnit       = '-';

%% Begin reading POSPac ASCII file

% Open POSPac file in read-only mode
fidPOSPacFile  = fopen(fileName,'r');

%% Read the header lines and set the sHud.h field
line      = fgets(fidPOSPacFile);
rsltRegex = regexp(line,'^\s?[0-9]+\.[0-9]+');

% Reading until the end of the header lines
while isempty(rsltRegex);
    
    % read header for HUD
    hIdx = strfind( line, 'TIME,' );
    
    % what if strfind becomes case-insensitive tomorrow? handling it here.
    photoIdx = strfind( line, 'Photo ID');
    
    if ~isempty(hIdx) && isempty(photoIdx)
        
        % Put header in cells
        hud.h    = strtrim(strsplit(line,',')');
        
        % Replace the empty space between header values with underscore
        for i=1:length(hud.h),
            hud.h(i) = strrep(hud.h(i),' ','_');
        end
        
        % Create unit field
        hud.u = cellstr(repmat(noUnit,length(hud.h),1));
        
        % Set unit for time
        if strncmp(hud.h{1}, 'TIME', 4)
            hud.h{1} = 'GPS_Second';
            hud.u{1} = '(s)';
        end
        
        %   If LATITUDE is the second index, then
        if strncmp(hud.h{2}, 'LATITUDE', 8)
            
            % Set LLH
            hud.u{2} = degreeUnit;
            hud.u{3} = degreeUnit;
            hud.u{4} = meterUnit;
            
            % Set velocities
            hud.u{5} = velocityUnit;
            hud.u{6} = velocityUnit;
            hud.u{7} = velocityUnit;
            
            % Set position covariance
            hud.u{8}  = meterUnit;
            hud.u{9}  = meterUnit;
            hud.u{10} = meterUnit;
            
            % Set Roll, Pitch and Heading
            hud.u{11} = degreeUnit;
            hud.u{12} = degreeUnit;
            hud.u{13} = degreeUnit;
            
            % Set Covariance for Roll, Pitch and Heading
            hud.u{14} = degreeUnit;
            hud.u{15} = degreeUnit;
            hud.u{16} = degreeUnit;
            
        end
        
        
        %   If LATITUDE is the sixth index, then
        if strncmp(hud.h{6}, 'LATITUDE', 8)
            % Set DISTANCE
            hud.u{2} = meterUnit;
            % EASTING, NORTHING, ELLIPSOID HEIGHT fro UTM Data
            hud.u{3} = meterUnit;
            hud.u{4} = meterUnit;
            hud.u{5} = meterUnit;
            
            % Set LLH
            hud.u{6} = degreeUnit;
            hud.u{7} = degreeUnit;
            hud.u{8} = meterUnit;
            
            % Set Roll, Pitch and Heading
            hud.u{9}  = degreeUnit;
            hud.u{10} = degreeUnit;
            hud.u{11} = degreeUnit;
            
            % Set velocities
            hud.u{12} = velocityUnit;
            hud.u{13} = velocityUnit;
            hud.u{14} = velocityUnit;
            
            % Set position sigmas
            hud.u{15} = meterUnit;
            hud.u{16} = meterUnit;
            hud.u{17} = meterUnit;
            
            % Set sigma for Roll, Pitch and Heading
            hud.u{18} = degreeUnit;
            hud.u{19} = degreeUnit;
            hud.u{20} = degreeUnit;
        end
    end
    
    lineNum = lineNum + 1;
    
%     % Making sure that we don't read past the maximum header length
%     if ( lineNum > maxHeaderLines ) 
%         error('ReadPOSPacASCII2Hud:HeaderLength','Invalid header in input file <%s>', fileName );
%     end
%     
    line      = fgets(fidPOSPacFile);
    rsltRegex = regexp(strtrim(line),'^\s?[0-9]+\.[0-9]+');
    
end

%% Read the data using Textscan 

% Note that textscan starts at the line when the previous loop was terminated, since the file is
% still open 

% Creating an Automatic Format Specifier based on the number of headers 
formatSpec = repmat('%f',1, length(hud.h));

% go back for one line 
fseek(fidPOSPacFile,-length(line),'cof');

% Read the data as a cell
dataAsCell = textscan(fidPOSPacFile,formatSpec,'EmptyValue',NaN);

% close the POSPac input file
fclose(fidPOSPacFile);

%% Assign the data to the struct

data = cell2mat(dataAsCell);

if isempty(data)
    error('ReadPOSPacASCII2Hud:Data' ,'No data available in input file <%s>', fileName );
end

% Handle Week-rollover and update time tags
weekOffset = 0;
dayLength  = 86400;

for i = 2:size(data,1)
    if ( data(i-1,1) - weekOffset ) - data(i,1) > (dayLength*3.5)
        weekOffset = weekOffset + (dayLength*7);
    end
    data(i,1) = data(i,1) + weekOffset;
end

% Set the data field of the sHud struct
hud.d = data;

% Compute variances if the headers are set
if isfield(hud,'h')
    
    % NOTE: ii starts at 8 as this is the first instance where
    %       covariances can be found in both formats
    
    for ii=8:length(hud.h)
        % Calculate position variance from sigma
        if(strncmp(hud.h(ii),'p_cov_xx',6))
            hud.d(:,ii)   = hud.d(:,ii).^2;
            hud.d(:,ii+1) = hud.d(:,ii+1).^2;
            hud.d(:,ii+2) = hud.d(:,ii+2).^2;
        end
        % Calculate attitude variance from sigma
        if(strncmp(hud.h(ii),'phi_cov_Roll',12))
            hud.d(:,ii)   = hud.d(:,ii).^2;
            hud.d(:,ii+1) = hud.d(:,ii+1).^2;
            hud.d(:,ii+2) = hud.d(:,ii+2).^2;
        end
    end
    
    % If the headers have not been set,throw an error
else
    % ERROR
    error('ReadPOSPacASCII2Hud:UnknownHeader',...
          ['No header in "' fileName '" HUD structure with unknown headers and units!']);
end

% Check the hud struct for possible errors and handle them if possible
[hud] = CheckHud(hud);


end

