function external = setexternal(mode, preExternal, varargin)      

% SETEXTERNAL - set external angles for makelist
%
% external = setexternal(mode, preExternal)  
%   external drawn from file and cannot be 'OPTIMAL'
% external = setexternal(mode, preExternal, nSim)  
%   external directly input into makelist and cannot be 'OPTIMAL' 
% external = setexternal(mode, preExternal, nSim, detId)  
%   internal can be 'OPTIMAL'
%
% mode      operating mode of makelist
% preExternal  intermediate external angles 
% nSim      (optional) number of angles to generate
% detId     (optional) detector identifier
%
% external  determined external angles

% $Id: setexternal.m,v 1.7 2004/05/17 21:21:01 stuver Exp $

% DETERMINE how external angles where input to makelist from mode
% IF external angles were read from file
%   DETERMINE if makelist needs to set angles
%   IF angle needs to be set
%       SET angle
%   ELSEIF anlge does not need to be set
%       TYPECAST from string to double
%   ENDIF
%   RETURN determined external angles
% ELSEIF external angles were not read from a file
%   DETERMINE class of external
%   IF string
%       SET angles either randomly or to optimal orientation
%   ELSEIF double
%       COPY external nSim times
%   ELSEIF struct
%       COPY exernal nSim times
%   ENDIF
%   RETURN determined external angles
% ENDIF

external = [];

% Modes with positive numbers are modes from makelist and match the modes
% used in makelist.  Modes with negative numbers are modes for
% pre-generated waveforms
if (mode ==3 | mode == 4 | mode ==6 | mode == -1 | mode == -2) ...
        & length(varargin)~=2
    varargin
    error(['makelist -> setexternal: length(varargin) must be 2 for ' ...
            'modes 3, 4, 6, -1 or -2'])
end

% If external may be 'OPTIMAL', assign varargin{2} as the detId
if length(varargin) == 2
    detId = varargin{2};
    if mode == 3 | mode == 4 | mode == 6 | mode == -1 | mode == -2
        % Get detector coordinates
        Cordnt = getifo(detId);
    end
end

% If external was read from file
if mode == 1 | mode == 2 | mode == 3 | mode == 4 | mode == -1
    % There are 3 types of external angles that need to be looked at
    % individually.
    % Each of these angle types my be a list.  Each angle on the list must
    % be looked at individually.
    
    % Sort external into the three angle types
    [ext1, ext2, ext3] = deal(preExternal{1}, preExternal{2}, ...
        preExternal{3});
        
    % Look at every angle in each angle type
    for k=1:size(ext1, 1)
        % Examine ext1
        if strcmp(upper(ext1(k,:)), 'RANDOM') | ...
            strcmp(upper(ext1(k,:)), 'RANDOM ')
            % Set first external angle randomly
            tempExt1(k,1) = randomangle(1, 'x');
        elseif (mode == 3 | mode == 4) & strcmp(upper(ext1(k,:)), 'OPTIMAL')
            % Set source at zenith
            if ~isfield(Cordnt, 'CODEC')
                error('makelist -> setexternal: Cordnt.CODEC does not exist')
            end
            tempExt1(k,1) = Cordnt.CODEC;
        else
            % Typecast first external angle
            tempExt1(k,1) = str2double(ext1(k,:));
            % Check for error
            if isnan(tempExt1(k,1))
                if mode == 1 | mode == 2
                    ext1 = ext1(k,:)
                    error(['makelist -> setexternal: ext1 must be a ' ...
                            'double or char ''RANDOM'''])
                elseif mode == 3 | mode == 4
                    ext1 = ext1(k,:)
                    error(['makelist -> setexternal: ext1 must be a ' ...
                            'double or char ''RANDOM'' or ''OPTIMAL'''])
                end
            end
        end
        % Examine ext2
        if strcmp(upper(ext2(k,:)), 'RANDOM') | ...
            strcmp(upper(ext2(k,:)), 'RANDOM ')
            % Set second external angle randomly
            tempExt2(k,1) = randomangle(1, 'phi');
        elseif (mode == 3 | mode == 4) & strcmp(upper(ext2(k,:)), 'OPTIMAL')
            % Set source at zenith
            if ~isfield(Cordnt, 'LONG')
                error('makelist -> setexternal: Cordnt.LONG does not exist')
            end
            tempExt2(k,1) = Cordnt.LONG;
        else
            % Typecast second internal angle 
            tempExt2(k,1) = str2double(ext2(k,:));
            % Check for error
            if isnan(tempExt2(k,1))
                if mode == 1 | mode == 2
                    ext2 = ext2(k,:)
                    error(['makelist -> setexternal: ext2 must be a ' ...
                            'double or char ''RANDOM'''])
                elseif mode == 3 | mode == 4
                    ext2 = ext2(k,:)
                    error(['makelist -> setexternal: ext2 must be a ' ...
                            'double or char ''RANDOM'' or ''OPTIMAL'''])
                end                
            end
        end 
        % Examine ext3
        if strcmp(upper(ext3(k,:)), 'RANDOM') | ...
            strcmp(upper(ext3(k,:)), 'RANDOM ')
            % Set third external angle randomly
            tempExt3(k,1) = randomangle(1, 'psi');
        elseif (mode == 3 | mode == 4) & strcmp(upper(ext3(k,:)), 'OPTIMAL')
            % Set polarization angle to 22.5 deg (50-50 mix of h+ and hx)
            tempExt3(k,1) = pi/8;
        else
            % Typecast third internal angle
            tempExt3(k,1) = str2double(ext3(k,:));
            % Check for error
            if isnan(tempExt3(k,1))
                if mode == 1 | mode == 2
                    ext3 = ext3(k,:)
                    error(['makelist -> setexternal: ext3 must be a ' ...
                            'double or char ''RANDOM'''])
                elseif mode == 3 | mode == 4
                    ext3 = ext3(k,:)
                    error(['makelist -> setexternal: ext3 must be a ' ...
                            'double or char ''RANDOM'' or ''OPTIMAL'''])
                end
            end
        end
    end
    % Return determined external angles
    external = [tempExt1, tempExt2, tempExt3];
    
