function []=dakota_m_write(method,dmeth,dvar,dresp,params,filem,package,varargin)
%DAKOTA_M_WRITE - Write a Matlab .m function file to be called by Dakota for 
% the MATLAB direct or external driver.
%
%   Usage:
%      []=dakota_m_write(method,dmeth,dvar,dresp,params,filem,package,varargin)
%
%   where the required input is,
%      method        (character, Dakota method name)
%      dmeth         (dakota_method, method class object)
%      dvar          (structure array, variable class objects)
%      dresp         (structure array, response class objects)
%      params        (structure array, method-independent parameters)
%      filem         (character, name of .m file)
%      package       (character, analysis package)
%
%   The method, dmeth, and filem will be prompted for if empty. params may be 
%   empty, in which case defaults will be used.
%
%   The optional varargin are passed directly through to the QmuUpdateFunctions 
%   brancher to be used by the analysis package. For example, this could be 
%   model information.
%
%   This function writes a MATLAB .m function file to be called by Dakota for 
%   the MATLAB direct or external driver. For the direct driver, Dakota is 
%   linked with MATLAB and automatically starts a MATLAB session, passing the 
%   variables and responses through the function; for the external driver,
%   Dakota calls a shell script to start the MATLAB session, passing the 
%   variables and responses through text files. This function must be tailored 
%   to the particular analysis package.
%
%   This data would typically be generated by a MATLAB script for a specific 
%   model, using the method, variable, and response class objects. This 
%   function may be called by dakota_in_data.
%
%   "Copyright 2009, by the California Institute of Technology. ALL RIGHTS 
%   RESERVED. United States Government Sponsorship acknowledged. Any commercial 
%   use must be negotiated with the Office of Technology Transfer at the 
%   California Institute of Technology. (NTR 47078)
%
%   This software may be subject to U.S. export control laws. By accepting this 
%   software, the user agrees to comply with all applicable U.S. export laws 
%   and regulations. User has the responsibility to obtain export licenses, or 
%   other export authority as may be required before exporting such information 
%   to foreign countries or providing access to foreign persons."
%
if ~nargin
    help dakota_m_write
    return
end

%  process the input parameters

if ~exist('method','var') || isempty(method)
    method=input('Method?  ','s');
end

if ~exist('dmeth' ,'var') || isempty(dmeth)
    dmeth=dakota_method(method);
end

if ~exist('params','var')
    params=[];
end

if ~exist('filem' ,'var') || isempty(filem)
    filem=input('Matlab m-file to write?  ','s');
end
[pathstr,name,ext,versn] = fileparts(filem);
if isempty(ext)
    ext='.m';
end
filem2=fullfile(pathstr,[name ext versn]);

