function [status,theta,thetaIndex,thetaDist,LowerBound,ModelParameters,thetaPositions,PriorDist,ParameterNames,UniformBounds] = VerifyPriorData(DSGEModel,CurrINI)
% VerifyPriorData: Verifies if the data in the file with the prior distribution specification is valid. If so, it returns
%                   information about the prior.
%
% USAGE:
%
%       [status,theta,ModelParameters,thetaPositions,PriorDist,ParameterNames] = VerifyPriorData(DSGEModel,CurrINI)
%
% REQUIRED INPUT:  DSGEModel (structure) with the fields required to locate the file (and sheet) with information about the
%                            prior distributions of the various parameters.
%
%                  CurrINI (structure), with initialization information.
%
% REQUIRED OUTPUT: status (boolean) is 1 if the prior can be used by YADA, and 0 otherwise.
%
%                  theta (vector) with all parameters to be estimated
%
%                  thetaIndex (vector) with integers where 1=gamma, invgamma, truncnormal 2=beta, 3=uniform, and 0=normal.
%                             This is used to determine the type of transformation that may need to be performed for the
%                             theta parameters.
%
%                  thetaDist (vector) with integers 1 if gamma, 2 if beta, 3 if normal, 4 if invgamma, 5 if
%                             truncnormal, and 6 if uniform.
%
%                  LowerBound (vector) with lower bound values for the theta vector.
%
%                  ModelParameters (structure) with fields having the names of the inidividual parameters as they are
%                             specified under the "model parameter" header in the file with prior distribution data,
%                             and having values as specified under the header "initial value" in the same file
%
%                  thetaPositions (structure) where thetaPositions(i).parameter is a string vector giving the name
%                             of the model parameter in position i of theta.
%
%                  PriorDist (structure) with fields "beta", "gamma", "normal", "invgamma", "truncnormal", and "uniform" where
%                             the values are matrices with the parameter values for the distributions. In the case of
%                             the normal, beta, and gamma these parameter values are the mean and the standard deviation.
%                             For the invgamma it is the s and q parameters, where q is a positive integer (degrees of
%                             freedom). Finally, for the left truncated normal there's a third parameter, the lower bound.
%
%                  ParameterNames (structure) with fields "calibrated", "beta", "gamma", "normal", "invgamma", "truncnormal",
%                             "uniform", "all" and "estimated". Each field returns a string matrix with the parameter names.
%
%                  UniformBounds (matrix) with the same number of rows as parameters and 2 columns. The columns are 0 1 except
%                             for the uniform and the beta distribution, where they represent the upper and lower bounds.
%
%
%                       Written by: Anders Warne
%                                   New Area Wide Model Project
%                                   DG-R/EMO
%                                   European Central Bank (ECB)
%                                   Email: anders.warne@ecb.europa.eu
%                                   Copyright © 2006-2008 European Central Bank.
%
%                       First version: August 4, 2006.
%                        This version: December 19, 2008.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% LICENSE INFORMATION:
%
%      YADA is free software: you can redistribute it and/or modify
%      it under the terms of the GNU General Public License as published by
%      the Free Software Foundation, either version 3 of the License, or
%      (at your option) any later version.
%
%      This program is distributed in the hope that it will be useful,
%      but WITHOUT ANY WARRANTY; without even the implied warranty of
%      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%      GNU General Public License for more details.
%
%      You should have received a copy of the GNU General Public License
%      along with this program.  If not, see <http://www.gnu.org/licenses/>.
%
%      YADA is released under the GNU General Public License, Version 3,
%      29 June 2007 <http://www.gnu.org/licenses/>. The current release of
%      the program was last modified by the ECB on the "This version" date
%      above.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% CHANGELOG:
%
% * 7-8-2006:   Added the thetaIndex and LowerBound vector outputs, as well as the ParameterNames and
%               InitialValues structures. The documentation was also updated.
%
% * 8-8-2006:   Added the thetaDist output vector for quick mapping from theta into the parts that belong
%               to the different prior distributions.
%
% * 11-8-2006:  Added the "all" and "estimated" fields to the ParameterNames structure.
%
% * 16-8-2006:  Made sure that the initial values are valid for the different prior distributions.
%
% * 18-8-2006:  Changed the StrTrim function to StringStrim.
%
% * 24-8-2006:  Removed the output "InitialValues" since it is not used by YADA.
%
% * 25-8-2006:  Added information collection and verification for the uniform distribution.
%
% * 28-8-2006:  Made sure that the initial value is within the upper and lower bound of the uniform prior
%               distribution.
%
% * 21-9-2006:  Fixed a bug when data was entered into the PriorDist.normal matrix. (The function erroneously
%               used the matrix PriorDist.invgamma as a base for each new parameter).
%
% * 13-11-2007: Updated the documentation.
%
% * 23-5-2008:  Updated the documentation.
%
% * 2-7-2008:   Added parameter name and other data to the error information text.
%
% * 21-7-2008:  The gamma and invgamma priors can now have a non-zero lower bound.
%
% * 23-7-2008:  The function now looks for the optional header "upper bound". Only used by the beta prior. These
%               upper and lower bounds default to 0 and 1. Added code to support a general beta prior.
%
% * 18-12-2008: Updated the documentation.
%
% * 19-12-2008: Added the check for the existence of the prior file.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%

