function [ image , Visu] = readBruker2dseq( path_to_2dseq, Visu, varargin)
% [ image ] = readBruker2dseq( path_to_2dseq, Visu, ['imageType', 'yourForcedType'], ['dim5_n', your_3D_DimArray])
% read images from disk
%
% IN:
%   path_to_2dseq: string in '' with relative path to 2dseq-data incl. filename !
%   Visu: parameterstruct with the visu-parameters
%
%   Optional [] input arguments:
%       ['imageType', 'yourForcedType']
%               Type: defined string followed by a string: 'complex' or 'real' or 'auto' (default: 'auto')
%               Defines if the process reads numbertype from
%               visu-parameters (='auto') or the type is forced ('complex' or 'real')
%               e.g. ... , 'imageType', 'real' , ...
%       ['dim5_n', your_3D_DimArray]
%               Type: defined string followed by an array with dimensions: 3x1
%               Normally all frames are written to the 5th dimension, but
%               with dim5_n you can split this 5th dimension in 5th - n-th
%               dimension. Just enter your prefered dimensions there:
%               e.g. with 24 visuFrames: ... , 'dim5_n', [3 4 2] , ...
%
% OUT:
%   image 
%       Type: complex or real matrix (most: real)
%       Dimensions: normally (dim1, dim2, dim3, dim4, NumberOfVisuFrames)
%       if you used dim5_n: (dim1, dim2, dim3, dim4, dim5_n(1), dim5_n(2), dim5_n(3), ...)


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Copyright (c) 2012
% Bruker BioSpin MRI GmbH
% D-76275 Ettlingen, Germany
%
% All Rights Reserved
%
% $Id: readBruker2dseq.m,v 1.1 2012/09/11 14:22:10 pfre Exp $
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



    %% Define default-value if necesseary:
    [varargin, imageType ] = bruker_addParamValue( varargin, 'imageType', ['@(x) (strcmp(x,''complex'') || strcmp(x,''real'') || strcmp(x,''reel'') ||', ... 
                                                                   ' strcmp(x,''magnitude'') || strcmp(x,''phase'') || strcmp(x,''imaginary'') || strcmp(x,''auto''))' ], 'auto');
    [varargin, dim5_n ] = bruker_addParamValue( varargin, 'dim5_n', '@(x) isnumeric(x)', []);
    test{1}=Visu;
    if strcmp(imageType, 'auto')
    all_here = bruker_requires(test, {'Visu', 'VisuCoreWordType', 'VisuCoreByteOrder', 'VisuCoreSize', 'VisuCoreFrameCount', 'VisuCoreDataSlope', 'VisuCoreDataOffs', ...
                                      'VisuCoreFrameType', 'VisuCoreDim', 'VisuCoreDimDesc'});
    else
        all_here = bruker_requires(test, {'Visu', 'VisuCoreWordType', 'VisuCoreByteOrder', 'VisuCoreSize', 'VisuCoreFrameCount', 'VisuCoreDataSlope', 'VisuCoreDataOffs', ...
                                          'VisuCoreDim', 'VisuCoreDimDesc'});
    end
    if ~all_here
       error('Not enough parameters in the Visu struct.') 
    end
    
    %% Check dim5_n and FrameGroups
    if isempty(dim5_n) && isfield(Visu, 'VisuFGOrderDescDim') && isfield(Visu, 'VisuFGOrderDesc')
        for i=1:size(Visu.VisuFGOrderDesc,2)
            dim5_n(i)=Visu.VisuFGOrderDesc{1,i};
        end      
    end  

    
    %% rewrite parameter-structs to local Variables:
    % visu_pars:
    VisuCoreWordType=Visu.VisuCoreWordType;
    VisuCoreByteOrder=Visu.VisuCoreByteOrder;
    VisuCoreSize=Visu.VisuCoreSize;
    NF = Visu.VisuCoreFrameCount; % number of frames
    VisuCoreDataSlope=Visu.VisuCoreDataSlope;
    VisuCoreDataOffs=Visu.VisuCoreDataOffs;
    if strcmp(imageType, 'auto')
        VisuCoreFrameType=Visu.VisuCoreFrameType;
        if isfield(Visu, 'VisuFGOrderDesc')        
            VisuFGOrderDesc=Visu.VisuFGOrderDesc;
            if size(VisuFGOrderDesc,2)>10 && iscell(VisuCoreFrameType) && length(VisuCoreFrameType)>1
                warning('MATLAB:bruker_warning', 'More then 10 Visu-Groups are not correct supported')
                imageType='real';
            end
        end
    end
    VisuCoreDim=Visu.VisuCoreDim;
    if isfield(Visu, 'VisuCoreDiskSliceOrder')        
        VisuCoreDiskSliceOrder=Visu.VisuCoreDiskSliceOrder;
        VisuCoreDimDesc=Visu.VisuCoreDimDesc;
    end
    
    
    
    
    %% Tranforming Parameters to Matlab
    %transform the Number-Format to Matlab-format (=format) and save the
    %number of bits per value
    
    %RECO_word_type ( while the byte order is given by RECO_byte_order

    switch(VisuCoreWordType)
        case ('_32BIT_SGN_INT')
            format='int32';
        case ('_16BIT_SGN_INT')
            format='int16';
        case ('_32BIT_FLOAT')
            format='float32';
        case('_8BIT_UNSGN_INT')
            format='uint8';
        otherwise
            error('Data-Format not correct specified!')
    end

    %transform the machinecode-format to matlab-format (=endian)
    switch(VisuCoreByteOrder)
        case ('littleEndian')
            endian='l';
        case ('bigEndian')
            endian='b';
        otherwise 
            error('MacineCode-Format not correct specified!')
    end
    
    % Is there a complex part stored in a frame-Group?
    complex_groupexist=false;
    if exist('VisuFGOrderDesc', 'var') && ~isempty(dim5_n) && strcmp(imageType, 'auto')      
        for i=1:size(VisuFGOrderDesc,2)
            if strcmpi(VisuFGOrderDesc{2,i}, 'FG_COMPLEX')
                complex_groupexist=true;
                complexindex=i;
            end
        end
    end
        
    
    %% calculate additional parameters: 
     
    % Calculating block size
    blockSize = VisuCoreSize(1);
    
    % Calculating number of elements in higher dimensions
    numDataHighDim=prod(VisuCoreSize(2:end));
  
    %% Reading in data

    % Opening input file
    try
        FileID=fopen(path_to_2dseq,'r');
    catch
        FileID = -1;
    end
    if FileID == -1
        error('Cannot open 2dseq file. Problem opening file %s.',path_to_visu_pars);
    end
    [image,valCount]=fread(FileID,[VisuCoreSize(1), inf],format,0,endian);
    
    % Closing input file
    fclose(FileID);
    
    % Errorcheck:
    % IF: image=Complex -> PV-Version < 6 -> errorcheck needs x2
%     if strcmpi(imageType, 'complex') || (strcmpi(imageType, 'auto') && sum(strcmpi(VisuCoreFrameType,'COMPLEX_IMAGE'))==1 )
%         if ~(valCount==2*blockSize*numDataHighDim*NF)
%             error('Size of 2dseq file does not match parameters.');
%         end
%     else
        if ~(valCount==blockSize*numDataHighDim*NF)
            error('Size of 2dseq file does not match parameters.');
        end
%     end
    
    
    
    
    
    %% Mapping data
    % to get the real values, we have to multiply with the slope-factor and
    % add the offset to the data
    slope = repmat(VisuCoreDataSlope',[VisuCoreSize(1)*numDataHighDim,1]);
    slope = reshape(slope,size(image));
    image=image.*slope;
    offset = repmat(VisuCoreDataOffs',[VisuCoreSize(1)*numDataHighDim,1]);
    offset = reshape(offset,size(image));
    image=image+offset;
    
    % set the new values:
    VisuCoreDataSlope=ones(size(VisuCoreDataSlope,1), size(VisuCoreDataSlope,2) );
    VisuCoreDataOffs=zeros(size(VisuCoreDataOffs,1), size(VisuCoreDataOffs,2) );
    
    
    %% Complex with PV < PV6
    % check the value of imageType
    %First IF: select with input-argument imageType   
        % complex-matrix
    switch imageType
        case 'complex'
            image=image(:,1:size(image,2)/2)+1i*image(:,size(image,2)/2+1:end);
        case {'real', 'reel', 'magnitude', 'phase'}
            % nothing to do, but no error
        case 'imaginary'
            image=complex(0, image(:,:));
        case 'auto'
            if sum(strcmpi(VisuCoreFrameType,'MAGNITUDE_IMAGE'))>=1 || sum(strcmpi(VisuCoreFrameType,'REAL_IMAGE'))>=1 || sum(strcmpi(VisuCoreFrameType,'PHASE_IMAGE'))>=1 || sum(strcmpi(VisuCoreFrameType,'IMAGINARY_IMAGE'))>=1
                % nothing to do at this place
            elseif strcmpi(VisuCoreFrameType,'COMPLEX_IMAGE') && ~complex_groupexist % PV < PV6 AND NOT(saved in framegroup)
                image=complex(image(:,1:size(image,2)/2), image(:,size(image,2)/2+1:end));
                NF=NF/2;
            %elseif strcmpi(VisuCoreFrameType,'IMAGINARY_IMAGE')
            %    image=complex(0, image(:,:));
            elseif complex_groupexist
                % nothing, but no error
            else
                error('Only magnitude, complex, real, and imaginary images are currently supported.');
            end
        otherwise
            error('Your imageType-input is not correct!');
    end
    
    
    %% Sorting data
    
    % sort with dimensions:
    switch VisuCoreDim
        case  1
            VisuCoreSize(2:4)=1;
        case 2
            VisuCoreSize(3:4)=1;
        case 3
            VisuCoreSize(4)=1;
        case 4
            % nothing but no error
        otherwise
            error('Unknown Visu.VisuCoreDim.');
    end
    
    if ~isempty(dim5_n)
        image=reshape(image, [ VisuCoreSize(1),VisuCoreSize(2),VisuCoreSize(3),VisuCoreSize(4), dim5_n] );
    else
        image=reshape(image, [ VisuCoreSize(1),VisuCoreSize(2),VisuCoreSize(3),VisuCoreSize(4), NF] );
    end
    
    %% Generate complex Values if the Framegroup Complex exist
    
    if complex_groupexist
        % PV 5:
        if (ischar(VisuCoreFrameType) && strcmpi(VisuCoreFrameType, 'COMPLEX_IMAGE') ) || (iscell(VisuCoreFrameType) || strcmpi(VisuCoreFrameType{1}, 'COMPLEX_IMAGE'))
            switch complexindex
                case 1
                    image=complex(image(:,:,:,:,1,:,:,:,:,:,:,:,:,:), image(:,:,:,:,2,:,:,:,:,:,:,:,:,:));
                case 2
                    image=complex(image(:,:,:,:,:,1,:,:,:,:,:,:,:,:), image(:,:,:,:,:,2,:,:,:,:,:,:,:,:));
                case 3
                    image=complex(image(:,:,:,:,:,:,1,:,:,:,:,:,:,:), image(:,:,:,:,:,:,2,:,:,:,:,:,:,:));
                case 4
                    image=complex(image(:,:,:,:,:,:,:,1,:,:,:,:,:,:), image(:,:,:,:,:,:,:,2,:,:,:,:,:,:));
                case 5
                    image=complex(image(:,:,:,:,:,:,:,:,1,:,:,:,:,:), image(:,:,:,:,:,:,:,:,2,:,:,:,:,:));
                case 6
                    image=complex(image(:,:,:,:,:,:,:,:,:,1,:,:,:,:), image(:,:,:,:,:,:,:,:,:,2,:,:,:,:));
                case 7
                    image=complex(image(:,:,:,:,:,:,:,:,:,:,1,:,:,:), image(:,:,:,:,:,:,:,:,:,:,2,:,:,:));
                case 8
                    image=complex(image(:,:,:,:,:,:,:,:,:,:,:,1,:,:), image(:,:,:,:,:,:,:,:,:,:,:,2,:,:));
                case 9
                    image=complex(image(:,:,:,:,:,:,:,:,:,:,:,:,1,:), image(:,:,:,:,:,:,:,:,:,:,:,:,2,:));
                case 10
                    image=complex(image(:,:,:,:,:,:,:,:,:,:,:,:,:,1), image(:,:,:,:,:,:,:,:,:,:,:,:,:,2));
            end
            
            % PV 6:
        elseif strcmpi(VisuCoreFrameType{1}, 'REAL_IMAGE') && strcmpi(VisuCoreFrameType{2}, 'IMAGINARY_IMAGE')
            switch complexindex
                case 1
                    image=complex(image(:,:,:,:,1,:,:,:,:,:,:,:,:,:), image(:,:,:,:,2,:,:,:,:,:,:,:,:,:));
                case 2
                    image=complex(image(:,:,:,:,:,1,:,:,:,:,:,:,:,:), image(:,:,:,:,:,2,:,:,:,:,:,:,:,:));
                case 3
                    image=complex(image(:,:,:,:,:,:,1,:,:,:,:,:,:,:), image(:,:,:,:,:,:,2,:,:,:,:,:,:,:));
                case 4
                    image=complex(image(:,:,:,:,:,:,:,1,:,:,:,:,:,:), image(:,:,:,:,:,:,:,2,:,:,:,:,:,:));
                case 5
                    image=complex(image(:,:,:,:,:,:,:,:,1,:,:,:,:,:), image(:,:,:,:,:,:,:,:,2,:,:,:,:,:));
                case 6
                    image=complex(image(:,:,:,:,:,:,:,:,:,1,:,:,:,:), image(:,:,:,:,:,:,:,:,:,2,:,:,:,:));
                case 7
                    image=complex(image(:,:,:,:,:,:,:,:,:,:,1,:,:,:), image(:,:,:,:,:,:,:,:,:,:,2,:,:,:));
                case 8
                    image=complex(image(:,:,:,:,:,:,:,:,:,:,:,1,:,:), image(:,:,:,:,:,:,:,:,:,:,:,2,:,:));
                case 9
                    image=complex(image(:,:,:,:,:,:,:,:,:,:,:,:,1,:), image(:,:,:,:,:,:,:,:,:,:,:,:,2,:));
                case 10
                    image=complex(image(:,:,:,:,:,:,:,:,:,:,:,:,:,1), image(:,:,:,:,:,:,:,:,:,:,:,:,:,2));
            end
            % PV 6
        elseif strcmpi(VisuCoreFrameType{2}, 'REAL_IMAGE') && strcmpi(VisuCoreFrameType{1}, 'IMAGINARY_IMAGE')
            switch complexindex
                case 1
                    image=complex(image(:,:,:,:,2,:,:,:,:,:,:,:,:,:), image(:,:,:,:,1,:,:,:,:,:,:,:,:,:));
                case 2
                    image=complex(image(:,:,:,:,:,2,:,:,:,:,:,:,:,:), image(:,:,:,:,:,1,:,:,:,:,:,:,:,:));
                case 3
                    image=complex(image(:,:,:,:,:,:,2,:,:,:,:,:,:,:), image(:,:,:,:,:,:,1,:,:,:,:,:,:,:));
                case 4
                    image=complex(image(:,:,:,:,:,:,:,2,:,:,:,:,:,:), image(:,:,:,:,:,:,:,1,:,:,:,:,:,:));
                case 5
                    image=complex(image(:,:,:,:,:,:,:,:,2,:,:,:,:,:), image(:,:,:,:,:,:,:,:,1,:,:,:,:,:));
                case 6
                    image=complex(image(:,:,:,:,:,:,:,:,:,2,:,:,:,:), image(:,:,:,:,:,:,:,:,:,1,:,:,:,:));
                case 7
                    image=complex(image(:,:,:,:,:,:,:,:,:,:,2,:,:,:), image(:,:,:,:,:,:,:,:,:,:,1,:,:,:));
                case 8
                    image=complex(image(:,:,:,:,:,:,:,:,:,:,:,2,:,:), image(:,:,:,:,:,:,:,:,:,:,:,1,:,:));
                case 9
                    image=complex(image(:,:,:,:,:,:,:,:,:,:,:,:,2,:), image(:,:,:,:,:,:,:,:,:,:,:,:,1,:));
                case 10
                    image=complex(image(:,:,:,:,:,:,:,:,:,:,:,:,:,1), image(:,:,:,:,:,:,:,:,:,:,:,:,:,1));
            end
        else
            error('Your VisuCoreFrameType is not supported')
        end
        % delete Group-entry
        VisuFGOrderDesc(:,complexindex)=[];
        VisuCoreFrameType='COMPLEX_IMAGE';
        NF=NF/2;
    end


                
    
    

    if exist('VisuCoreDiskSliceOrder', 'var') && strcmpi(VisuCoreDiskSliceOrder, 'disk_reverse_slice_order') && VisuCoreDim==3    
        image=flipdim(image, 3);
        VisuCoreDiskSliceOrder='disk_normal_slice_order';
    elseif exist('VisuCoreDiskSliceOrder', 'var') && strcmpi(VisuCoreDiskSliceOrder, 'disk_reverse_slice_order') && VisuCoreDim==4 && sum(strcmp(VisuCoreDimDesc, 'spatial'))==3
        % find 3rd spatial dimension: only 3x spatial -> last spacial searched
        for i=1:4
            if strcmp(VisuCoreDimDesc{i}, 'spatial')
                pos=i;
            end
        end
        image=flipdim(image, pos);
    elseif exist('VisuCoreDiskSliceOrder', 'var') && strcmpi(VisuCoreDiskSliceOrder, 'disk_reverse_slice_order')
       warning('MATLAB:bruker_note', 'The parameter VisuCoreDiskSliceOrder is set to disk_reverse_slice_order and the VisuCoreDim is not 3 - Other dimensions then 3 are not supported. Please sort your matrix yourself');
    end
    
    
    %% Write changed variables back
    if exist('VisuCoreDiskSliceOrder', 'var')
        Visu.VisuCoreDiskSliceOrder=VisuCoreDiskSliceOrder;
    end
    if exist('VisuFGOrderDesc', 'var')
        Visu.VisuFGOrderDesc=VisuFGOrderDesc;
    end
    if exist('VisuCoreFrameType', 'var')
        Visu.VisuCoreFrameType=VisuCoreFrameType;
    end
    Visu.VisuCoreDataSlope=VisuCoreDataSlope;
    Visu.VisuCoreDataOffs=VisuCoreDataOffs;
    Visu.VisuCoreFrameCount=NF;
end