% If external was not read from a file
elseif mode == 5 | mode == 6 | mode == -2
    
    if length(varargin) >= 1
        nSim = varargin{1};
    else
        error(['makelist -> setexternal: Need to know number if external '...
                'angles to generate (nSim)'])
    end
    
    if strcmp(class(preExternal), 'char') % external is a string
        if strcmp(upper(preExternal), 'RANDOM')
            % Set all (ext1, ext2 & ext3) external angles randomly nSim
            % times
            external = [randomangle(nSim, 'x'), randomangle(nSim, 'phi'), ...
                    randomangle(nSim, 'psi')];
            % Return external angles
        elseif strcmp(upper(preExternal), 'OPTIMAL') & (mode == 6 | ...
                mode == -2)
            % Set source at xenith and polarzation angle to 22.5 deg (50-50
            % h+ and hx) nSim times
            if ~isfield(Cordnt, 'CODEC') | ~isfield(Cordnt, 'LONG')
                error(['makelist -> setexternal: Cordnt.CODEC or ' ...
                        'Cordnt.LONG does not exist'])
            end
            external = repmat([Cordnt.CODEC, Cordnt.LONG, pi/8], nSim, 1);
            % Return external angles
        elseif mode == 5
            external = preExternal
            error(['makelist -> setexternal: external must be 1x3 vector,'...
                ' struct or string ''RANDOM'''])
        elseif mode == 6 | mode == -2
            external = preExternal
            error(['makelist -> setexternal: external must be 1x3 vector,'...
                    ' struct or string ''RANDOM'' or ''OPTIMAL'''])
        end
    elseif strcmp(class(preExternal), 'double') % external is a double
        % Copy external angles nSim times
        external = repmat(preExternal, nSim, 1);
        % Return external angles
    elseif strcmp(class(preExternal), 'struct') % external is a struct
        if ~isfield(preExternal, 'x') | ~isfield(preExternal, 'phi') ...
                | ~isfield(preExternal, 'psi')
            external = preExternal
            error(['makelist -> setexternal: the external struct must '...
                    'have fields x, phi and psi'])
        end
        % Copy external angles nSim times
        external = repmat([preExternal.x, preExternal.phi, ...
                preExternal.psi], nSim, 1);
        % Return external angles
    else
        external = preExternal
        error(['makelist -> setexternal: Class type of external must be '...
                'double, struct or char'])
    end
    
end

% Check ranges on angles
check = find(abs(external(:,1)) > 1);
if ~isempty(check)
    ext1 = external(:,1)
    error(['makelist -> setexternal: The first external angle is out of '...
            'range: (-1 1)'])
end

check = find(external(:,2) < -pi | external(:,2) > pi);
if ~isempty(check)
    ext2 = external(:,2)
    error(['makelist -> setexternal: The second external angle is out of '...
        'range: (-pi pi)'])
end

check = find(external(:,3) < 0 | external(:,3) > 2*pi);
if ~isempty(check)
    ext3 = external(:,3)
    error(['makelist -> setexternal: The third external angle is out of ' ...
            'range: (0 pi)'])
end

return