%
% initialize the outputs
%
status = 0;
theta = [];
thetaIndex = [];
thetaDist = [];
LowerBound = [];
ModelParameters = [];
thetaPositions = [];
PriorDist = [];
UniformBounds = [];
ParameterNames.calibrated = '';
ParameterNames.beta = '';
ParameterNames.gamma = '';
ParameterNames.normal = '';
ParameterNames.invgamma = '';
ParameterNames.truncnormal = '';
ParameterNames.uniform = '';
ParameterNames.all = '';
ParameterNames.estimated = '';
if FileExist(DSGEModel.PriorFile)==0;
   return;
end;
%
% Determine the file type
%
if strcmp(GetExt(DSGEModel.PriorFile),'.wk1')==1;
   %
   % Check the integrity of the Lotus 1-2-3 spreadsheet
   %
   [fok,chk] = wk1finfo(DSGEModel.PriorFile);
   if isempty(fok)==1;
      txt = ['The Lotus 1-2-3 spreadsheet you selected "' GetFilename(DSGEModel.PriorFile) '" cannot be read by YADA. Please select another file.'];
      About(txt,'information','Bad Lotus Spreadsheet',120,500,CurrINI);
      return;
   end;
   %
   % The file can be read. Now we try to read it.
   %
   [PriorData,PriorText] = wk1read(DSGEModel.PriorFile);
   [w1,w2] = size(PriorText);
   if w2>size(PriorData,2);
      PriorData = [PriorData zeros(size(PriorData,1),w2-size(PriorData,2))];
   end;
   for i=1:w1;
      TitleText = '';
      for j=1:w2;
         TitleText = strvcat(TitleText,PriorText{i,j});
      end;
      if isempty(TitleText)==0;
         StartRow = i;
         break;
      end;
   end;
   if isempty(TitleText)==1;
      %
      % no text informations whatsoever
      %
      txt = ['The Lotus 1-2-3 spreadsheet you selected "' GetFilename(DSGEModel.PriorFile) '" doesn''t contain any text. This file is therefore not a proper prior distribution file.'];
      About(txt,'information','Bad Lotus Spreadsheet',120,500,CurrINI);
      return;
   end;
   FileType = 'Lotus 1-2-3';
else;
   %
   % Tt's an Excel spreadsheet. Check its integrity
   %
   [fok,sheets] = xlsfinfo(DSGEModel.PriorFile);
   if isempty(fok)==1;
      txt = ['The Excel spreadsheet you selected "' GetFilename(DSGEModel.PriorFile) '" cannot be read by YADA. Please select another file.'];
      About(txt,'information','Bad Excel Spreadsheet',120,500,CurrINI);
      return;
   end;
   %
   % check if DSGEModel.PriorFileSheet is located among sheets!
   %
   sheets = char(sheets);
   pos = LocateStr(sheets,DSGEModel.PriorFileSheet);
   if pos==0;
      txt = ['The Excel spreadsheet "' GetFilename(DSGEModel.PriorFile) '" doesn''t have a sheet called "' DSGEModel.PriorFileSheet '". Please correct your selected sheet.'];
      About(txt,'information','Invalid Excel Spreadsheet Information',120,500,CurrINI);
      return;
   end;
   %
   % The file can be read. Now we try to read it.
   %
   [Data,PriorText,RawPriorData] = xlsread(DSGEModel.PriorFile,DSGEModel.PriorFileSheet);
   [w1,w2] = size(PriorText);
   %
   % User RawPriorData to create the matrix PriorData with the same information as PriorData
   % from reading a wk1-file.
   %
   [r,c] = size(RawPriorData);
   PriorData = zeros(r,c);
   for i=1:r;
      for j=1:c;
         if ischar(RawPriorData{i,j})==0;
            PriorData(i,j) = cell2mat(RawPriorData(i,j));
         end;
      end;
   end;
   for i=1:w1;
      TitleText = '';
      for j=1:w2;
         TitleText = strvcat(TitleText,PriorText{i,j});
      end;
      if isempty(TitleText)==0;
         StartRow = i;
         break;
      end;
   end;
   if isempty(TitleText)==1;
      %
      % no text informations whatsoever
      %
      txt = ['The Excel spreadsheet you selected "' GetFilename(DSGEModel.PriorFile) '" with sheet "' DSGEModel.PriorFileSheet '" doesn''t contain any text. This file is therefore not a proper prior distribution file.'];
      About(txt,'information','Bad Excel Spreadsheet',120,500,CurrINI);
      return;
   end;
   FileType = 'Excel';
