function slml2img( varargin )
% SLML2IMG Synthesizes a set of multicolor digital images from a collection
% of SLML Level 1.0 Version 1.* instances.
%
% COMMENT: When the method is not deployed the shape of the input arguments is
% slml2img( models, param )
%
% List Of Input Arguments  Descriptions
% -----------------------  ------------
% models                   A cell array of filenames
% param                    A structure holding the function options
%
% The shape of param is described
%
% List Of Parameters        Descriptions
% ------------------        ------------
% targetDirectory           (optional) Directory where the images are going to be saved. Default is current directory.
% prefix                    (optional) Filename prefix for the synthesized images. Default is 'demo'
% numberOfSynthesizedImages (optional) Number of synthesized images. Default is 1.
% compression               (optional) Compression of tiff, i.e. 'none', 'lzw' and 'packbits'
% debug                     (optional) Keeps temporary results and catches errors with full reports
% display                   (optional) Display flag for figures
% verbose                   (optional) Print the intermediate steps to screen. Default is true.
% microscope                (optional) Microscope model from which we select a point spread function. Default is 'none'
% synthesis                 (optional) Synthesis parameter that allows to
% synthesize                           'nucleus', 'framework' or 'all'. Default is 'all'
% sampling.method           (optional) Can be 'disc' or 'sampled'. Default is trimmed
% sampling.method.density   (optional) An integer. Default is empty.
% protein.cytonuclearflag   (optional) Can 'cyto', 'nucleus' or 'all'. Default is all.
% resolution.cell           (optional) The resolution of the cell and nucleus that are being passed in
% resolution.objects        (optional) The resolution of the object model being synthesized
% image_size                (optional) The image size. Default is [1024 1024] for both 2D and 3D in x and y
%
% output.tifimages           (optional) boolean flag specifying whether to write out tif images
% output.indexedimage        (optional) boolean flag specifying whether to write out indexed image
% output.blenderfile         (optional) boolean flag specifying whether to write out (.obj) files for use in blender
% output.blender.downsample  (optional) downsampling fraction for the creation of object files (1 means no downsampling, 1/5 means 1/5 the size)
%
% Example
% -------
% instances = { 'model01.xml', 'model02.mat', 'model03.mat' };
% param.targetDirectory = pwd;
% param.prefix = 'demo'
% param.numberOfSynthesizedImages = 100;
% param.compression = 'lzw';
% param.microscope = 'svi';
% param.verbose = true;
%
% >> slml2img( instances, param );

