classdef Calculator < handle & matlab.mixin.Copyable

    properties (Access = private)
        
        CalculatorDefaults     = struct('ChemicalPotential',                                       1, ...
                                        'EnergyComponents',                                        1, ...
                                        'NormalizedResiduals',                                     1, ...
                                        'OrderParameter',                                          1, ...
                                        'PhaseCoherence',                                          1, ...
                                        'TotalEnergy',                                             1, ...
                                        'CutoffType',                                  'Cylindrical');

    end

    properties (Access = public)
        ChemicalPotential;
        EnergyComponents;
        NormalizedResiduals;
        OrderParameter;
        PhaseCoherence;
        TotalEnergy;
        CutoffType;
    end
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %- Methods
    
    methods
        function this  = Calculator(varargin)
            
            p = inputParser;
            p.KeepUnmatched = true;
            addParameter(p, 'CutoffType', this.CalculatorDefaults.CutoffType,... 
                @(x) any(strcmpi(x,{'Cylindrical','CylindricalInfiniteZ', 'Spherical'})));
            
            p.parse(varargin{:});
            
            this.ChemicalPotential             = this.CalculatorDefaults.ChemicalPotential;
            this.EnergyComponents              = this.CalculatorDefaults.EnergyComponents;
            this.NormalizedResiduals           = this.CalculatorDefaults.NormalizedResiduals;
            this.OrderParameter                = this.CalculatorDefaults.OrderParameter;
            this.PhaseCoherence                = this.CalculatorDefaults.PhaseCoherence;
            this.TotalEnergy                   = this.CalculatorDefaults.TotalEnergy;
            this.CutoffType                    = p.Results.CutoffType;
        end

        function restoreDefaults(this)
            this.ChemicalPotential          = this.CalculatorDefaults.ChemicalPotential;
            this.EnergyComponents           = this.CalculatorDefaults.EnergyComponents;
            this.NormalizedResiduals        = this.CalculatorDefaults.NormalizedResiduals;
            this.OrderParameter             = this.CalculatorDefaults.OrderParameter;
            this.PhaseCoherence             = this.CalculatorDefaults.PhaseCoherence;
            this.TotalEnergy                = this.CalculatorDefaults.TotalEnergy;
            this.CutoffType                 = this.CalculatorDefaults.CutoffType;
        end
        
    end %

    % methods
        
    % end % - setters and getters
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %- Methods
    
    methods(Access = protected)
        function cp = copyElement(this)
            % Shallow copy object
            cp = copyElement@matlab.mixin.Copyable(this);
            
            % Forces the setter to redefine the function handles to the new copied object
            
            pl = properties(this);
            for k = 1:length(pl)
                sc = superclasses(this.(pl{k}));
                if any(contains(sc,{'matlab.mixin.Copyable'}))
                    cp.(pl{k}) = this.(pl{k}).copy();
                end
            end
        end
    end
    
    methods (Static)
        
        % Creates an Instance of Class, ensures singleton behaviour (that there
        % can only be one Instance of this class
        function singleObj = getInstance(varargin)
            % Creates an Instance of Class, ensures singleton behaviour
            persistent localObj;
            if isempty(localObj) || ~isvalid(localObj)
                localObj =  Simulator.Calculator(varargin{:});
            end
            singleObj = localObj;
        end
    end
    
end