end;
%
% remove any leading and trailing spaces from TitleText
%
NewTitleText = '';
for i=1:size(TitleText,1);
   NewTitleText = strvcat(NewTitleText,StringTrim(TitleText(i,:)));
end;
TitleText = NewTitleText;
%
% check if we can locate the positions of the headers
%
PriorPositions = zeros(1,8);
PriorPositions(1,1) = LocateStr(TitleText,'model parameter',0);
PriorPositions(1,2) = LocateStr(TitleText,'status',0);
PriorPositions(1,3) = LocateStr(TitleText,'initial value',0);
PriorPositions(1,4) = LocateStr(TitleText,'prior type',0);
PriorPositions(1,5) = LocateStr(TitleText,'prior parameter 1',0);
PriorPositions(1,6) = LocateStr(TitleText,'prior parameter 2',0);
PriorPositions(1,7) = LocateStr(TitleText,'lower bound',0);
PriorPositions(1,8) = LocateStr(TitleText,'upper bound',0);
%
% check if there are missing headers
%
if min(PriorPositions(1:7))==0;
   txt = ['The ' FileType ' spreadsheet you''ve selected for providing the prior distribution data has missing column headers. The required column headers are: "Model parameters", "Status", "Initial value", "Prior type", "Prior parameter 1", "Prior parameter 2", and "Lower bound" (without the quotation characters). The ordering of these headers is unimportant as is the case used (upper, lower, or any mixture).'];
   About(txt,'information','Missing Column Headers',160,500,CurrINI);
   return;
