classdef Beams < handle & matlab.mixin.Copyable

    properties (Access = private)
        
        BlueBeamDefault         = struct('Alias',                                          'Blue', ...
                                         'Power',                                          400e-3, ...
                                         'Detuning',  -1.64*Helper.PhysicsConstants.BlueLinewidth, ...
                                         'Radius',                                        17.5e-3, ...
                                         'Waist',                                           15e-3, ...
                                         'WaveNumber',2*pi/Helper.PhysicsConstants.BlueWavelength, ...
                                         'Linewidth',       Helper.PhysicsConstants.BlueLinewidth, ...
                                         'SaturationIntensity',  0.1 * (2 * pi^2 / 3)    * ...
                                         ((Helper.PhysicsConstants.PlanckConstantReduced * ...
                                         Helper.PhysicsConstants.SpeedOfLight            * ...
                                         Helper.PhysicsConstants.BlueLinewidth) / (Helper.PhysicsConstants.BlueWavelength)^3));
        
        BlueSidebandBeamDefault = struct('Alias',                                 'BlueSideband', ...
                                         'Power',                                          400e-3, ...
                                         'Detuning',     -3*Helper.PhysicsConstants.BlueLinewidth, ...
                                         'Radius',                                        17.5e-3, ...
                                         'Waist',                                           15e-3, ...
                                         'WaveNumber',2*pi/Helper.PhysicsConstants.BlueWavelength, ...
                                         'Linewidth',       Helper.PhysicsConstants.BlueLinewidth, ...
                                         'SaturationIntensity',  0.1 * (2 * pi^2 / 3)    * ...
                                         ((Helper.PhysicsConstants.PlanckConstantReduced * ...
                                         Helper.PhysicsConstants.SpeedOfLight            * ...
                                         Helper.PhysicsConstants.BlueLinewidth) / (Helper.PhysicsConstants.BlueWavelength)^3));
        
        PushBeamDefault         = struct('Alias',                                         'Push', ...
                                         'Power',                                         25e-3 , ...
                                         'Detuning',  104.2*Helper.PhysicsConstants.RedLinewidth, ...
                                         'Radius',                                       1.2e-03, ...
                                         'Waist',                                        1.0e-03, ...
                                         'WaveNumber',2*pi/Helper.PhysicsConstants.RedWavelength, ...
                                         'Linewidth',       Helper.PhysicsConstants.RedLinewidth, ...
                                         'SaturationIntensity',  0.1 * (2 * pi^2 / 3)    * ...
                                         ((Helper.PhysicsConstants.PlanckConstantReduced * ...
                                         Helper.PhysicsConstants.SpeedOfLight            * ...
                                         Helper.PhysicsConstants.RedLinewidth) / (Helper.PhysicsConstants.RedWavelength)^3));
                                   
        RedBeamDefault          = struct('Alias',                                          'Red', ...
                                         'Power',                                        100e-3 , ...
                                         'Detuning',     -1*Helper.PhysicsConstants.RedLinewidth, ...
                                         'Radius',                                        1.2e-3, ...
                                         'Waist',                                         12e-3 , ...
                                         'WaveNumber',2*pi/Helper.PhysicsConstants.RedWavelength, ...
                                         'Linewidth',       Helper.PhysicsConstants.RedLinewidth, ...
                                         'SaturationIntensity',  0.1 * (2 * pi^2 / 3)    * ...
                                         ((Helper.PhysicsConstants.PlanckConstantReduced * ...
                                         Helper.PhysicsConstants.SpeedOfLight            * ...
                                         Helper.PhysicsConstants.RedLinewidth) / (Helper.PhysicsConstants.RedWavelength)^3));
    end
    
    properties
        Alias
        Power;
        Detuning;
        Radius;
        Waist;
        WaveNumber;
        SaturationIntensity;
        Linewidth;
    end
    
    properties (Dependent)
        SaturationParameter;
    end
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %- Methods
    
    methods
        %% Class Constructor
        function this  = Beams(BeamName)
        	input = inputParser;
            addRequired(input,'BeamName', @ischar);
            parse(input, BeamName);
            this.Alias = input.Results.BeamName;
            
            switch this.Alias
                case this.BlueBeamDefault.Alias
                    this.Power               = this.BlueBeamDefault.Power;
                    this.Detuning            = this.BlueBeamDefault.Detuning;
                    this.Radius              = this.BlueBeamDefault.Radius;
                    this.Waist               = this.BlueBeamDefault.Waist;
                    this.WaveNumber          = this.BlueBeamDefault.WaveNumber;    
                    this.Linewidth           = this.BlueBeamDefault.Linewidth;    
                    this.SaturationIntensity = this.BlueBeamDefault.SaturationIntensity;
                case this.BlueSidebandBeamDefault.Alias
                    this.Power               = this.BlueSidebandBeamDefault.Power;
                    this.Detuning            = this.BlueSidebandBeamDefault.Detuning;
                    this.Radius              = this.BlueSidebandBeamDefault.Radius;
                    this.Waist               = this.BlueSidebandBeamDefault.Waist;
                    this.WaveNumber          = this.BlueSidebandBeamDefault.WaveNumber;  
                    this.Linewidth           = this.BlueSidebandBeamDefault.Linewidth;
                    this.SaturationIntensity = this.BlueSidebandBeamDefault.SaturationIntensity;
                case this.PushBeamDefault.Alias
                    this.Power               = this.PushBeamDefault.Power;
                    this.Detuning            = this.PushBeamDefault.Detuning;
                    this.Radius              = this.PushBeamDefault.Radius;
                    this.Waist               = this.PushBeamDefault.Waist;
                    this.WaveNumber          = this.PushBeamDefault.WaveNumber;     
                    this.Linewidth           = this.PushBeamDefault.Linewidth;
                    this.SaturationIntensity = this.PushBeamDefault.SaturationIntensity;
                case this.RedBeamDefault.Alias
                    this.Power               = this.RedBeamDefault.Power;
                    this.Detuning            = this.RedBeamDefault.Detuning;
                    this.Radius              = this.RedBeamDefault.Radius;
                    this.Waist               = this.RedBeamDefault.Waist;
                    this.WaveNumber          = this.RedBeamDefault.WaveNumber;   
                    this.Linewidth           = this.RedBeamDefault.Linewidth;
                    this.SaturationIntensity = this.RedBeamDefault.SaturationIntensity;
                otherwise
                    error('No such beam!')
            end
        end
    end % - lifecycle    

    methods
        function set.Power(this,val)
            this.Power = val;
        end
        function ret = get.Power(this)
            ret = this.Power;
        end
        function set.Detuning(this, val)
            this.Detuning = val;
        end
        function ret = get.Detuning(this)
            ret = this.Detuning;
        end
        function set.Radius(this, val)
            this.Radius = val;
        end
        function ret = get.Radius(this)
            ret = this.Radius;
        end
        function set.Waist(this, val)
            this.Waist = val;
        end
        function ret = get.Waist(this)
            ret = this.Waist;
        end
        function set.WaveNumber(this, val)
            this.WaveNumber = val;
        end
        function ret = get.WaveNumber(this)
            ret = this.WaveNumber;
        end
        function set.SaturationIntensity(this, val)
            this.SaturationIntensity = val;
        end
        function ret = get.SaturationIntensity(this)
            ret = this.SaturationIntensity;
        end
        function set.Linewidth(this, val)
            this.Linewidth = val;
        end
        function ret = get.Linewidth(this)
            ret = this.Linewidth;
        end
    end % - setters and getters
    
    methods
        function ret       = get.SaturationParameter(this)
            ret = 0.1 * (8 * this.Power) / (pi*this.Waist^2 * this.SaturationIntensity); % two beams are reflected
        end
    end % - getters for dependent properties
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %- 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(BeamName)
            % Creates an Instance of Class, ensures singleton behaviour
            persistent localObj;
            if isempty(localObj) || ~isvalid(localObj)
                localObj =  Simulator.Beams(BeamName);
            end
            singleObj = localObj;
        end
    end    
end
