function [ nucimg, cellimg, outres, param ] = model2framework( model, param )
%MODEL2FRAMEWORK Helper method that generates a 2D/3D framework from a
%valid SLML model. The models that are currently supported are
% (1) 2D spline model of the nucleus + 2D ratio model of the cell membrane
% (2) 3D spline model of the nucleus + 3D ratio model of the cell membrane
% (3) 3D diffeomorphic model of the nucleus and cell membrane

% Author: Ivan E. Cao-Berg (icaoberg@cs.cmu.edu)
%
% Copyright (C) 2012-2014 Murphy Lab
% Lane Center for Computational Biology
% School of Computer Science
% Carnegie Mellon University
%
% April 7, 2012 R.F. Murphy Use modified function for synthesizing cell
% shape; adding additional models for height ratios and nuclear position
%
% September 28, 2012 I. Cao-Berg Added documentation and checking of input
% arguments
%
% October 1, 2012 I. Cao-Berg Added diffeomorphic model structure so that
% the method knows what to do when a model of this type is added. I also
% added a default value so that if the model type is not recognized, the
% method returns empty nuclear and cell images
%
% October 1, 2012 I. Cao-Berg Added helper method that synthesizes an
% instance from a diffeomorphic model
%
% November 1, 2012 I. Cao-Berg Added option to parameter structure that allows
% the selection between two methods when synthesizing instances from diffeomorphic
% models. This option is meant for testing, and it is not documented in top
% level methods
%
% November 5, 2012 I. Cao-Berg Fixed bug in method that synthesizes images from
% diffeomorphic models that was returning an empty image due to wrong index
%
% November 6, 2012 I. Cao-Berg Updated synthesis code to use Euler integrator
%
% January 20, 2013 T. Buck Updated method to match new options from newly
% trained diffeomorphic model
%
% February 4, 2013 D. Sullivan made file return a resolution associated
% with the cell and nuclear shapes. If there is none specified, prints a
% warning and returns the outres field as blank.
%
% February 22, 2013 D. Sullivan made the nuclear shape synthesis dependent
%                               on the object model resolution
%
% February 24, 2013 D. Sullivan Moved resolution checks to model2img
%
% March 3, 2013 D. Sullivan Added resolution outres to the 2D synthesis
%
% March 5, 2013 D. Sullivan Added check for an existing framework
%
% May 18, 2013 I. Cao-Berg Updated method so if framework fails to
% synthesize it returns an empty framework
%
% July 1, 2013 I. Cao-Berg Updated method so that when parameter.resolution
% is not present, it will inherit the resolution of the model. This will
% only happen in the 2D case where images are not downsampled
%
% April 7, 2012 R.F. Murphy Use modified function for synthesizing cell
% shape; adding additional models for height ratios and nuclear position
%
% June 25, 2013 R.F. Murphy Added param.spherical_cell
%
% March 17, 2014 I. Cao-Berg Updated the model type for 3D vesicular
% models. It used to be 'medial axis' and it should have been 'major axis'
%
% April 20, 2015 I. Cao-Berg Fixed bug in method that would query a field
% even if field was not present in structure.
%
% 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 nargin > 2
    error('Wrong number of input arguments.' );
end

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

%icaoberg 10/1/2012
param = ml_initparam( param, struct( ...
    'debug', false, ...
    'display', false, ...
    'verbose', false ...
    ));

%icaoberg 7/1/2013
if length(model) > 1 || ( isa( model, 'cell' ) && length(model) == 1 )
    %icaoberg 9/28/2012
    if param.verbose && param.debug
        warning(['More than one model has been found. Synthesizing framework ' ...
            ' from the first model in the cell array']);
    end
    model = model{1};
end

%yajing 7/2/2013 Added field spherical_cell from bob's update
param = ml_initparam( param, struct( 'spherical_cell', false ) );
try
    dimensionality = model.dimensionality;
catch
    %icaoberg 9/28/2012
    disp( 'Unable to set dimensionality. Exiting method' );
    nucimg = [];
    cellimg = [];
    outres = [];
    return
end

