function s = saxs(varargin)
%SAXS/SAXS Creating Small angle X-ray scattering (SAXS) image objects.
%   SAXS constructs SAXS objects.  See below for more about SAXS objects.
%   You will usually create SAXS objects with GETSAXS, but you can use
%   SAXS directly to create a SAXS object from an array of pixel values.
%
%   SAXS(PIXELS, HISTORY) creates a new SAXS image object from the
%   two-dimensional array PIXELS.  The first history entry is set to the
%   string HISTORY.  If HISTORY is omitted, a default history entry is
%   inserted.  The SAXS type field is set to 'xy'.  Use SAXS methods TYPE,
%   REALTIME, LIVETIME, TRANSFACT, XAXIS, YAXIS, MASK, and HISTORY to set
%   additional attributes of the image object.  See help for those
%   functions. Some SAXS methods overload other MATLAB functions by the
%   same name, for example, TYPE and IMAGE.  Type HELP SAXS/IMAGE to
%   display help for the SAXS version of IMAGE.
%
%   S = SAXS(STRUCT) converts a structure to a SAXS object.  The structure
%   must result from loading an outdated SAXS object variable from disk.
%   MATLAB will warn you that the object does not conform to the current
%   SAXS class and converts the variable to a structure.  This form of the
%   SAXS method tries to update the structure and return an up-to-date SAXS
%   object.
%
% ABOUT SAXS OBJECTS AND METHODS
%   The displayed form of a SAXS variable (such as results when you type
%   the variable name at the command line) lists the attributes of the
%   image.  The displayed form does not print the pixel values.  To access
%   pixel values of a SAXS object S, use DOUBLE(S), S.PIXELS, or use
%   subscripts.  S(512,512) references the image pixel at column 512 and
%   row 512.  On the other hand to create arrays of SAXS objects, use cell
%   arrays.
%
%   See also SAXS/SAXS-FIELDS, SAXS/SAXS-METHODS, and SAXS/GETSAXS.

% SAXS invocations for behind-the-scenes object construction:
%   SAXS with no arguments returns an empty SAXS object.
%   SAXS(S) creates a copy of an existing SAXS object.

saxs_preferences_read  % get cmask_radius
default_cmask_radius = cmask_radius;

if nargin == 0  % make empty saxs object
    
    s = struct('pixels', {}, 'type', {'xy'}, 'relerr',{},...
        'error_norm_fact',{},'datatype', {},'detectortype',{}, ... 
        'cmask_radius', {}, 'cmask_outer', {}, ...
        'xaxis', {}, 'xaxisfull', {},'yaxis', {}, 'xaxisbintype', {},'log', {}, 'realtime', {}, 'livetime', {}, ...
        'transfact', {}, 'sample_thickness', {},...
        'calibrationtype', {},'kcal', {},'pixelcal', {}, 'koffset', {},...
        'wavelength', {}, 'pixelsize', {}, 'detector_dist', {},...
        'reduction_type', {},'reduction_state', {},'raw_filename', {},'raw_date', {},'raw_pixels', {},'raw_center', {},...
        'bsmask_configuration', {},'bsmask_pixels', {},...
        'mask_filename', {},'mask_pixels', {},...
        'flatfield_filename', {},'flatfield_pixels', {},'flatfieldtype', {},...
        'empty_filename', {},'empty_pixels', {},'empty_transfact', {},'empty_livetime', {},...
        'solvent_filename', {},'solvent_pixels', {},'solvent_transfact', {},'solvent_livetime', {},'solvent_thickness', {},...
        'darkcurrent_filename', {},'darkcurrent_pixels', {},'darkcurrent_livetime', {},...
        'readoutnoise_filename', {},'readoutnoise', {},...
        'zinger_removal',{},...
        'abs_int_fact',{},'sample_description', {},...
        'sample_condition.xpos',{},'sample_condition.ypos',{},...
        'sample_condition.angle1',{},'sample_condition.angle2',{},'sample_condition.angle3',{},...
        'sample_condition.temp',{},'sample_condition.pressure',{},'sample_condition.strain',{},'sample_condition.stress',{},...
        'sample_condition.shear_rate',{},...
        'sample_condition.sample_conc',{},...
        'exp_conf.d1',{},'exp_conf.d2',{},'exp_conf.d3',{},...
        'exp_conf.l1',{},'exp_conf.l2',{},'exp_conf.l3',{},'exp_conf.l4',{},...
        'exp_conf.wavelength',{},'exp_conf.deltawavelength',{},'exp_conf.Izero',{},...
        'exp_conf.det_pixsizex',{},'exp_conf.det_pixsizey',{},...
        'exp_conf.det_offx',{},'exp_conf.det_offy',{},...
        'exp_conf.det_rotx',{},'exp_conf.det_roty',{},...
        'exp_conf.det_resx',{},'exp_conf.det_resy',{},...
        'exp_conf.det_rel_eff',{},...
        'added_constant', {},'multiplication_fact', {},...
        'userdata_cell', {},'metadata', {},...
        'history', {});
    s = class(s, 'saxs');
