classdef Component < Config & matlab.mixin.Copyable
% Component: Represents an abstraction layer for all components
%   Components standardize object construction, config and data loading
%
%   Constructor:
%       - Component: Creates an instance of the Component class.
%           Arguments:
%               - mission: Mission, mission object, used to find config
%               files
%               - varsIn: If present, data is read from this variable
%               instead of config file
%
%           Options:
%
%               - elementWise: 
%                   - if true, data is copied element-by-element
%                       into target class
%                   - if false, the loaded data substitutes target class

    properties(Abstract, Access = protected) 
        mission Mission
    end

    methods
        function obj = Component(mission, varsIn, options)
            % Component: Contains and manages all bays
            %
            %   Constructor:
            %       - Rocket: Creates an instance of the Rocket class.
            %           Loaded config: rocketConfig.m > rocket (for overrides)
            %           Loaded data: -
            %           Arguments:
            %               - mission: Mission, mission object
            %               - varIn: (optional) config source. Alternative to config.m
            %               file

            arguments (Input)
                mission Mission = Mission()
                varsIn = []
                options.elementWise logical = true
            end

            if isempty(mission.name)
                return;
            end
            
            if isempty(varsIn)
                varsIn = obj.getConfig(mission);
            end

            fileName = obj.configName;
            varName = obj.variableName;
            if isempty(varName)
                varName = strtok(fileName, 'C');
            end

            if ~isfield(varsIn, varName)
                error(['Class not found inside the config folder: %s\n' ...
                    'With name: %s\n' ...
                    'Check that the correct mission is set in your component ' ...
                    'and the config file is correct'], fileName, varName);
            end

            configObj = varsIn.(varName);

            if options.elementWise
                fields = configObj.getProperties('writable');
                for field = fields
                    if isempty([configObj.(field)]), continue; end
                    obj.(field) = configObj.(field);
                end
            else
                obj = configObj;
            end

            [obj.mission] = deal(mission);
        end
    end
    
    methods
        function m = getMission(obj)
            m = obj.mission;
        end
    end

    methods(Access = protected)
        function cp = copyElement(obj)
            fields = obj.getProperties('readable', NonCopyable = 0);
            cp = copyElement@matlab.mixin.Copyable(obj); %shallow copy of all elements

            for field = fields
                if isa(obj.(field), 'matlab.mixin.Copyable')
                    cp.(field) = copy(obj.(field));
                end
            end
        end

        function outputVariables = getConfig(obj, mission)
            fileName = obj.configName;
            filePath = mission.configPath;
            file = fullfile(filePath, fileName);

            if ~isfile(file)
                error(['File not found inside the config folder: %s\n' ...
                    'Check that the correct mission is set in your component ' ...
                    'and the config file exists'], fileName); 
            end

            variables = [who(); "variables"];
            run(file);
            loadedVariables = who();
            loadedVariables(ismember(loadedVariables, variables)) = [];

            outputVariables = struct();
            for i = 1:length(loadedVariables)
                outputVariables.(loadedVariables{i}) = eval(loadedVariables{i});
            end
        end
    end
end

