classdef MEAAnalysis < handle
    
    properties
        par
        relevantFieldsXls
        excelRecordingDataFileName
        nTotalRecordings
        gridSorterObj
        
        currentDataObj
        currentRecName
        currentPRec
        currentMEAFiles
        currentMEADir
        currentAnalysisFolder
        currentPlotFolder
        
        files
    end
    
    properties (Constant)
        xlsSheet=1;
        titleLine=1;
        startCol=1;
        figResJPG=400;
        figResEPS=1000; %is not important
        defaultXlsFile='\\storage.laur.corp.brain.mpg.de\Data_3\Shein-IdelsonMark\DCMEA.xlsx';
        MCRackDir='MCRackData';
    end
    
    methods
        
   [data]=getSpikePositionEstimation(obj,varargin);
       
        %% MEAAnalysis - class constructor
        function [obj]=MEAAnalysis(xlsFile)
            if nargin==0
                obj=obj.getExcelData;
            elseif nargin==1
                obj=obj.getExcelData(xlsFile);
            end
        end
        %% getFileNames
        function [obj,fileName]=getFileNames(obj,methodName)
            %get the names of mat files associated with every method (or a specific method)
            %[obj,fileName]=getFileNames(obj,methodName)
            %   methodName - the name of the method
            %   fileName - the mat file name associated with the method and a specific recording
            if nargin==1
                methodNames=methods(obj);
                handleMethods=methods('handle');
                uniqueMethods=setdiff(methodNames,handleMethods);
                for i=1:numel(uniqueMethods)
                    obj.files.(uniqueMethods{i})=[obj.currentAnalysisFolder filesep uniqueMethods{i} '.mat'];
                end
            else
                fileName=[obj.currentAnalysisFolder filesep methodName '.mat'];
                obj.files.(methodName)=[obj.currentAnalysisFolder filesep methodName '.mat'];
            end
        end
        
        %% populate gridSorter object
        function obj=populateGridSorterObj(obj,gridSorterObj)
            if nargin==1
                obj.gridSorterObj=gridSorter(obj.currentDataObj);
            elseif nargin==2
                obj.gridSorterObj=gridSorterObj;
            end
            obj.gridSorterObj=obj.gridSorterObj.loadMetaData(obj.gridSorterObj.sortingDir);
        end
        
        %% batchProcessData
        function [outArgAll]=batchProcessData(obj,method,recNumbers,varargin)
            
            nOut=nargout;
            nRec=numel(recNumbers);
            
            pMultiParam=cellfun(@(x) iscell(x),varargin(2:2:end));
            %check input validity
            for i=find(pMultiParam)
                if numel(varargin{i*2})~=nRec
                    disp(['Size of cell array args for arg: ' varargin{i*2-1} ' does not match the number of recordings']);
                    return;
                end
            end
            
            %change arguments with single value to cell arrays to fit the multi value arguments
            if any(pMultiParam)
                for i=find(~pMultiParam)
                    tmpCell=cell(1,nRec);
                    tmpCell=cellfun(@(x) varargin{i*2},tmpCell,'UniformOutput',0);
                    varargin{i*2}=tmpCell;
                end
            end
            
            fprintf(['Performing batch analysis on method ' method '\nAnalyzing recording number:']);
            if obj.parPool4Batch & nRec>1
                parfor i=1:nRec
                    tmpObj=obj.setCurrentRecording(recNumbers(i));
                    fprintf('%d ',recNumbers(i));
                    if any(pMultiParam)
                        tmpVaragrin=cellfun(@(x) x{i},varargin(2:2:end),'UniformOutput',0);
                        newVarargin={};
                        newVarargin(1:2:numel(varargin))=varargin(1:2:end);
                        newVarargin(2:2:numel(varargin))=tmpVaragrin;
                        if nOut>0
                            [outArgs]=tmpObj.(method)(newVarargin{:});
                            outArgAll{i}=outArgs;
                        else
                            tmpObj.(method)(newVarargin{:});
                        end
                    else
                        if nOut>0
                            [outArgs]=tmpObj.(method)(varargin{:});
                            outArgAll{i}=outArgs;
                        else
                            tmpObj.(method)(varargin{:});
                        end
                    end
                    %return all non object variables
                end
            else
                for i=1:nRec
                    tmpObj=obj.setCurrentRecording(recNumbers(i));
                    fprintf('%d ',recNumbers(i));
                    if any(pMultiParam)
                        tmpVaragrin=cellfun(@(x) x{i},varargin(2:2:end),'UniformOutput',0);
                        newVarargin={};
                        newVarargin(1:2:numel(varargin))=varargin(1:2:end);
                        newVarargin(2:2:numel(varargin))=tmpVaragrin;
                        if nOut>0
                            [outArgs]=tmpObj.(method)(newVarargin{:});
                            outArgAll{i}=outArgs;
                        else
                            tmpObj.(method)(newVarargin{:});
                        end
                    else
                        if nOut>0
                            [outArgs]=tmpObj.(method)(varargin{:});
                            outArgAll{i}=outArgs;
                        else
                            tmpObj.(method)(varargin{:});
                        end
                    end
                    %return all non object variables
                end
            end
        end
        
        %% getDigitalTriggers
        function obj=getDigitalTriggers(obj,recNumber)
            
            obj.checkFileRecording;
            [tTrig,~,tTrig_string]=obj.currentDataObj.getTrigger;
            
            %save files
            obj.files.digiTrig=[obj.currentAnalysisFolder filesep 'digiTrig.mat'];
            save(obj.files.digiTrig,'tTrig','tTrig_string');
        end
        
        %% getExcelData
        function [obj]=getExcelData(obj,excelRecordingDataFileName,additionalExcelFieldNames)
            if nargin==1
                obj.excelRecordingDataFileName=obj.defaultXlsFile;
            else
                obj.excelRecordingDataFileName=excelRecordingDataFileName;
            end
                  
            %General rules for formatting excel files:
            %1) All title names will be extracted as fields, except if they have a '#' as a first letter
            %2) If an line does not contain data, it has to have 1 in the exclude colomn
            %3) If a field has a 
            
            
            %get data from excel spread sheet
            [excelNum,excelTxt,excelRaw] = xlsread(obj.excelRecordingDataFileName,obj.xlsSheet,'','basic'); %basic mode used for computers without installed excel
            xlsFieldNames=excelTxt(obj.titleLine,:);
            maxRow=size(excelTxt,1);
            
            %get all fields except the ones starting with #
            obj.relevantFieldsXls=excelRaw(obj.titleLine,:);
            pRelevantFields=cellfun(@(x) x(1)~='#',obj.relevantFieldsXls);
            obj.relevantFieldsXls=obj.relevantFieldsXls(pRelevantFields);
            
            for i=1:numel(obj.relevantFieldsXls)
                pFieldInExcel=find(strcmp(xlsFieldNames,obj.relevantFieldsXls{i}));
                if ~isempty(pFieldInExcel)
                    obj.par.(obj.relevantFieldsXls{i})=excelRaw(obj.titleLine+1:maxRow,pFieldInExcel+obj.startCol-1);
                else
                    obj.par.(obj.relevantFieldsXls{i})=[];
                end
            end
            obj.nTotalRecordings=numel(obj.par.(obj.relevantFieldsXls{1}));
            disp(['Experiment data retrieved from: ' num2str(obj.excelRecordingDataFileName)]);
        end
        
        %% getRecordingNames
        function getRecordingNames(obj)
            disp(obj.par.recNames);
        end
        
        %% setCurrentRecording
        function [obj]=setCurrentRecording(obj,recName) %if recNumber is negative loads all recording related files but not recording object
            if nargin>1
                pRec=find(strcmp(obj.par.recNames,recName));
                if numel(pRec)==1
                    %get files
                     obj.currentMEADir=[obj.par.folder{pRec} filesep obj.MCRackDir filesep];
                     if ~exist(obj.currentMEADir,'dir')
                         obj.currentMEADir=[obj.par.folder{pRec} filesep];
                     end
                     MEAfileNames=regexp(obj.par.MEAfiles{pRec},',','split');
                     if numel(MEAfileNames)==1 %if to take all mcd files with the beginning specified in obj.par.MEAfiles
                         currentMEAFilesShort=dir([obj.currentMEADir obj.par.MEAfiles{pRec} '*.mcd']);
                         currentMEAFilesShort={currentMEAFilesShort.name};
                     else %if all file names are given explicitly in obj.par.MEAfiles, notice if there is one file that is given explicitly, a comma should be added as well
                        currentMEAFilesShort=cellfun(@(x) [x '.mcd'],MEAfileNames,'UniformOutput',0);
                     end
                     obj.currentMEAFiles=cellfun(@(x) [obj.currentMEADir x],currentMEAFilesShort,'UniformOutput',0);
                     
                     %create data object
                     obj.currentDataObj=MCRackRecording(obj.currentMEAFiles);
                     obj.currentRecName=recName;
                     obj.currentPRec=pRec;
                     
                     %define related folders and construct correspondin file names
                     obj.currentAnalysisFolder=[obj.par.folder{pRec} filesep 'analysis' filesep obj.par.recNames{pRec}];
                     obj.currentPlotFolder=[obj.par.folder{pRec} filesep 'plots' filesep obj.par.recNames{pRec}];
                     obj=obj.getFileNames;
                     
                     [stat,mess,messid]=mkdir(obj.currentAnalysisFolder); %creates analysis directory if not existing
                     [stat,mess,messid]=mkdir(obj.currentPlotFolder); %creates analysis directory if not existing
                     fprintf('Current exp. set to: %s @ %s\n',obj.par.recNames{pRec},obj.par.folder{pRec});
                     
                 elseif numel(pRec)==0
                     disp('Recording name was not found in recording list');
                     return;
                 end
                 
             elseif nargin==1
                 disp('Not enough inputs, specify a recording name or number');
                 return;
             end
        end
    
        %% checkFile - check the existance of a data file and a recording object
        function checkFileRecording(obj,fileName,message)
            if isempty(obj.currentDataObj)
                error('No data recording object selected!!!!');
            end
            if nargin>1
                if ~exist(fileName,'file')
                    if nargin==2
                        error('Relevant analysis file missing, please first run relevant function');
                    else
                        error(message);
                    end
                end
            end
        end

    end
    
end