classdef pcbFileRead < handle & matlab.mixin.CustomDisplay & matlab.mixin.SetGet & matlab.mixin.Copyable 
% pcbFileRead reads the filepath of the ODB data.
%
% P = pcbFileRead(filepath) creates an pcbFileRead object that can read 
% ODB files in the specified path and returns the properties related to 
% the imported pcb. 
%
% pcbFileRead properties:
%
%   FileName   - File path of the ODB data.
%   NumLayers  - Number of layers in the board.
%   MetalLayer - Index/position of the metal layer/s in the board.
%   DielectricLayer - Index/position of the dielectric layer in the board.
%   LayerHeight     - Height from the bottom to the respective layer in
%                     inch.
%   NumCadnets      - Total number of cadnets in the board.
%   NumPadStacks    - Total number of padstacks in the board.
%   NumComponents   - Total number of components in the board.
%   NumParts        - Total number of parts in the board.
%
% pcbFileRead methods:
%   
%   stackUp       - Returns the material info of the stack in the pcb w.r.t
%                   the layer/layers
%   cadnetList    - Returns the table with cadnet list in the pcb
%   componentList - Returns the table with component list in the pcb
%   padstackList  - Returns the table with padstack list in the pcb
%   partList      - Returns the table with part list in the pcb
%
%   
%   % Examples
%
%   % Example 1: 
%   % Create a pcbFileReader. 
%
%   % P = pcbFileReader(filepath)
%
%   % Example 2:
%   % Get the material info of the metal layer in the stack
%   
%   % s = stackUp(P,P.MetalLayer);
% 
%   % Example 2:
%   % Get the list of cadnets, components and parts in the pcb.
%   
%   % netList = cadnetList(P);
%   % compList = componentList(P);
%   % partL = partList(P);
%
%
%   Copyright 2023 The MathWorks, Inc.

    properties (SetObservable)
        % Filepath of the ODB file.
        FileName (1,:) char  {} = []       
    end

    properties(SetAccess=protected, GetAccess = public) 
        % Number of layers in the board.
        NumLayers
        % Position of the metal layer in the stack.
        MetalLayer
        % Position of the dielectric layer in the stack.
        DielectricLayer
        % Layer Height.
        LayerHeight
        % Number of Cadnet in the board.
        NumCadnets
        % Number of Padstack in the board.
        NumPadStacks
        % Number of components in the board.
        NumComponents
        % Number of parts in the board.
        NumParts
    end

    % properties(Access=protected)
    %     LayerShapes = []
    % end

    methods
        function obj = pcbFileRead(FileName)
            arguments
                FileName (1,:) char {mustBeFolder(FileName)}
            end
             obj.FileName = FileName;
        end
        
        function set.FileName(obj,propval)
            obj.FileName = propval; 
            ODBFileRead(obj);
        end

        function propVal = get.NumLayers(obj)
           [Ids,~] = getLayerInfo();
           propVal = numel(Ids);
        end

        function propVal = get.MetalLayer(obj)
           [~,layerName] = getLayerInfo();
           layerName = deblank(layerName);
           tf = arrayfun(@(x) strcmpi('dielectric',deblank(x)),string(layerName));
           Mid = ~(tf);
           MetalId = find(Mid(:,1)==1);
           propVal = MetalId(1:end,1)';
        end

        function propVal = get.DielectricLayer(obj)
            [~,layerName] = getLayerInfo();
            tf = arrayfun(@(x) strcmpi('dielectric',deblank(x)),string(layerName));
            Did = tf; DielecId = find(Did(:,1)==1);
            propVal = DielecId';
        end

        function propVal = get.LayerHeight(obj)
            dind = obj.DielectricLayer;
            mind = obj.MetalLayer;
            Lid = sort([dind,mind]);
            Thickness = cell2mat(arrayfun(@(x) getLayerThickness(x),int32(Lid),'UniformOutput',false));
            % % mil to inch conversion.
            Thickness = 0.001*Thickness;
            % % Inch to meter
            % Thickness = 0.0254*Thickness;
            temp = cumsum(Thickness);
            LHeight = max(temp) - temp;
            propVal = LHeight;
        end

        function propVal = get.NumComponents(obj)
            CompList   = getComponentNames();
            Ncomp = size(CompList,1);
            propVal = Ncomp;
        end

        function propVal = get.NumParts(obj)
            Partlist  = getPartNames();
            Npart     = size(Partlist,1);
            propVal   = Npart;
        end

        function propVal = get.NumPadStacks(obj)
            PadSlist    = getPadstackNames();
            NpadList    = size(PadSlist,1);
            propVal     = NpadList;
        end

        function propVal = get.NumCadnets(obj)
            CadnetList     = getCadnetNames();
            NCadL = length(CadnetList);
            propVal = NCadL;
        end

        function stack = stackUp(pobj,LayerNumber)
            % STACKUP returns the material info of the stack w.r.t the
            % layer/layers
            %
            % stack = stackUp(pobj) returns the table with material info
            % of the layer in the stack
            %
            % stack = stackUp(pobj,pobj.MetalLayer) returns the table 
            % with material info of all the metal layer in the stack
            %
            %   Input Arguments:
            %
            %       pobj        : pcbFileRead object.
            %       LayerName   : Position/Index of the layer in the stack.
            %                     LayerNumber is the positional argument
            %                     that accepts scalar or vector values.
            %  
            %   Output Arguments:
            %  
            %       stack : Returns the table with material info of the
            %       respective layer in the stack.

            % Copyright 2023 The MathWorks, Inc.

            arguments
                pobj (1,1) pcbFileRead;
                LayerNumber {mustBeNumeric,...
                    mustBeNonNan,mustBeFinite,mustBeInteger,...
                    mustBePositive,mustBeRange(pobj,LayerNumber)}= sort([pobj.MetalLayer,pobj.DielectricLayer]);
            end

            Lnum = LayerNumber;
            if ~isempty(Lnum)
                Lid = int32(Lnum)';
            end

            LayerNumber   = Lid;
            LayerName     = arrayfun(@(x) getLayerName(x),Lid,'UniformOutput',false);
            LayerType     = arrayfun(@(x) getLayerType(x),Lid,'UniformOutput',false);
            Material      = arrayfun(@(x) getLayerMaterial(x),Lid,'UniformOutput',false);
            Thickness     = 0.001*(cell2mat(arrayfun(@(x) getLayerThickness(x),Lid,'UniformOutput',false)));
            EpsilonR      = cell2mat(arrayfun(@(x) getLayerEr(x),Lid,'UniformOutput',false));
            LossTangent   = cell2mat(arrayfun(@(x) getLayerLossTangent(x),Lid,'UniformOutput',false));
            Conductivity  = cell2mat(arrayfun(@(x) getLayerConductivity(x),Lid,'UniformOutput',false));
            %SplitPlane    = cell2mat(arrayfun(@(x) getLayerSplitPlanePerimeter(x),Lid,'UniformOutput',false));
            stack = table(LayerNumber,LayerName,LayerType,Material,Thickness,EpsilonR,LossTangent,Conductivity);
        end

        function  netList = cadnetList(pobj)
            % CADNETList returns the list of the cadnets in the pcb.
            %
            % netList = cadnetList(pobj) returns the table with cadnet list
            % in the pcb.
            %
            %   Input Arguments:
            %
            %       pobj        : pcbFileRead object.
            %
            %   Output Arguments:
            %
            %       netList : Returns the table with cadnet list in the pcb.

            % Copyright 2023 The MathWorks, Inc.

            arguments
                pobj (1,1) pcbFileRead;
            end

            CadnetName     = getCadnetNames();
            CadnetName     = string(CadnetName);
            CadnetList     = arrayfun(@(x) char(deblank(x)),CadnetName,'UniformOutput',false);
            CadSize = size(CadnetList,1);
            Cid = 1:CadSize;
            NumPins        = cell2mat(arrayfun(@(x) getCadnetData(CadnetList{x}).numOfPins,Cid,'UniformOutput',false))';
            Length         = cell2mat(arrayfun(@(x) getCadnetData(CadnetList{x}).length,Cid,'UniformOutput',false))';
            CadnetIndex = Cid';
            netList = table(CadnetIndex,CadnetList,NumPins,Length);
        end

        function  padSlist = padstackList(pobj)
            % padstackList returns the list of the padStacks in the pcb.
            %
            % padSList = padstackList(pobj) returns the table with padstack
            % list in the pcb.
            %
            %   Input Arguments:
            %
            %       pobj        : pcbFileRead object.
            %
            %   Output Arguments:
            %
            %       padSlist   : Returns the table with padstack list
            %                    in the pcb.
            %

            % Copyright 2023 The MathWorks, Inc.

            arguments
                pobj (1,1) pcbFileRead;
            end

            PadSName     = getPadstackNames();
            PadSName     = string(PadSName);
            PadSList     = arrayfun(@(x) char(deblank(x)),PadSName,'UniformOutput',false);
            PadSiz = size(PadSList,1);
            Pid = 1:PadSiz;
            PadSIndex = Pid';
            padSlist = table(PadSIndex,PadSList);
        end


        function  Complist = componentList(pobj)
            % COMPONENTLIST returns the list of the components in the pcb.
            %
            % Complist = componentList(pobj) returns the table with
            % component list in the pcb.
            %
            %   Input Arguments:
            %
            %       pobj        : pcbFileRead object.
            %
            %   Output Arguments:
            %
            %       Complist : Returns the table with component list in the
            %                 pcb.

            % Copyright 2023 The MathWorks, Inc.

            arguments
                pobj (1,1) pcbFileRead;
            end
            CompName    = getComponentNames();
            CompName     = string(CompName);
            CompList     = arrayfun(@(x) char(deblank(x)),CompName,'UniformOutput',false);
            CompSiz = size(CompList,1);
            Cid = 1:CompSiz;
            CompIndex = Cid';
            Complist = table(CompIndex,CompList);
        end

        function  Plist = partList(pobj)
            % PARTLIST returns the list of the parts in the pcb.
            %
            % Partlist = partList(pobj) returns the table with
            % part list in the pcb.
            %
            %   Input Arguments:
            %
            %       pobj        : pcbFileRead object.
            %
            %   Output Arguments:
            %
            %       Plist      : Returns the table with part list in the
            %                    pcb.

            % Copyright 2023 The MathWorks, Inc.

            arguments
                pobj (1,1) pcbFileRead;
            end
            PartName    = getPartNames();
            PartName    = string(PartName);
            PartsList   = arrayfun(@(x) char(deblank(x)),PartName,'UniformOutput',false);
            PartSiz = size(PartsList,1);
            Pid = 1:PartSiz;
            PartIndex = Pid';
            
            Plist = table(PartIndex,PartsList);
        end
    end

    methods (Hidden)

        function mustBeRange(pobj,value)
            LayerNum = value;
            LayerMax = max([pobj.MetalLayer,pobj.DielectricLayer]);
            if all(LayerNum<=LayerMax)
                value = value;  %#ok<ASGSL>
            else
                eid = 'Value:notGreaterThan';
                msg = getString(message('rfpcb:rfpcberrors:LayerMax', num2str(LayerMax)));
                throwAsCaller(MException(eid,msg));
            end
        end
        function ODBFileRead(B)
            if (~isempty(B.FileName))
                odbReaderOpen(B.FileName); 

                % Check if .csv files are missing
                LoadStatus = getFileLoadStatus();
                FileStatus = struct2cell(LoadStatus);
                for i = 1:length(FileStatus)
                    if strcmpi(FileStatus{1},'false')
                        error(message('rfpcb:rfpcberrors:Insuffdata','pcbFileRead'));
                    end
                end
            end
        end
    end

    methods (Access=protected)
        function group = getPropertyGroups(obj)
            title = '';
            p = {'FileName','NumLayers','MetalLayer','DielectricLayer','LayerHeight','NumCadnets','NumPadStacks','NumComponents','NumParts'};
            group = objectProps(obj,p,title);
        end

        function group = objectProps(obj, propertyDisplayList,title)
            propList    = properties(obj);
            numProps    = max(size(propertyDisplayList));
            for i = 1:numProps
                if(strcmpi(propertyDisplayList{i},propList(strcmpi(propertyDisplayList{i},propList))))
                    antennaProps.(char(propertyDisplayList{i})) = get(obj,propertyDisplayList{i});
                end                
            end
            group = matlab.mixin.util.PropertyGroup(antennaProps,title);
        end   
    end
end



function mustBeFolder(value)
chfolder = isfolder(value);
 if chfolder
     value = value;  %#ok<NASGU,ASGSL>
 else
     eid = 'Value:notFolder';
     msg = 'Incorrect FileName, Expected file path.';
     throwAsCaller(MException(eid,msg));
 end
 end