classdef (Abstract) OwnerAccessor < handle
%OWNERACCESSOR defines an interface for classes that provide access to the
%*Owner property of various TargetRegions
%
%   This is an undocumented class. Its methods and properties are likely to
%   change without warning from one release to the next.

%   Copyright 2020-2021 The MathWorks, Inc.
    
    properties (Access = protected)
        TargetRegion (1,1);
    end
        
    methods (Static, Access = public)
        function owner = getOwner(implementation)
            accessor = rtw.pil.OwnerAccessor.create(implementation);
            owner = accessor.getOwner_Impl;
        end
            
        function setOwner(implementation, newOwner)
            accessor = rtw.pil.OwnerAccessor.create(implementation);
            accessor.setOwner_Impl(newOwner);
        end
    end
    
    methods (Access = protected)
        function owner = getOwner_Impl(this)
            ownerPropName = this.getPropertyName(this.TargetRegion);
            owner = this.TargetRegion.(ownerPropName);
        end
        
        function setOwner_Impl(this, newOwner)
            ownerPropName = this.getPropertyName(this.TargetRegion);
            this.TargetRegion.(ownerPropName) = newOwner;
        end
    end
    
    methods (Static, Access = private)
        function accessorObj = create(implementation)
            % factory method, returns the correct accessor for the given
            % implementation
            assert(~isempty(implementation), ...
                'Property access is not allowed when the object is empty.');
            
            if ismember(class(implementation), ...
                    {'rtw.connectivity.FIAdaptor', 'rtw.connectivity.SlFIAdaptor'})
                accessorObj = rtw.pil.FunctionInterfaceOwnerAccessor(implementation);
            else
                switch rtw.connectivity.CodeInfoUtils.class(implementation)
                    case 'BasicAccessFunctionExpression'
                        accessorObj = rtw.pil.BasicAccessFcnExpOwnerAccessor(implementation);
                    case {'ClassMethodExpression', ...
                           'StructExpression', ...
                           'ArrayExpression', ...
                           'PointerExpression'}
                        accessorObj = rtw.pil.BaseRegionOwnerAccessor(implementation);
                    case {'AutosarErrorStatus', ...
                          'AutosarIsUpdated', ...
                          'AutosarInterRunnable', ...
                          'AutosarMemoryExpression'}
                        accessorObj = rtw.pil.AutosarInterfacesOwnerAccessor(implementation);
                    case 'AutosarCalibration'
                        accessorObj = rtw.pil.AutosarCalibrationOwnerAccessor(implementation);
                    otherwise
                        accessorObj = rtw.pil.StandardOwnerAccessor(implementation);
                end
            end
        end

        function ownerPropName = getPropertyName(impl)
            % get the Owner property name for different classes
            switch class(impl)
                case {'coder.descriptor.Variable' ...
                        'coder.descriptor.PointerVariable' ...
                        'coder.descriptor.StructAccessorVariable' ...
                        'coder.descriptor.PointerExpression' ...
                        'coder.descriptor.CustomVariable'}
                    ownerPropName = 'VarOwner';
                case 'coder.descriptor.CustomExpression'
                    ownerPropName = 'ExprOwner';
                otherwise
                    ownerPropName = 'Owner';
            end
        end
    end
end