elseif nargin == 1 && isa(varargin{1}, 'saxs')  % copy a (possibly empty) saxs object
    
    s = varargin{1};
    % No use trying to add history here.  We seem only to get here if
    % called explicitly from the command line.
elseif (nargin == 1 && isnumeric(varargin{1}) && ndims(varargin{1}) == 2) ...
        || (nargin == 2 && isnumeric(varargin{1}) && ndims(varargin{1}) == 2 && ischar(varargin{2}))
    % Make saxs object from pixel array.
    s.pixels = double(varargin{1});
    s.type = 'xy';
    s.relerr =[];
    s.error_norm_fact=1;
    s.datatype =[];
    s.detectortype =[];
    s.cmask_radius = default_cmask_radius;
    s.cmask_outer = [];
    s.xaxis = [1, size(varargin{1}, 2)];
    s.xaxisfull=[];
    s.yaxis = [1, size(varargin{1}, 1)];
    s.xaxisbintype= [];
    s.log = []; 
    s.realtime = [];
    s.livetime = [];
    s.transfact = [];
    s.sample_thickness = [];
    s.calibrationtype = [];
    s.kcal = [];
    s.pixelcal = [];
    s.koffset = [];
    s.wavelength = [];
    s.pixelsize = [];
    s.detector_dist = [];
    s.reduction_type =[];
    s.reduction_state =[];
    s.raw_filename=[];
    s.raw_date=[];
    s.raw_pixels=s.pixels;
    s.raw_center=size(s.raw_pixels)/2;
    s.bsmask_configuration=[];
    s.bsmask_pixels=[];
    s.mask_filename=[];
    s.mask_pixels = [];
    s.flatfield_filename=[];
    s.flatfield_pixels = [];
    s.flatfieldtype =[];
    s.empty_filename=[];
    s.empty_pixels = [];
    s.empty_transfact = [];
    s.empty_livetime = [];
    s.solvent_filename=[];
    s.solvent_thickness=[];
    s.solvent_pixels = [];
    s.solvent_transfact = [];
    s.solvent_livetime = [];
    s.darkcurrent_filename=[];
    s.darkcurrent_pixels = [];
    s.darkcurrent_livetime = [];
    s.readoutnoise_filename=[];
    s.readoutnoise= [];
    s.zinger_removal= 0;
    s.abs_int_fact = [];
    s.sample_description = [];
    s.sample_condition.xpos=[];
    s.sample_condition.ypos= [];
    s.sample_condition.angle1= [];
    s.sample_condition.angle2= [];
    s.sample_condition.angle3= [];
    s.sample_condition.temp= [];
    s.sample_condition.pressure= [];
    s.sample_condition.strain= [];
    s.sample_condition.stress= [];
    s.sample_condition.shear_rate= [];
    s.sample_condition.sample_conc= [];
    s.exp_conf.d1= [];
    s.exp_conf.d2= [];
    s.exp_conf.d3= [];
    s.exp_conf.l1= [];
    s.exp_conf.l2= [];
    s.exp_conf.l3= [];
    s.exp_conf.l4= [];
    s.exp_conf.wavelength= [];
    s.exp_conf.deltawavelength= [];
    s.exp_conf.Izero= [];
    s.exp_conf.det_offx= 0;
    s.exp_conf.det_offy= 0;
    s.exp_conf.det_rotx= 0;
    s.exp_conf.det_roty= 0;
    s.exp_conf.det_pixsizex= [];
    s.exp_conf.det_pixsizey= [];
    s.exp_conf.det_resx= [];
    s.exp_conf.det_resy= [];
    s.exp_conf.det_rel_eff= [];
    s.added_constant = 0;
    s.multiplication_fact = 1;
    s.userdata_cell = {};
    s.metadata = [];
    

    if nargin == 2  % history provided (validated above)
        s.history = varargin{2};
    else
        s.history = ['constructed from array (', inputname(1), ') ', datestr(now)];
    end
    s = class(s, 'saxs');