%icaoberg 7/1/2013
if ~isfield( param, 'synthesis' ) | ...
        ( ~strcmpi( param.synthesis, 'all' ) && ...
        ~strcmpi( param.synthesis, 'framework' ) && ...
        ~strcmpi( param.synthesis, 'nucleus' ) )
    disp( 'Unrecognized synthesis flag. Setting to default value' );
    param.synthesis = 'all';
end

switch lower(dimensionality)
    case '2d'
        %generate 2D framework
        %D. Sullivan 4/29/13 Removed this param init since it is done
        %immediately before call in model2img.m
        %         param = ml_initparam(param, ...
        %             struct('imageSize',[1024 1024],'gentex',0,'loc','all','spherical_cell',false));
        %
        %generate cell framework
        %yajing 7/2/2013 Added spherical_cell case from bob's update
        if param.spherical_cell
            [nucimg,cellimg] = rm_gencellcomp2D_circle( model, param);
        elseif isfield( model.nuclearShapeModel, 'type' ) && ...
               isfield( model.cellShapeModel, 'type' ) && ...
                strcmpi( model.nuclearShapeModel.type, 'diffeomorphic' ) && ...
                strcmpi( model.cellShapeModel.type, 'diffeomorphic' )
            
            %use the same code for 3D, returns RGB image
            [nucimg, cellimg, param] = model2diffeomorphicInstance( model, param );
            if ~isfield(param, 'resolution')
                param.resolution = model.proteinModel.resolution;
                outres = model.proteinModel.resolution;
            end
            nucEdge = bwboundaries( double(sum(nucimg,3)) > 0);
            cellEdge = bwboundaries(double(sum(nucimg,3)+sum(cellimg,3)) > 0);
            cellEdge = cellEdge{1};
            nucEdge = nucEdge{1};
            nucimg = zeros(size(nucimg, 1), size(nucimg, 2));
            cellimg = zeros(size(cellimg, 1), size(cellimg, 2));
            for i = 1 : size( nucEdge, 1)
                nucimg(nucEdge(i, 1), nucEdge(i, 2)) = 1;
            end
            for i = 1 : size( cellEdge, 1)
                cellimg(cellEdge(i, 1), cellEdge(i, 2)) = 1;
            end
        else
            [nucimg,cellimg] = ml_gencellcomp2D( model, param );
        end
        
        %icaobeg 5/18/2013
        %make sure the nuclear edge is not empty
        %the nuclear edge can never be empty
        if isempty( nucimg ) && isempty( cellimg )
            disp( 'Nuclear image is empty. Returning empty framework.' );
            outres = [];
            return
        end
        
        if strcmpi( param.synthesis, 'framework' ) || ...
                strcmpi( param.synthesis, 'all' )
            
            if isempty( cellimg )
                disp( 'Cell image is empty. Returning empty framework.' );
                nucimg = [];
                cellimg = [];
                return
            else
                box = tp_imbox(cellimg);
                nucimg = nucimg(box(1):box(2),box(3):box(4),:);
                cellimg = cellimg(box(1):box(2),box(3):box(4),:);
            end
        else
            if isempty( nucimg )
                disp( 'Nuclear image is empty. Returning empty framework.' );
                nucimg = [];
                cellimg = [];
            else
                box = tp_imbox(nucimg);
                nucimg = nucimg(box(1):box(2),box(3):box(4),:);
            end
        end
        
        %D. Sullivan 3/3/12
        %Set the output resolution
        if isfield( param,'resolution' )
            if isfield( param.resolution,'objects' )
                outres = param.resolution.objects;
            end
            outres = param.resolution;
        else
            %icaoberg 7/1/2013
            disp( 'Generated framework from 2D models are not downsampled. Inheriting resolution from model.' );
            outres = model.nuclearShapeModel.resolution;
        end
    case '3d'
        %D. Sullivan 3/5/13
        %check if we already have a framework (as in from raw data)
        
        if isfield( param, 'instance' ) && isfield(param.instance,'nucleus')
            if isfield(param.instance,'cell')
                %check if the images are the same size in all dimensions
                if all(size(param.instance.cell)==size(param.instance.nucleus))
                    nucimg = param.instance.nucleus;
                    cellimg = param.instance.cell;
                    if isfield(param,'resolution')
                        if isfield(param.resolution,'cell')
                            outres = param.resolution.cell;
                            
                        end
                    else
                        outres = [];
                    end
                    return
                    
                end
                if debug
                    warning('Cell and nucleus found, but the images were not the same size, synthesizing new framework');
                end
            end
        end
        
        %icaoberg march 17, 2014
        if strcmpi( param.synthesis, 'nucleus' ) && strcmpi( model.nuclearShapeModel.type, 'major axis' )
            %generate 3D framework
            model.nuclearShapeModel.height.stat.mu = model.nuclearShapeModel.height.stat.mu;
            model.nuclearShapeModel.height.stat.sigma = model.nuclearShapeModel.height.stat.sigma;
            
            %icaoberg 8/7/2013
            %resolution is always needed
            param.resolution.nucleus = model.nuclearShapeModel.resolution;
            
            %D. Sullivan 2/22/13 added param structure to pass the cell and
            %object resolutions
            instance = tp_genspsurf(model.nuclearShapeModel,param);
            %instance = tp_genspsurf(model.nuclearShapeModel);
            
            %disp('Generating nuclear shape instance');
            %Yajing Tang 7/2/2013 Added spherical_cell case from Bob's update
            [nucimg,nucsurf,outres] = tp_gennucshape(instance,param);
            
            nucleus.nucimgsize = size(nucimg);
            nucleus.nucsurf = nucsurf;
            nucleus.nucimg = nucimg;
            
            box = tp_imbox(nucimg);
            nucimg = nucimg(box(1):box(2),box(3):box(4),:);
            cellimg = [];
            
        elseif ( strcmpi( param.synthesis, 'framework' ) || ...
                strcmpi( param.synthesis, 'all' ) ) && strcmpi( model.nuclearShapeModel.type, 'major axis' ) && ...
                strcmpi( model.cellShapeModel.type, 'ratio' )
            
            %generate 3D framework
            model.nuclearShapeModel.height.stat.mu = model.nuclearShapeModel.height.stat.mu;
            model.nuclearShapeModel.height.stat.sigma = model.nuclearShapeModel.height.stat.sigma;
            
            %D. Sullivan 2/22/13 added param structure to pass the cell and
            %object resolutions
            instance = tp_genspsurf(model.nuclearShapeModel,param);
            %instance = tp_genspsurf(model.nuclearShapeModel);
            
            %disp('Generating nuclear shape instance');
            %Yajing Tang 7/2/2013 Added spherical_cell case from Bob's update
            if param.spherical_cell
                % this doesn't work yet
                [nucimg,nucsurf] = rm_gensphere([1024*1.25, 1024*1.25, 5*instance.height],[0.33, 0.33, 0.33]);
            else
                [nucimg,nucsurf,outres] = tp_gennucshape(instance,param);
            end
            
            nucleus.nucimgsize = size(nucimg);
            nucleus.nucsurf = nucsurf;
            nucleus.nucimg = nucimg;
            
            %disp('Generating cell shape instance');
            %Yajing Tang 7/2/2013 Added spherical_cell case from Bob's update
            if param.spherical_cell
                [cellimg,cellsurf] = rm_gensphere(1.0);
            else
                [cellimg,nucimg] = ml_gencellshape3d( ...
                    model.cellShapeModel, nucleus,param );
            end
            
            
            box = tp_imbox(cellimg);
            nucimg = nucimg(box(1):box(2),box(3):box(4),:);
            cellimg = cellimg(box(1):box(2),box(3):box(4),:);
            
        elseif strcmpi( model.nuclearShapeModel.type, 'diffeomorphic' ) && ...
                strcmpi( model.cellShapeModel.type, 'diffeomorphic' )
            %icaoberg 10/1/2012
            outres = param.resolution.cell;
            [nucimg, cellimg, param] = model2diffeomorphicInstance( model, param );
        else
            %icaoberg 10/1/2012
            warning( 'CellOrganizer: Unrecognized model type or combination of model types.' );
            nucimg = [];
            cellimg = [];
        end
    otherwise
        return
end
end
