function md=solve(md,solutionenum,varargin)
%SOLVE - apply solution sequence for this model
%
%   Usage:
%      md=solve(md,solutionenum,varargin)
%      where varargin is a lit of paired arguments of string OR enums
%
%   solution types available comprise:
%		 - StressbalanceSolutionEnum
%		 - MasstransportSolutionEnum
%		 - ThermalSolutionEnum
%		 - SteadystateSolutionEnum
%		 - TransientSolutionEnum
%		 - BalancethicknessSolutionEnum
%		 - BedSlopeSolutionEnum
%		 - SurfaceSlopeSolutionEnum
%		 - HydrologySolutionEnum
%		 - FlaimSolutionEnum
%
%  extra options:
%      - loadonly    : does not solve. only load results
%      - runtimename : true or false (default is true), makes name unique
%      - checkconsistency : 'yes' or 'no' (default is 'yes'), ensures checks on consistency of model
%
%   Examples:
%      md=solve(md,StressbalanceSolutionEnum);

%recover and process solve options
if ~strncmp(fliplr(EnumToString(solutionenum)),fliplr('Solution'),8),
	error(['solutionenum ' EnumToString(solutionenum) ' not supported!']);
end
options=pairoptions(varargin{:},'solutionenum',solutionenum);

%recover some fields
md.private.solution=solutionenum;
cluster=md.cluster;

%check model consistency
if strcmpi(getfieldvalue(options,'checkconsistency','yes'),'yes'),
	if md.verbose.solution,
		disp('checking model consistency');
	end
	if (solutionenum == FlaimSolutionEnum())
		md.private.isconsistent=true;
		md=checkconsistency(md.mesh,md,solutionenum);
		md=checkconsistency(md.flaim,md,solutionenum);
		if md.private.isconsistent==false,
			error('Model not consistent, see messages above');
		end
	else
		ismodelselfconsistent(md),
	end
end

%First, build a runtime name that is unique
if getfieldvalue(options,'runtimename',true),
	c=clock;
	md.private.runtimename=sprintf('%s-%02i-%02i-%04i-%02i-%02i-%02i-%i',md.miscellaneous.name,c(2),c(3),c(1),c(4),c(5),floor(c(6)),feature('GetPid'));
else
	md.private.runtimename=md.miscellaneous.name;
end

%if running qmu analysis, some preprocessing of dakota files using models
%fields needs to be carried out. 
if md.qmu.isdakota,
	md=preqmu(md,options);
end

%flaim analysis (To be removed?)
if (solutionenum == FlaimSolutionEnum())
	%fmdir     = getfieldvalue(options,'fmdir',['fm' num2str(feature('GetPid'))]);
	%overwrite = getfieldvalue(options,'overwrite','n');
	%keep      = getfieldvalue(options,'keep','y');
	%latsgn    = getfieldvalue(options,'latsgn',0);
	%cmap      = getfieldvalue(options,'cmap',[]);
	md=flaim_sol(md,options);
	md.private.solution=EnumToString(solutionenum);
	return;
end

%Do we load results only?
if getfieldvalue(options,'loadonly',false),
	md=loadresultsfromcluster(md);
	return;
end

%Write all input files
marshall(md);                                          % bin file
ToolkitsFile(md.toolkits,[md.miscellaneous.name '.toolkits']); % toolkits file
BuildQueueScript(cluster,md.private.runtimename,md.miscellaneous.name,md.private.solution,md.settings.io_gather,md.debug.valgrind,md.debug.gprof); % queue file

%Stop here if batch mode
if strcmpi(getfieldvalue(options,'batch','no'),'yes')
	if md.verbose.solution,
		disp('batch mode requested: not launching job interactively');
		disp('launch solution sequence on remote cluster by hand');
	end
	return;
end

%Launch job
modelname = md.miscellaneous.name;
filelist  = {[modelname '.bin '] [modelname '.toolkits ']};
if ispc,
	filelist{end+1}=[modelname '.bat '];
else
	filelist{end+1}=[modelname '.queue '];
end

if md.qmu.isdakota,
	filelist{end+1} = [modelname '.qmu.in'];
end
LaunchQueueJob(cluster,md.miscellaneous.name,md.private.runtimename,filelist);

%wait on lock
if isnan(md.settings.waitonlock),
	%load when user enters 'y'
	disp('solution launched on remote cluster. log in to detect job completion.');
	choice=input('Is the job successfully completed? (y/n)','s');
	if ~strcmp(choice,'y'), 
		disp('Results not loaded... exiting'); 
	else
		md=loadresultsfromcluster(md);
	end
elseif md.settings.waitonlock>0,
	%we wait for the done file
	done=waitonlock(md);
	if md.verbose.solution,
		disp('loading results from cluster');
	end
	md=loadresultsfromcluster(md);
elseif md.settings.waitonlock==0,
	 disp('Model results must be loaded manually with md=loadresultsfromcluster(md);');
end

%post processes qmu results if necessary
if md.qmu.isdakota,
	if ~strncmpi(getfieldvalue(options,'keep','y'),'y',1)
		system(['rm -rf qmu' num2str(feature('GetPid'))]);
	end
end
