function nitf_meta = nitfparse21(fid)
%NITFPARSE21 Parse the fields in an NITF2.1 file.

%   Copyright 2007-2020 The MathWorks, Inc.

nitf_meta = struct([]);
fields = {'FHDR',   'FileProfileNameAndVersion',         9
          'CLEVEL',  'ComplexityLevel',                  2
          'STYPE',   'StandardType',                     4
          'OSTAID',  'OriginatingStationID',            10
          'FDT',     'FileDateAndTime',                 14
          'FTITLE',  'FileTitle',                       80
          'FSCLAS',  'FileSecurityClassification',       1
          'FSCLSY',  'FileSecurityClassificationSystem', 2
          'FSCODE',  'FileCodewords',                   11
          'FSCTLH',  'FileControlAndHandling',           2
          'FSREL',   'FileReleasingInstructions',       20
          'FSDCTP',  'FileDeclassificationType',         2
          'FSDCDT',  'FileDeclassificationDate',         8
          'FSDCXM',  'FileDeclassificationExemption',    4
          'FSDG',    'FileDowngrade',                    1
          'FSDGT',   'FileDowngradeDate',                8
          'FSCLTX',  'FileClassificationText',          43
          'FSCATP',  'FileClassificationAuthorityType',  1
          'FSCAUT',  'FileClassificationAuthority',     40
          'FSCRSN',  'FileClassificationReason',         1
          'FSSRDT',  'FileSecuritySourceDate',           8
          'FSCTLN',  'FileSecurityControlNumber',       15
          'FSCOP',   'FileCopyNumber',                   5
          'FSCPYS',  'FileNumberOfCopies',               5
          'ENCRYP',  'Encryption',                       1
          'FBKGC',   'FileBackgroundColor',              3
          'ONAME',   'OriginatorName',                  24
          'OPHONE',  'OriginatorPhoneNumber',           18
          'FL',      'FileLength',                      12
          'HL',      'NITFFileHeaderLength',             6
          'NUMI',    'NumberOfImages',                   3};
nitf_meta = nitfReadMeta(nitf_meta, fields, fid);

numi = sscanf(nitf_meta(end).value, '%f');
[nitf_meta, imLengths] = processtopimagesubheadermeta(numi, nitf_meta, fid);

%Next field gives the number of graphics segments.
fields = {'NUMS', 'NumberOfGraphics', 3};
nitf_meta = nitfReadMeta(nitf_meta, fields, fid);

nums = sscanf(nitf_meta(end).value, '%f');
[nitf_meta, grLengths] = processtopgraphicsubheadermeta(nums, nitf_meta, fid);

%Next field is reserved for future use but it is a required field
fields = {'NUMX', 'ReservedForFutureUse', 3};
nitf_meta = nitfReadMeta(nitf_meta, fields, fid);

%Next group is text files
fields = {'NUMT', 'NumberOfTextFiles', 3};
nitf_meta = nitfReadMeta(nitf_meta, fields, fid);

numt = sscanf(nitf_meta(end).value, '%f');
[nitf_meta, teLengths] = processtoptextsubheadermeta(numt, nitf_meta, fid);

%Next group is Data Extension Segments
fields = {'NUMDES', 'NumberOfDataExtensionSegments', 3};
nitf_meta = nitfReadMeta(nitf_meta, fields, fid);

numdes = sscanf(nitf_meta(end).value, '%f');
[nitf_meta, deLengths] = processtopdesubheadermeta(numdes, nitf_meta, fid);

%Next group is Reserved Extension Segments
fields = {'NUMRES', 'NumberOfReservedDataExtensionSegments', 3};
nitf_meta = nitfReadMeta(nitf_meta, fields, fid);

numres = sscanf(nitf_meta(end).value, '%f');
[nitf_meta, reLengths, reHeaderLengths] = processtopresubheadermeta(numres, nitf_meta, fid);

%Next group is User Define Header Segments which contain tagged record extensions.
%Get the Header Data Length
fields = {'UDHDL', 'UserDefinedHeaderDataLength', 5};
nitf_meta = nitfReadMeta(nitf_meta, fields, fid);

UDHDL = sscanf(nitf_meta(end).value, '%f');
nitf_meta = processtopudsubheadermeta(UDHDL, nitf_meta, fid);

