function [optSettings,missingInfo] = loadOptSettings(optimizerFolder,optInputFile)
% [optSettings,missingInfo] = loadOptSettings(optimizerFolder,optInputFile) 
% loads the linear least squares optimization settings from the 
% optimization input file into  a Matlab structure.  Beamlets are not 
% loaded, but everything else is. If any inconsistancies are found, such as
% 
% missing fields, etc, the inconsistancies are stored in the cell array, 
% missingInfo.  The optInputFile must be that absolute path of the input 
% file.
%
% RTF 1/19/07

% initialize outputs
optSettings = [];
missingInfo = {};

% Open the optimization input file
fid = fopen([optimizerFolder '/' optInputFile],'r');

if fid == -1
    error(['Unable to open ' optimizerFolder '/' optInputFile]);
end

optSettings = [];  % optimization settings structure

% read the file into a cell array, line-by-line
fileText = {};
while 1
    tline = fgetl(fid);
    if ~ischar(tline)
        break; 
    end
    fileText{end+1} = tline;
end
fclose(fid);

% Extract the folder name that contains the input file
inputFileNameRev = fliplr(optInputFile);  % flip the input filename around
% pop off the reversed file name
[fileNameRev,inputFolderRev] = strtok(inputFileNameRev,{'/','\'});
inputFolder = fliplr(inputFolderRev);
if isempty(inputFolder)  % input folder is the current folder
    inputFolder = pwd;
end

optSettings.optInfo.inputFile = fliplr(fileNameRev);
%                 Field Name              subfield            conversion  function
fieldFunctions = {'Niterations'           'optInfo'           'str2num'            
                  'Nperbatch'             'optInfo'           'str2num'            
                  'prescFile'             'prescInfo'         ''                   
                  'initBeamWeightFile'    'initialGuessInfo'  ''                   
                  'beamletHeaderFileName' 'beamletInfo'       ''                   
                  'doseBatchBaseName'     'optInfo'           ''                   
                  'doseBatchExtension'    'optInfo'           ''                   
                  'weightBatchBaseName'   'optInfo'           ''                   
                  'weightBatchExtension'  'optInfo'           ''                   
                  'objFuncFileName'       'optInfo'           ''
                  'modFactor'             'optInfo'           'str2num'
                  'calcInitialGuessFlag'  'initialGuessInfo'  'str2num'};

% search for key fields
for k=1:length(fileText)
    for m=1:size(fieldFunctions,1)
        if strcmp(deblank(fileText{k}),fieldFunctions{m,1})
            eval(['optSettings.' fieldFunctions{m,2} '.' fieldFunctions{m,1} ' = ' fieldFunctions{m,3} '(''' fileText{k+1} ''');']);
        end
    end
end

% search for missing fields
for k=1:size(fieldFunctions,1)
    if ~isfield(optSettings,fieldFunctions{k,2}) | ~eval(['isfield(optSettings.' fieldFunctions{k,2} ',''' fieldFunctions{k,1} ''')'])
        missingInfo{end+1} = ['Missing: optSettings.' fieldFunctions{k,2} '.' fieldFunctions{k,1}];
    end
end

% find the output folder
if isfield(optSettings,'optInfo') & isfield(optSettings.optInfo,'doseBatchBaseName')
    doseBatchBaseNameRev = fliplr(optSettings.optInfo.doseBatchBaseName);
    [fileNameRev,outputFolderRev] = strtok(doseBatchBaseNameRev,{'/','\'});
    optSettings.optInfo.outputFolder = fliplr(outputFolderRev);
    optSettings.optInfo.outputFolder(:,end) = [];  % delete last character, which is a '/' or '\'
    optSettings.optInfo.doseBatchBaseName = fliplr(fileNameRev);
end

% get the weightBatchBaseName
if isfield(optSettings,'optInfo') & isfield(optSettings.optInfo,'weightBatchBaseName')
    doseBatchBaseNameRev = fliplr(optSettings.optInfo.weightBatchBaseName);
    [fileNameRev,outputFolderRev] = strtok(doseBatchBaseNameRev,{'/','\'});
    optSettings.optInfo.weightBatchBaseName = fliplr(fileNameRev);
end

% find the input folder
if isfield(optSettings,'prescInfo') & isfield(optSettings.prescInfo,'prescFile')
    prescFileRev = fliplr(optSettings.prescInfo.prescFile);
    [fileNameRev,inputFolderRev] = strtok(prescFileRev,{'/','\'});
    optSettings.optInfo.inputFolder = fliplr(inputFolderRev);
    optSettings.optInfo.inputFolder(:,end) = [];  % delete last character, which is a '/' or '\'
    optSettings.prescInfo.prescFile = fliplr(fileNameRev);
end

% get the initial beam weights file name
if isfield(optSettings,'initialGuessInfo') & isfield(optSettings.initialGuessInfo,'initBeamWeightFile')
    initBeamWeightFileRev = fliplr(optSettings.initialGuessInfo.initBeamWeightFile);
    [fileNameRev,inputFolderRev] = strtok(initBeamWeightFileRev,{'/','\'});
    optSettings.initialGuessInfo.initBeamWeightFile = fliplr(fileNameRev);
end

% trim off the objective function filename
if isfield(optSettings,'optInfo') & isfield(optSettings.optInfo,'objFuncFileName')
    prescFileRev = fliplr(optSettings.optInfo.objFuncFileName);
    [fileNameRev,inputFolderRev] = strtok(prescFileRev,{'/','\'});
    optSettings.optInfo.objFuncFileName = fliplr(fileNameRev);
end

% get the beamletFolder and beamletHeader
if isfield(optSettings,'beamletInfo') & isfield(optSettings.beamletInfo,'beamletHeaderFileName')
    beamletHeaderFileNameRev = fliplr(optSettings.beamletInfo.beamletHeaderFileName);
    [fileNameRev,beamletFolderRev] = strtok(beamletHeaderFileNameRev,{'/','\'});
    optSettings.beamletInfo.beamletFolder = fliplr(beamletFolderRev);
    optSettings.beamletInfo.beamletFolder(:,end) = [];  % delete last character, which is a '/' or '\'
    optSettings.beamletInfo.beamletHeaderFileName = fliplr(fileNameRev);
end

% open the prescription file if it has been specified properly
if isfield(optSettings,'optInfo') & isfield(optSettings,'prescInfo') ...
        & isfield(optSettings.optInfo,'inputFolder') & isfield(optSettings.prescInfo,'prescFile')
    
    prescFile = [optSettings.optInfo.inputFolder '/' optSettings.prescInfo.prescFile];
    fid = fopen([prescFile],'r');
    if fid == -1
        missingInfo{end+1} = ['Unable to open prescription file: ' prescFile];
    else
        % read the entire file into a cell array
        fileText = {};
        while 1
            tline = fgetl(fid);
            if ~ischar(tline)
                break;
            end
            fileText{end+1} = tline;
        end
        fclose(fid);

        if ~strcmp(deblank(fileText{1}),'Ntissue')
            error('First line of prescription file must be ''Ntissue''');
        else
            Ntissue = str2num(fileText{2});
        end

        k = 5;  % skip up to the 5th line of the file, which is the tissue number
        
        % read in the tissues
        for m=1:Ntissue  % read through the lines for the current tissue
            tissNum = str2num(fileText{k});
            k = k + 2;
            optSettings.prescInfo.presc.tissue(m).name = fileText{k};
            k = k + 2;
            optSettings.prescInfo.presc.tissue(m).alpha = str2num(fileText{k});
            k = k + 2;
            optSettings.prescInfo.presc.tissue(m).betaVPlus = str2num(fileText{k});
            k = k + 2;
            optSettings.prescInfo.presc.tissue(m).dVPlus = str2num(fileText{k});
            k = k + 2;
            optSettings.prescInfo.presc.tissue(m).vPlus = str2num(fileText{k});
            k = k + 2;
            optSettings.prescInfo.presc.tissue(m).betaVMinus = str2num(fileText{k});
            k = k + 2;
            optSettings.prescInfo.presc.tissue(m).dVMinus = str2num(fileText{k});
            k = k + 2;
            optSettings.prescInfo.presc.tissue(m).vMinus = str2num(fileText{k});
            k = k + 2;
            optSettings.prescInfo.presc.tissue(m).betaPlus = str2num(fileText{k});
            k = k + 2;
            optSettings.prescInfo.presc.tissue(m).dosePlusFileName = fileText{k};
            k = k + 2;
            optSettings.prescInfo.presc.tissue(m).betaMinus = str2num(fileText{k});
            k = k + 2;
            optSettings.prescInfo.presc.tissue(m).doseMinusFileName = fileText{k};

            % load-in the dPlus inforomation
            fid = fopen(optSettings.prescInfo.presc.tissue(m).dosePlusFileName,'rb');
            siz = fread(fid,3,'int');  % size of the sparse array
            Nind = fread(fid,1,'int');
            ind = fread(fid,Nind,'int=>int');
            dat = fread(fid,Nind,'float=>float');
            fclose(fid);
            optSettings.prescInfo.presc.tissue(m).ind = ind + 1;
            optSettings.prescInfo.presc.tissue(m).dPlus = dat;

            % load-in the dMinus inforomation
            fid = fopen(optSettings.prescInfo.presc.tissue(m).doseMinusFileName,'rb');
            siz = fread(fid,3,'int')';  % size of the sparse array
            Nind = fread(fid,1,'int');
            ind = fread(fid,Nind,'int=>int');
            dat = fread(fid,Nind,'float=>float');
            fclose(fid);
            optSettings.prescInfo.presc.tissue(m).ind = ind + 1;
            optSettings.prescInfo.presc.tissue(m).dMinus = dat;

            k = k + 3;  % skip up to the next tissueNum value field
        end
        optSettings.prescInfo.presc.siz = siz;  % size of all of the dose grid
    end
end

% read in the initial guess information
if isfield(optSettings,'initialGuessInfo') & isfield(optSettings.initialGuessInfo,'initBeamWeightFile') ...
        & isfield(optSettings,'optInfo') & isfield(optSettings.optInfo,'inputFolder')
    if ~isfield(optSettings.initialGuessInfo,'calcInitialGuessFlag') ...
        || (isfield(optSettings.initialGuessInfo,'calcInitialGuessFlag') & optSettings.initialGuessInfo.calcInitialGuessFlag == 0)
        fid = fopen([optimizerFolder '/' optSettings.optInfo.inputFolder '/' optSettings.initialGuessInfo.initBeamWeightFile]);
        if fid == -1
            missingInfo{end+1} = ['Unable to open initial guess file for beam weights: ' optSettings.initialGuessInfo.initBeamWeightFile];
        else
            optSettings.initialGuessInfo.w0 = fread(fid,'float');
            fclose(fid);
        end
    end
end

% read in the beamlet file and folder information
if isfield(optSettings,'beamletInfo') & isfield(optSettings.beamletInfo,'beamletFolder') ...
        & isfield(optSettings.beamletInfo,'beamletFolder')

    beamletHeaderFile = [optSettings.beamletInfo.beamletFolder '/' optSettings.beamletInfo.beamletHeaderFileName];
    fid = fopen(beamletHeaderFile,'r');
    if fid == -1
        missingInfo{end+1} = ['Unable to open beamlet header file: ' beamletHeaderFile];
    else
        % read the file into a cell array, line-by-line
        fileText = {};
        while 1
            tline = fgetl(fid);
            if ~ischar(tline)
                break;
            end
            fileText{end+1} = tline;
        end
        fclose(fid);

        fieldFunctions = { ...
            'beamletDim'            'beamletInfo'       'str2num'         
            'Nbeamlets'             'beamletInfo'       'str2num'                  
            'Nbeamletbatches'       'beamletInfo'       'str2num'                  
            'beamletFolder'         'beamletInfo'       ''                   
            'beamletBatchBaseName'  'beamletInfo'       ''                   
            'beamletBatchExtension' 'beamletInfo'       '' };

        % search for key fields
        for k=1:length(fileText)
            for m=1:size(fieldFunctions,1)
                if strcmp(deblank(fileText{k}),fieldFunctions{m,1})
                    eval(['optSettings.' fieldFunctions{m,2} '.' fieldFunctions{m,1} ' = ' fieldFunctions{m,3} '(''' fileText{k+1} ''');']);
                end
            end
        end

        % search for missing fields
        for k=1:size(fieldFunctions,1)
            if ~isfield(optSettings,fieldFunctions{k,2}) | ~eval(['isfield(optSettings.' fieldFunctions{k,2} ',''' fieldFunctions{k,1} ''')'])
                missingInfo{end+1} = ['Missing: optSettings.' fieldFunctions{k,2} '.' fieldFunctions{k,1}];
            end
        end
    end
end
