%'check_field_structure': check the validity of the field struture representation consistant with the netcdf format
%------------------------------------------------------------------------
% function [DataOut,errormsg]=check_field_structure(Data)
%
% OUTPUT:
% DataOut: structure reproducing the input structure Data, with the additional elements:
%           with fields:
%
%            .ListDimName: cell listing the names of the array dimensions
%             .DimValue: array dimension values (Matlab vector with the same length as .ListDimName
%            .VarDimIndex: cell containing the set of dimension indices (in list .ListDimName) for each variable of .ListVarName
%            .VarDimName: cell containing a cell of dimension names (in list .ListDimName) for each variable of .ListVarName
% errormsg: error message which is not empty when the input structure does not have the right form
%
% INPUT:
% Data:   structure containing 
%         (optional) .ListGlobalAttribute: cell listing the names of the global attributes
%                    .Att_1,Att_2... : values of the global attributes
%         (requested)  .ListVarName: list of variable names to select (cell array of  char strings {'VarName1', 'VarName2',...} ) 
%         (requested)  .VarDimName: list of dimension names for each element of .ListVarName (cell array of string cells)                         
%         (requested) .Var1, .Var2....: variables (Matlab arrays) with names listed in .ListVarName


function [DataOut,errormsg]=check_field_structure(Data)
DataOut=[]; %default
errormsg=[];
if ~isstruct(Data)
    errormsg='input field is not a structure';
    return
end
if isfield(Data,'ListVarName') && iscell(Data.ListVarName)
    nbfield=numel(Data.ListVarName); 
else
    errormsg='input field does not contain the cell array of variable names .ListVarNames';
    return
end
%check dimension names
if (isfield(Data,'VarDimName') && iscell(Data.VarDimName))
    if  numel(Data.VarDimName)~=nbfield
       errormsg=' .ListVarName and .VarDimName have different lengths';
        return
    end
else
    errormsg='input field does not contain the  cell array of dimension names .VarDimName';
    return
end
if isfield(Data,'DimValue')
    Data=rmfield(Data,'DimValue');
end
nbdim=0;
Data.ListDimName={};

%% main loop on the list of variables
for ivar=1:nbfield
    VarName=Data.ListVarName{ivar};
    if ~isfield(Data,VarName)
        errormsg=['the listed variable ' VarName ' is not found'];
        return
    end
    eval(['sizvar=size(Data.' VarName ');'])% sizvar = dimension of variable
    DimCell=Data.VarDimName{ivar};
    if ischar(DimCell)
        DimCell={DimCell};%case of a single dimension name, defined by a string
    elseif ~iscell(DimCell)
        errormsg=['wrong format for .VarDimName{' num2str(ivar) ' (must be the cell of dimension names of the variable ' VarName];
        return
    end
    nbcoord=numel(sizvar);%nbre of coordinates for variable named VarName
    testrange=0;
    if numel(DimCell)==0
        errormsg=['empty declared dimension .VarDimName{' num2str(ivar) '} for ' VarName];
        return
    elseif numel(DimCell)==1% one dimension declared
        if nbcoord==2
            if sizvar(1)==1
                nbcoord=1;
                sizvar(1)=sizvar(2);
            elseif sizvar(2)==1
                nbcoord=1;
            else
                errormsg=['1 dimension declared in .VarDimName{' num2str(ivar) '} inconsistent with the nbre of dimensions =2 of the variable ' VarName];
                return
            end
            if sizvar(1)==2 && isequal(VarName,DimCell{1})
                testrange=1;% test for a dimension variable representing a range 
            end
        else
            errormsg=['1 dimension declared in .VarDimName{' num2str(ivar) '} inconsistent with the nbre of dimensions =' num2str(nbcoord) ' of the variable ' VarName];
            return
        end
    else
        if numel(DimCell)>nbcoord
            DimCell=DimCell(end-nbcoord+1:end);%first singleton diemensions omitted,
        elseif nbcoord > numel(DimCell)
            errormsg=['nbre of declared dimensions in .VarDimName{' num2str(ivar) '} smaller than the nbre of dimensions =' num2str(nbcoord) ' of the variable ' VarName];
            return
        end
    end
    DimIndex=[];
    for idim=1:nbcoord %loop on the coordinates of variable #ivar
        DimName=DimCell{idim};
        iprev=find(strcmp(DimName,Data.ListDimName),1);%look for dimension name DimName in the current list
        if isempty(iprev)% append the dimension name to the current list
            nbdim=nbdim+1;
            RangeTest(nbdim)=0; %default
            if sizvar(idim)==2 && strcmp(DimName,VarName)%case of a coordinate defined by the two end values (regular spacing)
                RangeTest(nbdim)=1; %to be updated for a later variable  
            end
            Data.DimValue(nbdim)=sizvar(idim);
            Data.ListDimName{nbdim}=DimName;
            DimIndex=[DimIndex nbdim];
        else % DimName is detected in the current list of dimension names
            if ~isequal(Data.DimValue(iprev),sizvar(idim))
                        RangeTest(iprev)
            Data.DimValue(iprev)
                if isequal(Data.DimValue(iprev),2)&& RangeTest(iprev)  % the dimension has been already detected as a range [min max]
                    Data.DimValue(iprev)=sizvar(idim); %update with actual value
                elseif ~testrange                
                    errormsg=['dimension declaration inconsistent with the size =[' num2str(sizvar) '] for ' VarName];
                    return
                end
            end
            DimIndex=[DimIndex iprev];
        end
    end
    Data.VarDimIndex{ivar}=DimIndex;
end
DataOut=Data;
    
   