%Next group is Extended Header Segments which contain tagged record extensions.
%Get the Header Data Length
fields = {'XHDL', 'ExtendedHeaderDataLength', 5};
nitf_meta = nitfReadMeta(nitf_meta, fields, fid);

XHDL = sscanf(nitf_meta(end).value, '%f');
nitf_meta = processtopxsubheadermeta(XHDL, nitf_meta, fid);

%Call the image segment metadata parser for each image subheader

% We want the image subheader(s) to be drillable from the structure
% editor.  Image subheader data will not be visible from command line
% feedback without explicitly accessing the structure.

%First, we want the nitf_meta struct to have a ImageSubHeader field.  This
%will have the total offset of the subheader(s), and the value will be
%a struct which contains a list of image subheaders.  Each subheader in
%the list is displayed table form when the user clicks on the struct
%value.

%Build the structure of ImageSubHeaders
if numi > 0
    nitf_meta = processImageSubheaders(nitf_meta,numi,fid, imLengths);
end

%Build the structure of SymbolSubHeaders
if nums > 0
    nitf_meta = processGraphicSubheaders(nitf_meta,nums ,fid, grLengths);
end

%Build the structure of TextSubHeaders
if numt > 0
    nitf_meta = processTextSubheaders(nitf_meta,numt ,fid, teLengths);
end

%Build the structure of DataExtensionSubHeaders
if numdes > 0
    nitf_meta = processDESubheaders(nitf_meta,numdes ,fid, deLengths);
end

%Build the structure of ReservedExtensionSubHeaders
if numres > 0
    nitf_meta = processRESubheaders(nitf_meta,numres ,fid, reLengths, reHeaderLengths);
end



function [nitf_meta, imLengths] = processtopimagesubheadermeta(numi, nitf_meta, fid)
%Add the nth image subheader information to the nitf_meta struct
%This struct contains the image subheader length and image length
%for all the images in the file
imLengths(1).value = '';

if (numi > 0)
    
    % Preallocate the lengths structure.
    imLengths(numi).value = '';
    
    nitf_meta(end + 1).name = 'ImageAndSubHeaderLengths';
    nitf_meta(end).vname = 'ImageAndImageSubheaderLengths';

    fields = {'LISH%03d', 'LengthOfNthImageSubheader',  6
              'LI%010d',  'LengthOfNthImage',          10};
    
    for currentImage = 1:numi

        % Setup.
        nitf_metaISL(currentImage).name = sprintf('Image%03d', currentImage);
        nitf_metaISL(currentImage).vname = [nitf_metaISL(currentImage).name 'ImageAndSubheaderLengths'];

        % Parse the data.
        tempStruct = struct([]);
        tempStruct = nitfReadMetaMulti(tempStruct, fields, fid, currentImage);
        nitf_metaISL(currentImage).value = tempStruct;
        
        % Update lengths with the value read.
        imLengths(currentImage).value = tempStruct(2).value;
        
    end

    nitf_meta(end).value = nitf_metaISL;
    
end



function [nitf_meta, grLengths] = processtopgraphicsubheadermeta(nums,nitf_meta, fid)

grLengths(1).value = '';

if (nums > 0)
    
    % Preallocate the lengths structure.
    grLengths(nums).value = '';
    
    nitf_meta(end + 1).name = 'GraphicAndSubHeaderLengths';
    nitf_meta(end).vname = 'GraphicAndGraphicSubheaderLengths';

    fields = {'LSSH%03d', 'LengthOfNthGraphicSubheader', 4
              'LS%06d',   'LengthOfNthGraphic',          6};
    
    for currentGraphic = 1:nums
        
        % Setup.
        nitf_metaGSL(currentGraphic).name = sprintf('Graphic%03d', currentGraphic);
        nitf_metaGSL(currentGraphic).vname = [nitf_metaGSL(currentGraphic).name 'GraphicAndSubheaderLengths'];

        % Parse the data.
        tempStruct = struct([]);
        tempStruct = nitfReadMetaMulti(tempStruct, fields, fid, currentGraphic);
        nitf_metaGSL(currentGraphic).value = tempStruct;
        
        % Update lengths with the value read.
        grLengths(currentGraphic).value = tempStruct(2).value;
        
    end

    nitf_meta(end).value = nitf_metaGSL;
    
end



