function [datname, datlength, readstring, extras, blocktype, dirstart, dirend, endoffile] = gdfreadhead(fid,gdfnamelen)
%
% function [datname, datlength, readstring, extras, blocktype, dirstart, dirend, endoffile] ...
%               = gdfreadhead(fid,gdfnamelen)
%
%    GDFREADHEAD - Read out data header from binary GDF file
%
%    gdfreadhead(fid)
%
%    [datname, datlength, readstring, extras, blocktype, dirstart, dirend, endoffile] = gdfreadhead(fid)
%
%    [...] = gdfreadhead(fid,gdfnamelen)
%
%    GDFREADHEAD reads out the data header at the start of each block of
%    binary data within a binary GDF file produced by GPT.
%
%    gdfreadhead(fid) - read the header data from the GDF file with
%    file ID FID.  The file must previously have been opened with the FOPEN
%    command to produce the valid FID.
%
%    [datname, datlength, readstring, extras, blocktype, dirstart, dirend, endoffile]
%    = gdfreadhead(fid) - read out the header data and output as separate
%    variables.  The output variables are:
%
%        datname - name of variable to read out (string)
%        datlength - length of data, in bytes (double)
%        readstring - string that specifies what format the data is in and
%            what to convert it to eg. uchar=>char, *uint8; used directly
%            by fread (string)
%        extras - additional characters for reading out data eg. the '
%            character to transpose a character array (string)
%        blocktype - binary representation of GDF block type (string): 
%            0001 - directory entry start
%            0010 - directory entry end
%            0100 - single value
%            1000 - array
%        dirstart - indicates whether the variable is the start of a group;
%            dirstart = 1 if directory entry start, dirstart = 0 otherwise
%        dirend - indicates whether the variable is the last in a group;
%            dirend = 1 if directory entry end, dirend = 0 otherwise
%        endoffile - indicates whether the end of file has been reached;
%            endoffile = 1 if feof(fid) = 1, endoffile = 0 otherwise.
%
%    [...] = gdfreadhead(fid,gdfnamelen) - specify length of character
%    strings with GDFNAMELEN.  Default value is GDFNAMELEN = 16.
%
%    The header data has a standard structure, with the following format:
%
%    struct gdfhead
%
%    U8 name[GDFNAMELEN] ;
%    U32 type ;
%    U32 size ;
%
%    Data types
%
%    t_ascii  0x0001      /* Ascii string	      */
%    t_s32	 0x0002      /* Signed long	      */
%    t_dbl	 0x0003      /* Double		      */
%
%    t_undef  0x0000      /* Data type not defined */
%    t_nul	 0x0010      /* No data 	      */
%    t_u8	 0x0020      /* Unsigned char	      */
%    t_s8	 0x0030      /* Signed char	      */
%    t_u16	 0x0040      /* Unsigned short	      */
%    t_s16	 0x0050      /* Signed short	      */
%    t_u32	 0x0060      /* Unsigned long	      */
%    t_u64	 0x0070      /* Unsigned 64bit int    */
%    t_s64	 0x0080      /* Signed 64bit int      */
%    t_flt	 0x0090      /* Float		      */
%
%    Block types
%
%    t_dir	 0x0100      /* Directory entry start */
%    t_edir	 0x0200      /* Directory entry end   */
%    t_sval	 0x0400      /* Single valued	      */
%    t_arr	 0x0800      /* Array		      */
%

% File is the property of Simon Jolly, Imperial College London.  File
% released under the GNU public license.
%
% File history
%
%   26-Jun-2008 S. Jolly
%       Full read-in of GPT .gdf file and conversion to Matlab format.
%
%======================================================================

    if nargin < 1
        error('Too few input variables: syntax is [...] = gdfreadhead(fid)') ;
    elseif nargin > 2
        error('Too many input variables: syntax is [...] = gdfreadhead(fid,gdfnamelen)') ;
    elseif nargout > 8
        error('Too many output variables: syntax is [datname, datlength, readstring, extras, blocktype, dirstart, dirend, endoffile] = gdfreadhead(fid)') ;
    end

    if nargin < 2 || isempty(gdfnamelen)
        gdfnamelen = 16 ;
    end

%    Read out header data: name, type and size

    position = ftell(fid) ;
    gdfname = fread(fid, gdfnamelen, '*uint8') ;
    gdftype = dec2hex(fread(fid, 1, '*uint32')) ;
    gdfsize = fread(fid, 1, 'uint32=>double') ;

%    Determine if the end of file has been reached

    if isempty(gdfname) && isempty(gdftype) && isempty(gdfsize)
        if feof(fid)
            endoffile = 1 ;
            datname = '' ;
            datlength = 0 ;
            readstring = '' ;
            extras = [] ;
            blocktype = [] ;
            dirstart = 0 ;
            dirend = 0 ;
%            disp('End of file reached') ;
            return
        else
            endoffile = 0 ;
        end
    else
        endoffile = 0 ;
    end

%    Set the name of the variable

    [wordend] = find(gdfname == 0) ;
    datname = char(gdfname(1:wordend(1)-1))' ;

    if numel(datname) > 0 && strcmp(datname(1),'@')
        datname(1) = [] ;
    end

%    Display some information on the header if required

    if 0
        disp(['Name = "' gdfname' '", datname = "' datname '", type = "' num2str(gdftype) '", size = "' ...
            num2str(gdfsize) '" at posn. = ' num2str(position)]) ;
    end

%    Determine the block type, and whether its the start or end of a block
%    of data (directory)

    blocktype = dec2bin(str2num(gdftype(1)),4) ;

    if blocktype(4) == '1'
        dirstart = 1 ;
    else
        dirstart = 0 ;
    end

    if blocktype(3) == '1'
        dirend = 1 ;
    else
        dirend = 0 ;
    end

%    Set the readout string and data length based on the data type

    switch gdftype(3)
        case '0'
            switch gdftype(2)
                case '1'
                    readstring = '*uint8' ;
                    datlength = gdfsize ;
                    extras = [] ;
                case '1'
                    readstring = '*uint8' ;
                    datlength = gdfsize ;
                    extras = [] ;
                case '2'
                    readstring = 'uchar=>char' ;
                    datlength = gdfsize ;
                    extras = [''''] ;
                case '3'
                    readstring = 'schar=>char' ;
                    datlength = gdfsize ;
                    extras = [''''] ;
                case '4'
                    readstring = 'uint16=>double' ;
                    datlength = gdfsize./2 ;
                    extras = [] ;
                case '5'
                    readstring = 'int16=>double' ;
                    datlength = gdfsize./2 ;
                    extras = [] ;
                case '6'
                    readstring = 'uint32=>double' ;
                    datlength = gdfsize./4 ;
                    extras = [] ;
                case '7'
                    readstring = 'uint64=>double' ;
                    datlength = gdfsize./8 ;
                    extras = [] ;
                case '8'
                    readstring = 'int64=>double' ;
                    datlength = gdfsize./8 ;
                    extras = [] ;
                case '9'
                    readstring = 'float64=>double' ;
                    datlength = gdfsize./8 ;
                    extras = [] ;
                otherwise
                    error('Unknown data type') ;
            end
        case '1'
            readstring = 'uchar=>char' ;
            datlength = gdfsize ;
            extras = [''''] ;
        case '2'
            readstring = '*int32' ;
            datlength = gdfsize./4 ;
            extras = [] ;
        case '3'
            readstring = '*double' ;
            datlength = gdfsize./8 ;
            extras = [] ;
        otherwise
            error('Unknown data type') ;
    end

    return