end;
%
% all header are present, now we try to set up the data
%
ModelParameters = [];
ParamValueExist = 1;
ValidStatus = 1;
ValidDist = 1;
ValidParameters = 1;
num = 1;
PriorDist.beta = [];
PriorDist.gamma = [];
PriorDist.invgamma = [];
PriorDist.normal = [];
PriorDist.truncnormal = [];
PriorDist.uniform = [];
%
for i=1+StartRow:w1;
   %
   % parameter name
   %
   CurrParameter = PriorText{i,PriorPositions(1,1)};
   %
   % check initial values
   %
   if (isnumeric(PriorData(i,PriorPositions(1,3)))==1)&(isempty(PriorData(i,PriorPositions(1,3)))==0);
      ModelParameters = setfield(ModelParameters,PriorText{i,PriorPositions(1,1)},PriorData(i,PriorPositions(1,3)));
      ParameterNames.all = strvcat(ParameterNames.all,PriorText{i,PriorPositions(1,1)});
   else;
      ParamValueExist = 0;
      break;
   end;
   %
   % check the status
   %
   StatusStr = PriorText{i,PriorPositions(1,2)};
   if (isempty(StatusStr)==1)|(length(StatusStr)<2)|(ischar(StatusStr)==0);
      ValidStatus = 0;
      break;
   end;
   StatusStr = StringTrim(StatusStr);
   if (strcmp(lower(StatusStr(1,1:2)),'es')==0)&(strcmp(lower(StatusStr(1,1:2)),'ca')==0);
      ValidStatus = 0;
      break;
   end;
   %
   % Add the parameter to theta if it should be estimated and if so map its name to the position in theta
   % through the structure thetaPositions. This structure has the feature that if theta(2) = ModelParameters.gamma
   % then, thetaPositions(2).parameter = 'gamma'. Hence, when updating ModelParameters we simply use the
   % command:
   %
   %            ModelParameters = setfield(ModelParameters,thetaPositions(i).parameter,theta(i))
   %
   if strcmp(lower(StatusStr(1,1:2)),'es')==1;
      theta = [theta;PriorData(i,PriorPositions(1,3))];
      ParameterNames.estimated = strvcat(ParameterNames.estimated,PriorText{i,PriorPositions(1,1)});
      thetaPositions(num).parameter = PriorText{i,PriorPositions(1,1)};
      %
      % check if the claimed distribution is valid
      %
      DistStr = PriorText{i,PriorPositions(1,4)};
      if (isempty(DistStr)==1)|(length(DistStr)<2)|(ischar(DistStr)==0);
         ValidDist = 0;
         break;
      end;
      %
      DistStr = lower(StringTrim(DistStr));
      if (strcmp(DistStr,'beta')==0)&(strcmp(DistStr,'gamma')==0)&(strcmp(DistStr,'invgamma')==0)&(strcmp(DistStr,'normal')==0)&(strcmp(DistStr,'truncnormal')==0)&(strcmp(DistStr,'uniform')==0);
         ValidDist = 0;
         break
      end;
      %
      % we have a valid distribution
      %
      num = num+1;
      %
      % Now we check the prior parameter 1 and prior parameter 2 entries
      %
      Parameter1 = PriorData(i,PriorPositions(1,5));
      Parameter2 = PriorData(i,PriorPositions(1,6));
      Parameter3 = PriorData(i,PriorPositions(1,7));
      if PriorPositions(1,8)>0;
         Parameter4 = PriorData(i,PriorPositions(1,8));
      else;
         Parameter4 = [];
      end;
      if (isnumeric(Parameter1)==1)&(isempty(Parameter1)==0)&(isnan(Parameter1)==0)&(isnumeric(Parameter2)==1)&(isempty(Parameter2)==0)&(isnan(Parameter2)==0);
         %
         % check the distribution type
         %
         if strcmp(DistStr,'beta')==1;
            if Parameter2>0;
               ParameterNames.beta = strvcat(ParameterNames.beta,PriorText{i,PriorPositions(1,1)});
               thetaIndex = [thetaIndex;2];
               thetaDist = [thetaDist;2];
               if isempty(Parameter4)==0;
                  %
                  % check the upper and lower bounds
                  %
                  if (isnumeric(Parameter3)==1)&(isempty(Parameter3)==0)&(isnan(Parameter3)==0)&(isnumeric(Parameter4)==1)&(isnan(Parameter4)==0)&(Parameter4>Parameter3)&(Parameter1>Parameter3)&(Parameter1<Parameter4)&(PriorData(i,PriorPositions(1,3))>Parameter3)&(PriorData(i,PriorPositions(1,3))<Parameter4);
                     UniformBounds = [UniformBounds;Parameter3 Parameter4];
                     PriorDist.beta = [PriorDist.beta;Parameter1 Parameter2 Parameter3 Parameter4];
                     LowerBound = [LowerBound;Parameter3];
                  else;
                     ValidParameters = 0;
                     break;
                  end;
               else;
                  if (PriorData(i,PriorPositions(1,3))>0)&(PriorData(i,PriorPositions(1,3))<1);
                     UniformBounds = [UniformBounds;0 1];
                     PriorDist.beta = [PriorDist.beta;Parameter1 Parameter2 0 1];
                     LowerBound = [LowerBound;0];
                  else;
                     ValidParameters = 0;
                     break;
                  end;
               end;
            else;
               ValidParameters = 0;
               break;
            end;
         elseif strcmp(DistStr,'gamma')==1;
            if (isnumeric(Parameter3)==1)&(isempty(Parameter3)==0)&(isnan(Parameter3)==0)&(Parameter1>Parameter3)&(Parameter2>0)&(PriorData(i,PriorPositions(1,3))>Parameter3);
               PriorDist.gamma = [PriorDist.gamma;Parameter1 Parameter2 Parameter3];
               ParameterNames.gamma = strvcat(ParameterNames.gamma,PriorText{i,PriorPositions(1,1)});
               thetaIndex = [thetaIndex;1];
               LowerBound = [LowerBound;Parameter3];
               thetaDist = [thetaDist;1];
               UniformBounds = [UniformBounds;0 1];
            else;
               ValidParameters = 0;
               break;
            end;
         elseif strcmp(DistStr,'invgamma')==1;
            if  (isnumeric(Parameter3)==1)&(isempty(Parameter3)==0)&(isnan(Parameter3)==0)&(Parameter1>Parameter3)&(Parameter2>0)&(IsInteger(Parameter2)==1)&(PriorData(i,PriorPositions(1,3))>Parameter3);
               PriorDist.invgamma = [PriorDist.invgamma;Parameter1 Parameter2 Parameter3];
               ParameterNames.invgamma = strvcat(ParameterNames.invgamma,PriorText{i,PriorPositions(1,1)});
               thetaIndex = [thetaIndex;1];
               LowerBound = [LowerBound;Parameter3];
               thetaDist = [thetaDist;4];
               UniformBounds = [UniformBounds;0 1];
            else;
               ValidParameters = 0;
               break;
            end;
         elseif strcmp(DistStr,'normal')==1;
            if Parameter2>0;
               PriorDist.normal = [PriorDist.normal;Parameter1 Parameter2];
               ParameterNames.normal = strvcat(ParameterNames.normal,PriorText{i,PriorPositions(1,1)});
               thetaIndex = [thetaIndex;0];
               LowerBound = [LowerBound;0];
               thetaDist = [thetaDist;3];
               UniformBounds = [UniformBounds;0 1];
            else;
               ValidParameters = 0;
               break;
            end;
         elseif strcmp(DistStr,'truncnormal')==1;
            if (isnumeric(Parameter3)==1)&(isempty(Parameter3)==0)&(isnan(Parameter3)==0)&(Parameter2>0)&(PriorData(i,PriorPositions(1,3))>=Parameter3);
               PriorDist.truncnormal = [PriorDist.truncnormal;Parameter1 Parameter2 Parameter3];
               ParameterNames.truncnormal = strvcat(ParameterNames.truncnormal,PriorText{i,PriorPositions(1,1)});
               thetaIndex = [thetaIndex;1];
               LowerBound = [LowerBound;Parameter3];
               thetaDist = [thetaDist;5];
               UniformBounds = [UniformBounds;0 1];
            else;
               ValidParameters = 0;
               break;
            end;
         elseif strcmp(DistStr,'uniform')==1;
            if (Parameter2>Parameter1)&(PriorData(i,PriorPositions(1,3))>=Parameter1)&(Parameter2>=PriorData(i,PriorPositions(1,3)));
               PriorDist.uniform = [PriorDist.uniform; Parameter1 Parameter2];
               ParameterNames.uniform = strvcat(ParameterNames.uniform,PriorText{i,PriorPositions(1,1)});
               LowerBound = [LowerBound;0];
               thetaIndex = [thetaIndex;3];
               thetaDist = [thetaDist;6];
               UniformBounds = [UniformBounds;Parameter1 Parameter2];
            else;
               ValidParameters = 0;
               break;
            end;
         end;
      else;
         ValidParameters = 0;
         break;
      end;
   else;
      %
      % we have a calibrated parameter
      %
      ParameterNames.calibrated = strvcat(ParameterNames.calibrated,PriorText{i,PriorPositions(1,1)});
   end;
