%-------------------------------------------------------------------------%
% SDS_INFO.m
%-------------------------------------------------------------------------%
% Auteur: Aminata NDIAYE, CGTD ICARE 2013
%-------------------------------------------------------------------------%
% Version: 0, Décembre 2013
% Revison: JUIN 2014
%-------------------------------------------------------------------------%




classdef SDS_INFO
    properties (SetAccess = private, GetAccess = public)
        filename;
        sdsname;
    end
    
    methods
        
        % Create a constructor
        function obj = SDS_INFO ( file_name, sds_name)
            if nargin == 2
                obj.filename = file_name  ;
                obj.sdsname =  sds_name;
            else
                error(' Invalid input arguments: enter a file name and a dataset name');
            end
        end
        %------------------------------------
        
        % Open the hdf file
        function sd_id = open_hdf_file (obj)
            
            sd_id = isempty(obj.filename) ;
            if sd_id == 1
                error('Filename is null');
            end
            
            sd_id = hdfh('ishdf', obj.filename) ;
            if   sd_id == 0
                error('It is not a hdf file')
            end
            
            sd_id =  hdfsd( 'start', obj.filename,  'rdonly');
            if sd_id < 0
                error ('Fail to open the hdf file')
            end
        end
        %------------------------------------
        
        
        
        % Get the sds identifier
        function sds_id = get_id_from_sdsname(obj, sd_id)
            sds_index  = hdfsd('nametoindex', sd_id, obj.sdsname) ;
            sds_id = hdfsd('select', sd_id, sds_index);
        end
        %------------------------------------
        
        % Create an attribute structure
        function attr = create_attr ( obj, id, number_of_attributes, varargin)
            attr = struct([]);
            if nargin == 4
                % attr_name existe
                attr_name = varargin{1};
                var = hdfsd('findattr', id, attr_name);
                start_cpt = var;
                end_cpt = var;
            else
                start_cpt = 0;
                end_cpt = number_of_attributes - 1;
            end
            
            for i = start_cpt :   end_cpt
                [attr(i+1,1).name, attr(i+1,1).dtype, attr(i+1,1).count, attr(i+1,1).status] = hdfsd('attrinfo', id, i);
                obj.test_status('hdfsd[attrinfo]', attr(i+1,1).status);
                attr(i+1,1).value = hdfsd('readattr', id, i);
                sprintf('Attribute name: %s\nData type: %s\nCount :%s\nAttribute value: %s\n',attr(i+1,1).name,...
                    attr(i+1,1).dtype, num2str(attr(i+1,1).count), num2str(attr(i+1,1).value))
            end
            
        end
        %------------------------------------
        
        % Get attributes characteristics
        function attr = get_sds_attr (obj, varargin)
            sd_id =  obj.open_hdf_file();
            sds_id = obj.get_id_from_sdsname (sd_id);
            [name, num_dim, sds_dim,sds_datatype, num_attr] = hdfsd('getinfo', sds_id);
            if nargin == 2  %  Get an sds attribute
                attr = obj.create_attr( sds_id, num_attr,  varargin{1});
            else    % Get all sds attributes
                attr = obj.create_attr( sds_id, num_attr);
            end
            obj.close_sds_access (sds_id);
            obj.close_hdf_file (sd_id);
        end
        
        % Get sds calibration
        function calibration = get_sds_calibration(obj)
            sd_id =  obj.open_hdf_file();
            sds_id = obj.get_id_from_sdsname (sd_id);
            [calibration.cal, calibration.cal_err, calibration.offset, calibration.offset_err, calibration.sds_datatype, calibration.status]...
                = hdfsd('getcal',sds_id);
            obj.test_status('hdfsd[getcal', calibration.status);
            obj.close_sds_access (sds_id);
            obj.close_hdf_file (sd_id);
        end
        %------------------------------------
        
        % Get sds fill value
        function fillvalue = get_sds_fillvalue(obj)
            sd_id =  obj.open_hdf_file();
            sds_id = obj.get_id_from_sdsname (sd_id);
            [fillvalue, status] = hdfsd('getfillvalue',sds_id);
            obj.test_status('hdfsd[getfillvalue]', status);
            obj.close_sds_access (sds_id);
            obj.close_hdf_file (sd_id);
        end
        
        %------------------------------------
        
        % Get sds binary data
        function data = get_sds_binary_data(obj, varargin)
            sd_id = obj.open_hdf_file() ;
            sds_id = obj.get_id_from_sdsname(sd_id);
            if nargin == 1
                data = hdfread (obj.filename, obj.sdsname) ;
            elseif nargin == 4
                % Get binary data with start, stride, edge
                start= varargin{1};
                stride = varargin{2};
                edge =  varargin{3};
                data = hdfread (obj.filename, obj.sdsname, 'Index', {start, stride, edge}) ;
            else
                error ('Invalid inputs argument');
            end
            obj.close_sds_access (sds_id);
            obj.close_hdf_file (sd_id);
            
        end
        %------------------------------------
        
        % Get sds scaled data
        function scaled_data = get_sds_scaled_data(obj, varargin)
            sd_id = obj.open_hdf_file() ;
            sds_id = obj.get_id_from_sdsname(sd_id);
            data = get_sds_binary_data(obj, varargin{:});
            [scale_factor, scale_factor_err, offset, offset_err, format, status]...
                = hdfsd('getcal',sds_id);
            obj.test_status('hdfsd[getcal]', status);
            scaled_data = double(data - offset ) * scale_factor;
            obj.close_sds_access (sds_id);
            obj.close_hdf_file (sd_id);
        end
        %------------------------------------
        
        % Get a string describing an SDS_INFO instance
        function info = get_obj_caracteristics ( obj )
            sd_id = obj.open_hdf_file() ;
            sds_id = obj.get_id_from_sdsname(sd_id);
            [obj.sdsname,  number_of_dim, size_of_dim, sds_datatype, number_of_attributes] = hdfsd('getinfo', sds_id) ;
            info = sprintf('HDF file: %s\nDataset name: %s\nNumber of dimensions: %d\nSize of dimensions: %s\nData type: %s\nNumber of attributes: %d',...
                obj.filename, obj.sdsname, number_of_dim,num2str(size_of_dim),  sds_datatype, number_of_attributes );
            obj.close_sds_access (sds_id);
            obj.close_hdf_file (sd_id);
            
        end        
        %------------------------------------
        
        % Get a string describing the hdf file
        function info = get_hdf_info (obj)
            hdf_id = obj.open_hdf_file() ;
            [num_datasets, num_global_attr, status] = hdfsd('fileinfo',hdf_id) ;
            obj.test_status('hdfsd[fileinfo]', status);
            info = sprintf('HDF file name:  %s\nHDF file identifier: %d\nNumber of datasets: %d\nNumber of global attributes: %d',...
                obj.filename, hdf_id, num_datasets, num_global_attr);
            
            obj.close_hdf_file (hdf_id);
        end
        %------------------------------------
        
        % Get hdf file attribute(s)
        function attr = get_hdf_attr (obj)
            sd_id = obj.open_hdf_file() ;
            [num_datasets, num_global_attr, status] = hdfsd('fileinfo',sd_id);
            obj.test_status('hdfsd[fileinfo]', status);
            attr = struct([]);
            obj.create_attr(sd_id, num_global_attr, attr, '');
            obj.close_hdf_file (sd_id);
        end
        %------------------------------------
    end
    
    
    methods (Static)
        %------------------------------------
        % Close the hdf file access
        function close_hdf_file (sd_id)
            status  =  hdfsd('end',sd_id) ;
            if status < 0
                error ('Failed to close the hdf file');
            end
        end
        %------------------------------------
        
        % Close sds access
        function close_sds_access (sds_id)
            status  =  hdfsd('endaccess',sds_id) ;
            if status < 0
                error ('Failed to close sds access');
            end
        end
        
        %------------------------------------
        % Test status value
        function test_status(var, status)
            if status == -1
                error('Funtion %s failed', var);
            end
        end
        
        %------------------------------------
        
        % Set start, stride and edge
        function sds_param = set_start_stride_edge(number_of_dim, size_of_dim)
            sds_param.start = zeros(1,  number_of_dim);
            sds_param.stride = [];
            sds_param.edges = size_of_dim;
        end
        
    end
    
    
end