display(sprintf('Opening Matlab m-file ''%s''',filem2));
fidm=fopen(sprintf('%s',filem2),'w');
if (fidm < 0)
    error('''%s'' could not be opened',filem2);
end

%  write beginning of the Matlab m-file

begin_write(fidm,name,params);

%  write variables into the Matlab m-file

variables_write(fidm,dmeth,dvar,params,varargin{:});

%  write solution into the Matlab m-file

solution_write(fidm,package);

%  write responses into the Matlab m-file

responses_write(fidm,dmeth,params,dresp);

%  write end of the Matlab m-file

end_write(fidm,name,params);

fclose(fidm);
display('End of file successfully written');

end

%%  function to write beginning of the Matlab m-file

function []=begin_write(fidm,name,params)

display('Writing beginning of Matlab m-file');

fprintf(fidm,'%%\n');
if strcmpi(params.analysis_driver,'matlab')
    fprintf(fidm,'%%  Run the specified input variables and return the output responses.\n');
    fprintf(fidm,'%%\n');
    fprintf(fidm,'function Dakota=%s(Dakota)\n\n',name);
    fprintf(fidm,'clk=clock;\n');
    fprintf(fidm,'cpu=cputime;\n\n');
    fprintf(fidm,'%% Dakota\n\n');
    fprintf(fidm,'infile=''%s'';\n','Qmu.model');
else
    fprintf(fidm,'%%  Run the specified input file and return the output file.\n');
    fprintf(fidm,'%%\n');
    fprintf(fidm,'function %s(infile,outfile)\n\n',name);
    fprintf(fidm,'clk=clock;\n');
    fprintf(fidm,'cpu=cputime;\n\n');
end
fprintf(fidm,'try\n');
fprintf(fidm,'\tloadmodel(infile);\n\n');

if strcmpi(params.analysis_driver,'matlab')
	fprintf(fidm,'\tmd=qmuname(md,Dakota.fnEvalId);\n\n');
else
	fprintf(fidm,'\tmd=qmuname(md);\n\n');
end

end

%%  function to write variables into the Matlab m-file

function []=variables_write(fidm,dmeth,dvar,params,varargin)

display('Writing variables for Matlab m-file');

fprintf(fidm,'%%  Apply the variables.\n\n');
ixc=0;

%  variables vary by method

ixc=vsets_write(fidm,ixc,dvar,dmeth.variables,params,varargin{:});

end

%%  function to write variable sets into the Matlab m-file

function [ixc]=vsets_write(fidm,ixc,dvar,variables,params,varargin)

for i=1:length(variables)
    if isfield(dvar,variables{i})
        ixc=vlist_write(fidm,ixc,variables{i},dvar.(variables{i}),params,varargin{:});
    end
end

end

%%  function to write variable list into the Matlab m-file

function [ixc]=vlist_write(fidm,ixc,vtype,dvar,params,varargin)

disp(sprintf('  Writing %d %s variables',length(dvar),class(dvar)));

for i=1:length(dvar)

	%first find descriptor, without sample number on it.
	descriptor=discardnum(dvar(i).descriptor);

	%is there a lock on this variable? We don't want to update the variable twice!
	if exist([descriptor '_lock'],'var'),
		%lock is in place, do not update! continue;
		continue;
	else
		%first things first, put lock in place
		eval([descriptor '_lock=1;']);

		%now, we need a string to put in the matlab file, which will update all the variables 
		%for  this descriptor.
		[string,ixc]=QmuUpdateFunctions(ixc,descriptor,dvar,params,i,varargin{:});

		%dump this string in the matlab file.
        fprintf(fidm,'%s',string);
	end
end

end

%%  function to write solution into the Matlab m-file

function []=solution_write(fidm,package)

display('Writing solution for Matlab m-file');
fprintf(fidm,'%%  Run the solution.\n\n');

fprintf(fidm,['\tmd=solve(md,''stressbalance'',''' package ''');\n\n']);

end

%%  function to write responses into the Matlab m-file

function []=responses_write(fidm,dmeth,params,dresp)

display('Writing responses for Matlab m-file');

fprintf(fidm,'%%  Calculate the responses.\n\n');
ifnvals=0;

if ~strcmpi(params.analysis_driver,'matlab')
    fprintf(fidm,'\tfid=fopen(outfile,''w'');\n\n');
end

%  responses vary by method

ifnvals=rsets_write(fidm,ifnvals,params,dresp,dmeth.responses);

fprintf(fidm,'\n');
if ~strcmpi(params.analysis_driver,'matlab')
    fprintf(fidm,'\tstatus=fclose(fid);\n\n');
end

end

%%  function to write response sets into the Matlab m-file

function [ifnvals]=rsets_write(fidm,ifnvals,params,dresp,responses)

for i=1:length(responses)
    if isfield(dresp,responses{i})
        ifnvals=rlist_write(fidm,ifnvals,params,responses{i},dresp.(responses{i}));
    end
end

end

%%  function to write response list into the Matlab m-file

function [ifnvals]=rlist_write(fidm,ifnvals,params,rtype,dresp)

disp(sprintf('  Writing %d %s responses',length(dresp),class(dresp)));
for i=1:length(dresp)
    ifnvals=ifnvals+1;
    if strcmpi(params.analysis_driver,'matlab')
        fprintf(fidm,'\tDakota.fnVals(%d)=QmuResponseValue(md,''%s'');\n',ifnvals,dresp(i).descriptor);
    else
        fprintf(fidm,'\tfprintf(fid,''%%f\\n'',QmuResponseValue(md,''%s''));\n',dresp(i).descriptor);
    end
end

end

%%  function to write end of the Matlab m-file

function []=end_write(fidm,name,params)

display('Writing end of Matlab m-file');

fprintf(fidm,'%%  Error condition.\n\n');

fprintf(fidm,'catch ME\n');
fprintf(fidm,'\tME\n');
fprintf(fidm,'\tfor i=1:length(ME.stack)\n');
fprintf(fidm,'\t\tdisplay(sprintf(''    file(%%d): %%s'',  i,ME.stack(i).file));\n');
fprintf(fidm,'\t\tdisplay(sprintf(''    name(%%d): %%s'',  i,ME.stack(i).name));\n');
fprintf(fidm,'\t\tdisplay(sprintf(''    line(%%d): %%d\\n'',i,ME.stack(i).line));\n');
fprintf(fidm,'\tend\n');
if strcmpi(params.analysis_driver,'matlab')
    fprintf(fidm,'\tDakota.failure=1;\n');
else
    fprintf(fidm,'\tif exist(''fid'',''var'')\n');
    fprintf(fidm,'\t\tstatus=fclose(fid);\n');
    fprintf(fidm,'\tend\n');
    fprintf(fidm,'\tfid=fopen(outfile,''w'');\n');
    fprintf(fidm,'\tfprintf(fid,''fail\\n'');\n');
    fprintf(fidm,'\tstatus=fclose(fid);\n');
end
fprintf(fidm,'end\n\n');

fprintf(fidm,'disp(sprintf(''%s -- %%f CPU seconds; %%f clock seconds\\n'',...\n',name);
fprintf(fidm,'    cputime-cpu,etime(clock,clk)))\n\n');
fprintf(fidm,'end\n\n');

end
