classdef (ConstructOnLoad) SemanticModelChangedEventData < event.EventData
    % SemanticModelChangedEventData event data describing a semantic model
    % change to a pipeline in terms of additions, removals, and renames.
    properties
        Delta(:,5) table
    end

    methods
        function data = SemanticModelChangedEventData()
            Action       = bioinfo.pipeline.internal.SemanticModelChangedAction.empty(0,1);
            Model        = bioinfo.pipeline.internal.SemanticModelObject.empty(0,1);
            Parent       = bioinfo.pipeline.internal.SemanticModelObject.empty(0,1);
            Name         = string.empty(0,2);
            Value        = cell(0,2);
            data.Delta = table(Action, Model, Parent, Name, Value);
        end

        function rename(data, modelObj, parent, nameChange)
            arguments
                data
                modelObj(1,1) bioinfo.pipeline.internal.SemanticModelObject
                parent(1,1) bioinfo.pipeline.internal.SemanticModelObject
                nameChange(1,2) string
            end
            data.appendDelta("Renamed", modelObj, parent, nameChange);
        end

        function remove(data, modelObj, parent, oldName)
            arguments
                data
                modelObj(1,1) bioinfo.pipeline.internal.SemanticModelObject
                parent(1,1) bioinfo.pipeline.internal.SemanticModelObject
                oldName(1,1) string
            end
            data.appendDelta("Removed", modelObj, parent, [oldName, ""]);
        end

        function add(data, modelObj, parent, newName)
            arguments
                data
                modelObj(1,1) bioinfo.pipeline.internal.SemanticModelObject
                parent(1,1) bioinfo.pipeline.internal.SemanticModelObject
                newName(1,1) string
            end
            data.appendDelta("Added", modelObj, parent, ["", newName]);
        end

        function valueSet(data, inputObj, parentBlock, inputName, preValue, postValue)
            arguments
                data
                inputObj(1,1) bioinfo.pipeline.Input
                parentBlock(1,1) bioinfo.pipeline.Block
                inputName(1,1) string
                preValue
                postValue
            end
            data.appendDelta("ValueSet", inputObj, parentBlock, [inputName, inputName], preValue, postValue);
        end

        function invDelta = inverseDelta(obj)
            % Semantic deltas are invertible. In order to undo a change, we
            % produce the inverse delta table.

            originalDelta = obj.Delta;
            invDelta = originalDelta;

            % Invert Added/Removed
            invDelta.Action(originalDelta.Action == "Added") = "Removed";
            invDelta.Action(originalDelta.Action == "Removed") = "Added";

            % Invert Name & Value columns, which describe before and after
            % state for every Action type.
            invDelta.Name = fliplr(originalDelta.Name);
            invDelta.Value = fliplr(originalDelta.Value);
        end

    end

    methods(Access = private)
        function appendDelta(data, action, modelObj, parent, objNames, preValue, postValue)
            arguments
                data
                action(1,1) bioinfo.pipeline.internal.SemanticModelChangedAction
                modelObj(1,1) bioinfo.pipeline.internal.SemanticModelObject
                parent(1,1) bioinfo.pipeline.internal.SemanticModelObject
                objNames(1,2) string
                preValue = [];
                postValue = [];
            end

            data.Delta = [data.Delta; {action, modelObj, parent, objNames, {preValue, postValue}}];
        end


    end
end