function [nitf_meta, teLengths] = processtoptextsubheadermeta(numt, nitf_meta, fid)

teLengths(1).value = '';

if (numt > 0)
     
    % Preallocate the lengths structure.
    teLengths(numt).value = '';
   
    nitf_meta(end + 1).name = 'TextAndSubHeaderLengths';
    nitf_meta(end).vname = 'TextAndTextSubheaderLengths';

    fields = {'LTSH%03d', 'LengthOfNthTextSubheader', 4
              'LT%03d',   'LengthOfNthText',          5};
    
    for currentText = 1:numt
        
        % Setup.
        nitf_metaLTL(currentText).name = sprintf('Text%03d', currentText);
        nitf_metaLTL(currentText).vname = [nitf_metaLTL(currentText).name 'TextAndSubheaderLengths'];

        % Parse the data.
        tempStruct = struct([]);
        tempStruct = nitfReadMetaMulti(tempStruct, fields, fid, currentText);
        nitf_metaLTL(currentText).value = tempStruct;
        
        % Update lengths with the value read.
        teLengths(currentText).value = tempStruct(2).value;
    
    end

    nitf_meta(end).value = nitf_metaLTL;

end



function [nitf_meta, deLengths] = processtopdesubheadermeta(numdes, nitf_meta, fid)

deLengths(1).value = '';

if (numdes > 0)
    
    % Preallocate the lengths structure.
    deLengths(numdes).value = '';
   
    nitf_meta(end + 1).name = 'DataExtensionsAndSubHeaderLengths';
    nitf_meta(end).vname = 'DataExtensionAndDataExtensionSubheaderLengths';

    fields = {'LDSH%03d', 'LengthOfNthDataExtensionSubheader', 4
              'LD%03d',   'LengthOfNthDataExtension',          9};
    
    for currentDES = 1:numdes
        
        % Setup.
        nitf_metaDES(currentDES).name = sprintf('DataExtension%03d', currentDES);
        nitf_metaDES(currentDES).vname = [nitf_metaDES(currentDES).name 'DataExtensionAndSubheaderLengths'];

        % Parse the data.
        tempStruct = struct([]);
        tempStruct = nitfReadMetaMulti(tempStruct, fields, fid, currentDES);
        nitf_metaDES(currentDES).value = tempStruct;
        
        % Update lengths with the value read.
        deLengths(currentDES).value = tempStruct(2).value;
    
    end

    nitf_meta(end).value = nitf_metaDES;

end



function [nitf_meta, reLengths, reHeaderLengths] = processtopresubheadermeta(numres, nitf_meta, fid)

reLengths(1).value = '';
reHeaderLengths(1).value = '';

if (numres > 0)
    
    % Preallocate the lengths structure.
    reLengths(numres).value = '';
    reHeaderLengths(numres).value = '';
    
    nitf_meta(end + 1).name = 'ReservedExtensionsAndSubHeaderLengths';
    nitf_meta(end).vname = 'ReservedExtensionAndReservedExtensionSubheaderLengths';

    fields = {'LRSH%03d', 'LengthOfNthReservedExtensionSegmentSubheader', 4
              'LR%03d',   'LengthOfNthReservedExtensionSegmentData',      7};
    
    for currentRES = 1:numres

        % Setup.
        nitf_metaRES(currentRES).name = sprintf('ReservedExtension%03d', currentRES);
        nitf_metaRES(currentRES).vname = [nitf_metaRES(currentRES).name 'ReservedExtensionAndSubheaderLengths'];

        % Parse the data.
        tempStruct = struct([]);
        tempStruct = nitfReadMetaMulti(tempStruct, fields, fid, currentRES);
        nitf_metaRES(currentRES).value = tempStruct;

        % Update lengths with the value read.
        reHeaderLengths(currentRES).value = tempStruct(1).value;
        reLengths(currentRES).value = tempStruct(2).value;
    
    end

    nitf_meta(end).value = nitf_metaRES;
    
end



function nitf_meta = processtopudsubheadermeta(UDHDL, nitf_meta, fid)

if (UDHDL > 0)

    fields = {'UDHOFL', 'UserDefinedHeaderOverflow',      3
              'UDHDL',  'UserDefinedHeaderData',  UDHDL - 3};
    nitf_meta = nitfReadMeta(nitf_meta, fields, fid);
    
end