end;
%
% if there have been errors, display correct message and return function which called VerifyPriorData
%
if ParamValueExist==0;
   txt = ['The ' FileType ' spreadsheet you''ve selected has a missing initial value for the parameter "' CurrParameter '". YADA is therefore unable to continue.'];
   About(txt,'information','Missing Initial Values',120,500,CurrINI);
   return;
end;
%
if ValidStatus==0;
   txt = ['The ' FileType ' spreadsheet you''ve selected has a parameter, "' CurrParameter '", whose status, "' StatusStr '", is neither es(timated) or ca(librated). YADA is therefore unable to continue.'];
   About(txt,'information','Invalid Parameter Status',140,500,CurrINI);
   return;
end;
%
if ValidDist==0;
   txt = ['The ' FileType ' spreadsheet you''ve selected has a parameter, "' CurrParameter '", whose prior distribution, "' DistStr '", is not of a known type. These types are: "beta", "gamma", "invgamma", "normal", "truncnormal", and "uniform".'];
   About(txt,'information','Invalid Parameter Status',140,500,CurrINI);
   return;
end;
%
if ValidParameters==0;
   txt = ['The ' FileType ' spreadsheet you''ve selected has a parameter, "' CurrParameter '", whose initial value and/or prior parameters are not valid. YADA is therefore unable to continue.'];
   About(txt,'information','Invalid Prior Parameters',140,500,CurrINI);
   return;
end;
status = 1;

%
% end of VerifyPriorData.m
%
