classdef StandaloneHDLPI < handle
    %This instance creates the HDLPropertyInspector Class
    %Creating an object of this class will Create the HDLPropertyInspector
    %for the selected block

%   Copyright 2022-2023 The MathWorks, Inc.

    properties
        Config;
        StandalonePropInspector;
        BlkObj;
        BlkHandle;
        propertySchema;
    end

    properties(Access = private)
        listener;
    end

    methods(Static)
        function instance = create(blockHandle)
            instance = StandaloneHDLPI.getInstance(blockHandle,true);
        end

        function refresh(blockHandle)
            hdlspi = StandaloneHDLPI.getInstance(blockHandle,false);
            if ~isempty(hdlspi)
                hdlspi.updateHDLPropertyInspector;
            end
        end

        function clear(blockHandle,all)
            if all
                StandaloneHDLPI.getInstance(blockHandle,false,clearAll=true);
            else
                StandaloneHDLPI.getInstance(blockHandle,false,clearSingle=true);
            end
        end

    end

    methods(Static,Access=private)
        function instance = getInstance(blockHandle,createNew,clear)
            arguments
                blockHandle 
                createNew 
                clear.clearAll = false
                clear.clearSingle = false
            end
            instance = containers.Map;
            persistent propInspectorMapStandalone

            if isempty(propInspectorMapStandalone)
                propInspectorMapStandalone = containers.Map;
            end

            if clear.clearAll && ~isempty(propInspectorMapStandalone)
                keys = propInspectorMapStandalone.keys;
                for i =1:propInspectorMapStandalone.length
                    pi=propInspectorMapStandalone(keys{i});
                    delete(pi.StandalonePropInspector);
                end
                remove(propInspectorMapStandalone,propInspectorMapStandalone.keys);

                return;
            end

            if clear.clearSingle
                remove(propInspectorMapStandalone,num2str(blockHandle));
                return;
            end

            

            if createNew
                propInspectorMapStandalone(num2str(blockHandle)) = StandaloneHDLPI(blockHandle);
            end

            if propInspectorMapStandalone.isKey(num2str(blockHandle))
                instance = propInspectorMapStandalone(num2str(blockHandle));
            end

        end
    end

    methods
        function obj = StandaloneHDLPI(blockHandle)
            %Constructor of the HDLPropertyInspector Class
            obj.BlkHandle = blockHandle;
            blockName = get_param(blockHandle,'Name');
            obj.BlkObj = get_param(blockHandle,'Object');
            obj.Config =struct('tag', ['standalone_hdlpi','_',blockName], 'mode', 'StandAlone',...
                'supportBatchApply', false, 'supportUndoRedo', true);
            obj.StandalonePropInspector = DAStudio.PropertyInspector(jsonencode(obj.Config));

            obj.propertySchema = HDLPropertySchema(obj.BlkObj);
            obj.StandalonePropInspector.updateSource(obj.Config.tag,obj.propertySchema.getPropertySchema);
            obj.StandalonePropInspector.show;

            obj.registerListener;

        end


    end

    methods(Access = private)
        function updateHDLPropertyInspector(obj,varargin)
            obj.propertySchema.updateSchema(obj.BlkObj);
            eventDispatcher = DAStudio.EventDispatcher;
            eventDispatcher.broadcastEvent('ObjectStateChangedEvent', obj.propertySchema, 'Refresh');
            obj.StandalonePropInspector.show;
        end

        function registerListener(obj)
            %Function to register the listeners
            mdlName = get_param(bdroot(obj.BlkHandle),'Name');
            md = get_param(mdlName,'Object');
            ed = DAStudio.EventDispatcher;
            L{1} = handle.listener(ed,'PropertyChangedEvent',...
                @obj.PropertyChangedListener);
            L{2} = event.listener(obj.StandalonePropInspector,'ObjectBeingDestroyed',...
                @obj.objectDestroyedListener);
            L{end+1} = event.listener(md, 'CloseEvent', ...
                @obj.onModelClose);
            L{end+1} = event.listener(md, 'ObjectChildRemoved', ...
                @(hSrc, ev)obj.blockDeleted(ev));
            if isempty(obj.listener)
                obj.listener = L;
            end


        end

        function PropertyChangedListener(obj,varargin)
            if isequal(obj.BlkObj,varargin{2}.Source)
                if strcmp(varargin{2}.String,'HDLData')
                    %Do nothing when 'HDLData' is changed
                    return;
                end
                obj.updateHDLPropertyInspector;
            else
                return;
            end
        end

        function objectDestroyedListener(obj,varargin)
            if ~isempty(obj.listener)
                for i=1:length(obj.listener)
                    delete(obj.listener{i});
                end
            end
            StandaloneHDLPI.clear(obj.BlkHandle,false);
        end

        function onModelClose(obj,~,~)
            StandaloneHDLPI.clear(obj.BlkHandle,true); %When model is closed, close all instances of StandaloneHDLPI
        end

        function blockDeleted(obj, ev)
            if obj.BlkObj == ev.Child
                StandaloneHDLPI.clear(obj.BlkHandle,false);
            end
        end

    end


end



% LocalWords:  hdlpi