% Author: Ivan E. Cao-Berg (icaoberg@cmu.edu)
% Created: May 8, 2007
% March 7, 2012 R.F.Murphy  Don't create directory to hold 3D images if
%                           generating 2D
% March 8, 2012 I. Cao-Berg Documented the method
% March 9, 2012 I. Cao-Berg Changed disp to fprintf and improved logs
% March 9, 2012 I. Cao-Berg Removed print of progress bar from log file
% March 21, 2012 I. Cao-Berg Changed protein.location to protein.cytonuclearflag
% April 11, 2012 I. Cao-Berg Removed removal of temporary folder
% June 5, 2012 M. Mackie    Added option to save as an index image using
%                           param.image.type and param.image.option
% June 6, 2012 M. Mackie	Removed parameter image.option (index images
%							may only be saved as 'priority'
% July 25, 2012 D. Sullivan Added fields param.blender.file and param.blender.downsample
%                           Created option for saving .obj files for exporting to blender
% July 26, 2012 D. Sullivan Changed param.image and param.blender structures
%                           to param.output structure (see header for usage)
% July 30, 2012 I. Cao-Berg Modified code that is res files in the temporary folder rather than
%                           the folder itself. This way if a user trains a model and synthesizes
%                           images in the same script, the temp folder remains intact in case it is
%                           run in debug mode
% August 20, 2012 I. Cao-Berg Renamed img2blender to im2blender
% October 1, 2012 I. Cao-Berg Removed deprecated code from previous versions
% October 9, 2012 I. Cao-Berg Added print of the error stack if method
% fails to synthesize an image
% January 28, 2012 I. Cao-Berg Updated try/catch statement to print an
% error report when running debug mode
% April 29, 2013 D. Sullivan added documentation for param.debug
% May 18, 2013 I . Cao-Berg Updated method so if framework fails to
% synthesize it returns an empty framework
% June 7, 2013 R. Arepally added the variable shiftvector as a parameter to
% the im2blender function. This fixes the bug of inconsistant shifting of
% different objects when the blender files are created.
%
% Copyright (C) 2007-2013 Murphy Lab
% Carnegie Mellon University
%
% This program 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 2 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, write to the Free Software
% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
% 02110-1301, USA.
%
% For additional information visit http://murphylab.web.cmu.edu or
% send email to murphy@cmu.edu

% if ~isdeployed
%     if nargin ~= 2
%         error( ['CellOrganizer: Wrong number of input arguments. If slml2img ' ...
%             ' is not deployed, then the number of input arguments must be 2.'] );
%     end
%
% end

%check if files exists and are valid SLML instances
%INPUT ARGUMENTS
param = varargin{2};

%INPUT ARGUMENTS
try
    verbose = param.verbose;
    if ~islogical( verbose )
        verbose = true;
    end
catch
    verbose = true;
end

try
    debug = param.debug;
    if ~islogical( debug )
        debug = false;
    end
catch
    debug = false;
end

%icaoberg 02/06/2013
if ~isfield( param, 'display' )
    param.display = false;
end

%icaoberg 10/9/2012
try
    synthesis = param.synthesis;
    if ~isa( synthesis, 'char' )
        synthesis = 'all';
    else
        if ~strcmpi( synthesis, 'nucleus' ) && ~strcmpi( synthesis, 'cell' ) && ...
                ~strcmpi( synthesis, 'framework' ) && ~strcmpi( synthesis, 'all' )
            synthesis = 'all';
        else
            synthesis = lower( synthesis );
        end
    end
catch
    synthesis = 'all';
end

% R. Arepally 6/7/13 shiftvector empty array is instantiated 
% so that it can be passed to im2blender. 
shiftvector = [];


%mmackie June 1st 2012
%see what type of image to return, default is tif
%dsullivan July 26 2012
%edited from try-catch to if statement and changed from
%param.image to param.output
%moved to top of program, no reason to be checking this now
if ~isfield(param,'output')
    param.output.tifimages = true;
elseif ~isfield(param.output,'tifimages') && ~isfield(param.output,'indexedimage')&& ~isfield(param.output,'blenderfile')
    error('CellOrganizer: Unsupported output specified. Supported outputs for param.output are tifimages,indexedimage, and blenderfile. ')
end

%LOGS
try
    if verbose
        disp( 'Checking existence of log folder' );
    end
    
    if ~exist( [ pwd filesep 'log'], 'dir' )
        if verbose
            disp( ['Making log directory ' pwd filesep 'log' ] );
        end
        mkdir( 'log' );
    end
    
    c = clock;
    logfile = '';
    for i=1:1:length(c)
        logfile = ['',logfile,num2str(c(i))]; %#ok<AGROW>
    end
    logfile = [ pwd filesep 'log' filesep logfile, '.log' ];
    
    fileID = fopen( logfile, 'w' );
catch err
    warning( 'CellOrganizer: Failed to create log file. Exiting program.' ) %#ok<*WNTAG>
    
    %icaoberg 1/28/2013
    if debug
        getReport( err, 'extended' );
    end
    
    if ~isdeployed
        return
    else
        exit
    end
end

filenames = varargin{1};
if verbose
    fprintf( 1, '%s%%', 'Checking the validity of input files: 0');
end

fprintf( fileID, '%s', 'Checking the validity of input files' );
for i=1:1:length(filenames)
    if ~isaFile( filenames{i} )
        if verbose
            fprintf( 1, '\n%s', ['Input argument ' filenames{i} ' is not a file'] );
        end
        
        fprintf( fileID, '\n%s', ['Input argument ' filenames{i} ' is not a file'] );
        fclose( fileID );
        
        error( ['CellOrganizer: Input argument ' i ' is not a file'] );
    else
        n=length(filenames);
        if verbose
            %indicate an object has been successfully added
            fprintf( 1, [ repmat('\b', 1, length(num2str(100*(i-1)/n))+1) '%s'], ...
                repmat(' ', 1, length(num2str(100*(i-1)/n))+1) );
            fprintf( 1, [ repmat('\b', 1, length(num2str(100*(i-1)/n))+1) '%s%%'], num2str(100*i/n) );
            pause(0.1)
        end
    end
end

%parse SLML instances into Matlab structures
if verbose
    fprintf( 1, '\n%s%%', 'Parsing SLML instances: 0' );
end

fprintf( fileID, '%s', 'Parsing SLML instances' );
try
    for j=1:1:length(filenames)
        %if it is a mat file then load directly into memory
        if( isMatFile(filenames{j}) )
            load(filenames{j});
            models{j} = model;
        else
            models{j} = slml2model( filenames{j} );
        end
        
        n=length(filenames);
        if verbose
            %indicate an object has been successfully added
            fprintf( 1, [ repmat('\b', 1, length(num2str(100*(j-1)/n))+1) '%s'], ...
                repmat(' ', 1, length(num2str(100*(j-1)/n))+1) );
            fprintf( 1, [ repmat('\b', 1, length(num2str(100*(j-1)/n))+1) '%s%%'], num2str(100*j/n) );
            pause(0.1)
        end
    end
catch err
    warning( 'CellOrganizer: Unable to parse SLML instances. Exiting program.' );
    fprintf( fileID, '%s\n', 'Unable to parse SLML instances. Exiting progam.' );
    
    %icaoberg 1/28/2013
    if debug
        getReport( err, 'extended' );
    end
    
    if verbose
        fprintf( 1, '%s\n', 'Unable to parse SLML instances. Exiting progam.' );
    end
    
    fprintf( fileID, '%s\n', 'Closing log file' );
    fclose( fileID );
    
    if ~isdeployed
        return
    else
        exit
    end
end

%TEMPORARY FOLDER
fprintf( fileID, '\n%s\n', 'Checking existence of temporary folder' );
if verbose
    fprintf( 1, '\n%s\n', 'Checking existence of temporary folder' );
end

%icaoberg 7/30/2012
if exist([pwd filesep 'temp'], 'dir' )
    fprintf( fileID, '%s\n', ['Temporary folder found in ' pwd filesep 'temp. Removing all temporary files.'] );
    if verbose
        fprintf( 1, '%s\n', ['Temporary folder found in ' pwd filesep 'temp. Removing all temporary files.'] );
    end
    %delete([pwd filesep '*.mat']);
    %rmdir([pwd filesep 'temp'], 's');
    %mkdir([pwd filesep 'temp']);
else
    fprintf( fileID, '%s\n', ['Creating temporary folder in: ' pwd filesep 'temp'] );
    if verbose
        fprintf( 1, '%s\n', ['Creating temporary folder in: ' pwd filesep 'temp'] );
    end
    mkdir([pwd filesep 'temp']);
end

%SETTING ARGUMENTS
try
    targetDirectory = param.targetDirectory;
catch err
    targetDirectory = pwd;
end

fprintf( fileID, '%s\n', ['Setting target directory to: ' targetDirectory ]  );
if verbose
    fprintf( 1, '%s\n', ['Setting target directory to: ' targetDirectory ]  );
end

%setting prefix
try
    prefix = param.prefix;
catch
    prefix = 'demo';
end

fprintf( fileID, '%s\n', ['Setting prefix to: ' prefix ]  );
if verbose
    fprintf( 1, '%s\n', ['Setting prefix to: ' prefix ]  );
end

%setting number of synthesized images
if isdeployed
    numberOfSynthesizedImages = str2double( varargin{3} );
else
    try
        numberOfSynthesizedImages =  param.numberOfSynthesizedImages;
    catch err
        numberOfSynthesizedImages = 1;
    end
end

fprintf( fileID, '%s\n', ['Setting number of synthesized images to: ' num2str(numberOfSynthesizedImages) ]  );
if verbose
    fprintf( 1, '%s\n', ['Setting number of synthesized images to: ' num2str(numberOfSynthesizedImages) ]  );
end

%setting compression
try
    compression = param.compression;
catch err
    compression = 'none';
end

fprintf( fileID, '%s\n', ['Setting compression to: ' compression ] );
if verbose
    fprintf( 1, '%s\n', ['Setting compression to: ' compression ] );
end

%synthesize multicolor images and save them to disk
for i=1:1:numberOfSynthesizedImages
    if verbose
        disp( ['Synthesizing image ' num2str(i) '. Please wait, this might take several minutes.' ] );
    end
    
    fprintf( fileID, '%s\n', ['Synthesizing image ' num2str(i) '. Please wait, this might take several minutes.' ] );
    
    %     try
    param.fileID = fileID;
    imgs = model2img( models, param );
    
    %mmackie June 1st 2012
    %see what method for determining index, default is summation
    %dsullivan July 26 2012
    %changed to param.output boolean flag structure
    if isfield(param.output,'indexedimage') && param.output.indexedimage
        mapping = 1:length(imgs);
        mapping(1) = 2;
        mapping(2) = 1;
        
        %icaoberg 8/10/2012
        imgs = ims2index(imgs,mapping);
    end
    
    if isempty( imgs )
        warning( ['CellOrganizer: Unable to synthesize image ' ...
            num2str(i) ' from the given models. Continuing synthesis.'] );
    end
%     catch err
%         %icaoberg 1/28/2013
%         getReport( err, 'extended' );
%              
%         warning( 'CellOrganizer: Unable to synthesize an image from the given models. Exiting program.' );
%         fprintf( fileID, '%s\n', 'Unable to synthesize an image from the given models. Exiting progam.' );
%         if verbose
%             disp('Closing log file.')
%         end
%         
%         fprintf( fileID, '%s\n', 'Closing log file' );
%         fclose( fileID );
%         
%         if ~exist([pwd filesep 'temp'], 'dir' )
%             rmdir([pwd filesep 'temp'],'s');
%         end
%         
%         if ~isdeployed
%             return
%         else
%             exit
%         end
%     end
    
    if strcmpi( models{1}.dimensionality, '2d' )
        temporary_file = [ pwd filesep 'temp' filesep 'image.mat' ];
        if exist( temporary_file )
            load( temporary_file );
            img2tif( imgs,[ targetDirectory filesep prefix num2str(i) ...
                '.tif'], compression );
            clear img
            delete( temporary_file );
        end
        
        %mmackie June 1st 2012
        %dsullivan July 26 2012
        %changed to boolean param.output options (can turn all on at once)
    else
        outdir = [ targetDirectory filesep prefix filesep 'cell' num2str(i) ];
        if ~exist( outdir, 'dir' )
            mkdir ( outdir )
        end
        
        %if indexed image flag is true, save as indexed image
        if isfield(param.output,'indexedimage') && param.output.indexedimage
            if verbose
                disp( 'Saving indexed image' );
            end
            
            fprintf( fileID, '%s\n', 'Saving indexed image' );
            img2tif( imgs, [ outdir filesep 'indexed.tif'], compression, true) ;
        end
        
        %icaoberg 10/9/2012 LINE 481 USED TO BE HERE

        
        %cell membrane
        if strcmpi( synthesis, 'cell' ) || strcmpi( synthesis, ...
                'framework' ) || strcmpi( synthesis, 'all' )
            load( [ pwd filesep 'temp' filesep 'image2.mat' ] );
            if isfield(param.output,'tifimages') && param.output.tifimages
                if verbose
                    disp( 'Saving cell channel tif image' );
                end
                
                fprintf( fileID, '%s\n', 'Saving cell channel tif image'  );
                
                img2tif( img, [ outdir filesep 'cell.tif'], compression );
            end
            
            %7/25/12 DPS blender files
            if isfield(param.output,'blenderfile') && param.output.blenderfile
                if verbose
                    disp( 'Saving cell channel .obj file' );
                end
                fprintf( fileID, '%s\n', 'Saving cell channel .obj file'  );
                
                %icaoberg 8/10/2012
                
                
                % Rohan Arepally 6/7/13 added [] and shiftvector to parameters
                % also shiftvector is returned by the function im2blender.
                [shiftvector, ~] = im2blender(img,[ outdir filesep 'cell.obj'],param.output.blender.downsample, ...
                [],shiftvector);
            end
            
            clear image;
        end
        
        %icaoberg 10/9/2012
        if strcmpi( synthesis, 'nucleus' ) || strcmpi( synthesis, ...
                'framework' ) || strcmpi( synthesis, 'all' )
            load( [ pwd filesep 'temp' filesep 'image1.mat' ] );
            %added conditional for synthesis option
            if isfield(param.output,'tifimages') && param.output.tifimages
                if verbose
                    disp( 'Saving nuclear channel tif image' );
                end
                
                fprintf( fileID, '%s\n', 'Saving nuclear channel tif image'  );
                img2tif( img, [ outdir filesep 'nucleus.tif'], compression );
            end
            
            %added conditional for synthesis option
            if isfield(param.output,'blenderfile')&& param.output.blenderfile
                %7/25/12 DPS blender files
                if verbose
                    disp( 'Saving nuclear channel object file' );
                end
                fprintf( fileID, '%s\n', 'Saving nuclear channel .obj file'  );
                
                %icaoberg 8/10/2012
                % Rohan Arepally 6/7/13 added [] and shiftvector to parameters
                % also shiftvector is returned by the function im2blender.
                [res, ans] = im2blender(img,[ outdir filesep 'nucleus.obj'], ...
                    param.output.blender.downsample , [], shiftvector);
                assert(res==shiftvector);
            end
            clear image;
        end
        
        %icaoberg 10/9/2012
        %will only perform this tasks if synthesis is set to all
        if strcmpi( synthesis, 'all' )
            for j=1:1:length(models)
                if ~strcmpi( models{j}.proteinShape.class, 'centrosome' )
                    load( [ pwd filesep 'temp' filesep 'image' num2str(j+2) '.mat' ] )
                    if isfield(param.output,'tifimages') && param.output.tifimages
                        if verbose
                            disp( ['Saving protein channel image ' models{j}.proteinShape.class ] );
                        end
                        fprintf( fileID, '%s\n', ['Saving protein channel image ' models{j}.proteinShape.class] );
                        
                        img2tif( img, [ outdir filesep models{j}.proteinShape.class '.tif'], compression );
                    end
                    %7/25/12 DPS blender files
                    if isfield(param.output,'blenderfile') && param.output.blenderfile
                        if verbose
                            disp( ['Saving protein channel object file ' models{j}.proteinShape.class ] );
                        end
                        % R. Arepally 6/7/13 added [] and shiftvector as
                        % parameters to im2blender. 
                        [res, ans] = im2blender(img,[ outdir filesep models{j}.proteinShape.class '.obj'],param.output.blender.downsample ...
                        ,[], shiftvector);
                        assert(res==shiftvector);
                    end
                    %7/25/12 DPS end addition
                end
            end
        end
    end
end

if ~debug
    fprintf( fileID, '%s\n', 'Removing temporary folder' );
    if verbose
        fprintf( 1, '%s\n', 'Removing temporary files' );
        delete( [ pwd filesep 'temp' filesep 'image*.mat'] );
    end
end

if verbose
    disp('Closing log file.')
end

fprintf( fileID, '%s\n', 'Closing log file' );
fclose( fileID );