function nitf_meta = processtopxsubheadermeta(XHDL, nitf_meta, fid)

if (XHDL > 0)
    
    fields = {'XHDLOFL', 'ExtendedHeaderDataOverflow', 3
              'XHDL', 'ExtendedHeaderData', XHDL - 3};
    nitf_meta = nitfReadMeta(nitf_meta, fields, fid);
    
end



function nitf_meta = processImageSubheaders(nitf_meta, numi, fid, imLengths)
%Add the nth image subheader to the nitf_meta struct

nitf_meta(end + 1).name = 'ImageSubHeaders';
nitf_meta(end).vname = 'ImageSubheaderMetadata';

%Preallocate memory for ISnitf_meta
ISnitf_meta(numi).name = '';

for imageNumber = 1:numi
    ISnitf_meta(imageNumber).name = sprintf('IS%03d', imageNumber);
    ISnitf_meta(imageNumber).vname = sprintf('ImageSubheader%03d', imageNumber);
    ISnitf_meta(imageNumber).value = parseimagesubheader( fid, imLengths(imageNumber).value);
end

nitf_meta(end).value = ISnitf_meta;



function nitf_meta = processGraphicSubheaders(nitf_meta, nums, fid, grLengths)
%Add the nth graphic subheader to the nitf_meta struct

nitf_meta(end + 1).name = 'GraphicSubHeaders';
nitf_meta(end).vname = 'GraphicSubheaderMetadata';

%Preallocate memory for ISnitf_meta
IGnitf_meta(nums).name = '';

for graphicNumber = 1:nums
    IGnitf_meta(graphicNumber).name = sprintf('IG%03d', graphicNumber);
    IGnitf_meta(graphicNumber).vname = sprintf('GraphicSubheader%03d', graphicNumber);
    IGnitf_meta(graphicNumber).value = parsegraphicsubheader( fid, grLengths(graphicNumber).value);
end

nitf_meta(end).value = IGnitf_meta;



function nitf_meta = processTextSubheaders(nitf_meta, numt, fid, teLengths)
%Add the nth text subheader to the nitf_meta struct

nitf_meta(end + 1).name = 'TextSubHeaders';
nitf_meta(end).vname = 'TextSubheaderMetadata';

%Preallocate memory for ITnitf_meta
ITnitf_meta(numt).value = '';

for textNumber = 1:numt
    ITnitf_meta(textNumber).name = sprintf('IT%03d', textNumber);
    ITnitf_meta(textNumber).vname = sprintf('TextSubheader%03d', textNumber);
    ITnitf_meta(textNumber).value = parsetextsubheader( fid, teLengths(textNumber).value);
end

nitf_meta(end).value = ITnitf_meta;



function nitf_meta = processDESubheaders(nitf_meta, numdes, fid, deLengths)
%Add the nth data extension subheader to the nitf_meta struct

nitf_meta(end + 1).name = 'DataExtensionSubHeaders';
nitf_meta(end).vname = 'DataExtensionSubheaderMetadata';

%Preallocate memory for ITnitf_meta
DEnitf_meta(numdes).value = '';

for deNumber = 1:numdes
    DEnitf_meta(deNumber).name = sprintf('DE%03d', deNumber);
    DEnitf_meta(deNumber).vname = sprintf('DataExtensionSubheader%03d', deNumber);
    DEnitf_meta(deNumber).value = parseDEsubheader( fid, deLengths(deNumber).value);
end

nitf_meta(end).value = DEnitf_meta;



function nitf_meta = processRESubheaders(nitf_meta, numres, fid, reLengths, reHeaderLengths)
%Add the nth reserved extension header to the nitf_meta struct

nitf_meta(end + 1).name = 'ReservedExtensionSubHeaders';
nitf_meta(end).vname = 'ReservedExtensionSubheaderMetadata';

%Preallocate memory for ITnitf_meta..How to do this?
REnitf_meta(numres).value = '';

for reNumber = 1:numres
    REnitf_meta(reNumber).name = sprintf('RE%03d', reNumber);
    REnitf_meta(reNumber).vname = sprintf('ReserveExtensionSubheader%03d', reNumber);
    REnitf_meta(reNumber).value = parseREsubheader20( fid, reLengths(reNumber).value, reHeaderLengths(reNumber).value);
end

nitf_meta(end).value = REnitf_meta;