elseif nargin == 1 && isa(varargin{1}, 'struct')
    % Make a saxs from a struct containing some of the saxs fields.
    t = varargin{1};
    if ~ isfield(t, 'pixels')
        error('I can''t make a SAXS object from a struct without pixels.')
    end
    % And thereupon we naively assume the best...
    s.pixels = t.pixels;
    if isempty(t.type)
        s.type = 'xy';
    else
        s.type = t.type;
    end
    if isfield(t, 'relerr')
        s.relerr = t.relerr;
    else
        s.relerr = [];
    end
    if isfield(t, 'datatype')
        s.datatype = t.datatype;
    else
        s.datatype = [];
    end
    if isfield(t, 'detectortype')
        s.detectortype = t.detectortype;
    else
        s.detectortype = [];
    end
    
    s.cmask_radius = t.cmask_radius;
    
    if isfield(t, 'cmask_outer')
        s.mask_outer = t.cmask_outer;
    else
        s.cmask_outer = [];
    end
    if isempty(t.xaxis)
        s.xaxis = [1, size(t.pixels, 2)];
    else
        s.xaxis = t.xaxis;
    end
    
    if isempty(t.xaxisfull)
        s.xaxisfull = s.xaxis;
    else
        s.xaxisfull = t.xaxisfull;
    end
    
    if isempty(t.yaxis)
        s.yaxis = [1, size(t.pixels, 1)];
    else
        s.yaxis = t.yaxis;
    end
    
    if isfield(t, 'xaxisbintype')
        s.xaxisbintype = t.xaxisbintype;
    else
        s.xaxisbintype = [];
    end
    
    s.log = t.log;
    
    if isfield(t, 'realtime')
        s.realtime = t.realtime;
        s.livetime = t.livetime;
    else
        s.realtime = [];
        s.livetime = [];
    end
    
    if isfield(t, 'transfact')
        s.transfact = t.transfact;
    else
        s.transfact = [];
    end
    
    if isfield(t, 'sample_thickness')
        s.sample_thickness = t.sample_thickness;
    else
        s.transfact = [];
    end
    
    if isfield(t, 'calibrationtype')
        s.calibrationtype = t.calibrationtype;
    else
        s.calibrationtype = [];
    end
    
    if isfield(s, 'kcal')
        s.kcal = t.kcal;
        s.pixelcal = t.pixelcal;
        s.koffset = t.koffset;
    else
        s.kcal = [];
        s.pixelcal = [];
        s.koffset = [];
    end

    if isfield(s, 'wavelength')
        s.wavelength = t.wavelength;
        s.pixelsize = t.pixelsize;
        s.detector_dist = t.detector_dist;
    else
        s.wavelength = [];
        s.pixelsize = [];
        s.detector_dist = [];
    end

    if isfield(t, 'reduction_type')
        s.reduction_type = t.reduction_type;
    else
        s.reduction_type = [];
    end
    
    if isfield(t, 'reduction_state')
        s.reduction_state = t.reduction_state;
    else
        s.reduction_state = [];
    end
    
    if isfield(t, 'raw_filename')
        s.raw_filename = t.raw_filename;
    else
        s.raw_filename = [];
    end
    
    if isfield(t, 'raw_date')
        s.raw_date = t.raw_date;
    else
        s.raw_date = [];
    end
    
    s.raw_pixels = s.pixels;
    
    if isempty(t.raw_center)
        s.raw_center = size(t.raw_pixels)/2;
    else
        s.xaxis = t.raw_center;
    end
    
    if isfield(t, 'bsmask_configuration')
        s.bsmask_configuration = t.bsmask_configuration;
    else
        s.bsmask_configuration = [];
    end

    if isfield(t, 'bsmask_pixels')
        s.bsmask_pixels = t.bsmask_pixels;
    else
        s.bsmask_pixels = [];
    end
    
    if isfield(t, 'mask_filename')
        s.mask_filename = t.mask_filename;
    else
        s.mask_filename = [];
    end

    if isfield(t, 'mask_pixels')
        s.mask_pixels = t.mask_pixels;
    else
        s.mask_pixels = [];
    end
    
    if isfield(t, 'flatfield_filename')
        s.flatfield_filename = t.flatfield_filename;
    else
        s.flatfield_filename = [];
    end

    if isfield(t, 'flatfield_pixels')
        s.flatfield_pixels = t.flatfield_pixels;
    else
        s.flatfield_pixels = [];
    end
    if isfield(t, 'flatfieldtype')
        s.flatfieldtype = t.flatfieldtype;
    else
        s.flatfieldtype = [];
    end

    if isfield(t, 'empty_filename')
        s.empty_filename = t.empty_filename;
    else
        s.empty_filename = [];
    end

    if isfield(t, 'empty_pixels')
        s.empty_pixels = t.empty_pixels;
    else
        s.empty_pixels = [];
    end
    if isfield(t, 'empty_transfact')
        s.empty_transfact = t.empty_transfact;
    else
        s.empty_transfact= [];
    end
    if isfield(t, 'empty_livetime')
        s.empty_livetime = t.empty_livetime;
    else
        s.empty_livetime= [];
    end

    if isfield(t, 'solvent_filename')
        s.solvent_filename = t.solvent_filename;
    else
        s.solvent_filename = [];
    end

    if isfield(t, 'solvent_pixels')
        s.solvent_pixels = t.solvent_pixels;
    else
        s.solvent_pixels = [];
    end
    if isfield(t, 'solvent_transfact')
        s.solvent_transfact = t.solvent_transfact;
    else
        s.solvent_transfact= [];
    end
    if isfield(t, 'solvent_livetime')
        s.solvent_livetime = t.solvent_livetime;
    else
        s.solvent_livetime= [];
    end
    
    if isfield(t, 'solvent_thickness')
        s.solvent_thickness = t.solvent_thickness;
    else
        s.solvent = [];
    end
    
    if isfield(t, 'darkcurrent_filename')
        s.darkcurrent_filename = t.darkcurrent_filename;
    else
        s.darkcurrent_filename = [];
    end

    if isfield(t, 'darkcurrent_pixels')
        s.darkcurrent_pixels = t.darkcurrent_pixels;
    else
        s.darkcurrent_pixels = [];
    end
    if isfield(t, 'darkcurrent_livetime')
        s.darkcurrent_livetime = t.darkcurrent_livetime;
    else
        s.darkcurrent_livetime= [];
    end
    
    if isfield(t, 'readoutnoise_filename')
        s.readoutnoise_filename = t.readoutnoise_filename;
    else
        s.readoutnoise_filename = [];
    end

    if isfield(t, 'readoutnoise')
        s.readoutnoise = t.readoutnoise;
    else
        s.readoutnoise = [];
    end
    
    if isfield(t, 'zinger_removal')
        s.zinger_removal = t.zinger_removal;
    else
        s.zinger_removal= [];
    end

    if isfield(t, 'abs_int_fact')
        s.abs_int_fact = t.abs_int_fact;
    else
        s.abs_int_fact= [];
    end
    name={'sample_description','sample_condition.xpos','sample_condition.ypos','sample_condition.angle1','sample_condition.angle2','sample_condition.angle3',...
        'sample_condition.temp','sample_condition.pressure','sample_condition.strain','sample_condition.stress','sample_condition.shear_rate',...
        'sample_condition.sample_conc','exp_conf.d1','exp_conf.d2','exp_conf.d3',...
        'exp_conf.l1','exp_conf.l2','exp_conf.l3','exp_conf.l4','exp_conf.wavelength','exp_conf.deltawavelength','exp_conf.Izero',...
        'exp_conf.det_offx','exp_conf.det_offy','exp_conf.det_rotx','exp_conf.det_roty',...
        'exp_conf.det_pixsizex','exp_conf.det_pixsizey','exp_conf.det_resx','exp_conf.det_resy','exp_conf.det_rel_eff'};
    
    for ii=1:length(name)
        txt=['if isfield(t,''',name{ii},'''), s.',name{ii},' = t.',name{ii},';else s.',name{ii},' = []; end'];
        eval(txt)
    end
    if isempty(s.exp_conf.det_offx), s.exp_conf.det_offx= 0; end
    if isempty(s.exp_conf.det_offy), s.exp_conf.det_offy= 0; end
    if isempty(s.exp_conf.det_rotx), s.exp_conf.det_rotx= 0; end
    if isempty(s.exp_conf.det_roty), s.exp_conf.det_roty= 0; end 

    if isfield(t, 'added_constant')
        s.added_constant = t.added_constant;
    else
        s.added_constant= 0;
    end
    
    if isfield(t, 'multiplication_fact')
        s.multiplication_fact = t.multiplication_fact;
    else
        s.multiplication_fact= [];
    end
    
    if isfield(t, 'userdata_cell')
        s.userdata_cell = t.userdata_cell;
    else
        s.userdata_cell= {};
    end
    
    if isfield(t, 'metadata')
        s.metadata = t.metadata;
    else
        s.metadata= [];
    end
    
    s.history = t.history;
    s = class(s, 'saxs');
    s = history(s, 'updated SAXS field structure');
else
    error('I don''t understand those arguments.')
end
