classdef surfacePin < handle & matlab.mixin.CustomDisplay & matlab.mixin.SetGet & matlab.mixin.Copyable
% surfacePin creates a surfacePin object that returns the data of the 
% surface pin.
%
% S = surfacePin(sobj,SurfInd) creates a pin object of a metalSurface w.r.t
% the surface index.
%
% surfacePin input arguments:
%   sobj            - metalSurface object.
%   SurfInd         - Index of the surface in a metalSurface. It accepts the
%                     scalar value.
%
% surfacePin properties:
%   NumPins           - Number of pins in a surface.
%
% Properties of rectangular pin
%   NumRectangle      - Number of rectangular pins
%   ShapeRectangle    - Shape of the rectangular pins
%   CenterRectangle   - Center of the rectangular pins in meter
%   Length            - Length of the rectangular pins in meter
%   Width             - Width of the rectangular pins in meter
%
% Properties of circular pin
%   NumCircle         - Number of circular pin
%   ShapeCircle       - Shape of the circular pin
%   CenterCircle      - Center of the circular pin in meter
%   HoleDiameter      - Hole diameter of the circular pin in meter
%   Diameter          - Pad diameter of the circular pin in meter
%
% surfacePin methods:  
%   shapes  - Returns the shape of the pins in a surface

% Copyright 2023 The MathWorks, Inc.


    properties(SetAccess = private, GetAccess = public)
        % Number of pins
        NumPins

        % Pin Rectangle
        % Number of rectangular pins
        NumRectangle
        % Shape of the rectangular pins
        %ShapeRectangle
        % Center of the rectangle in meter
        CenterRectangle
        % Length of the rectangle in meter
        Length
        % Width of the rectangle in meter
        Width

        % Pin Circle
        % Number of circular pins
        NumCircle
        % Shape of the circular pins
        %ShapeCircle
        % Center of the circle in meter
        CenterCircle
        % Drill hole diameter of pin in meter
        HoleDiameter
        % Pad diameter of pin in meter
        Diameter  
    end

    properties(Access=private)
        PrivateSurfaceInd
        PrivateLayerNumber
        PrivateCadnetName
        PrivateInputType
    end

    methods
        function obj = surfacePin(Sobj,SurfInd)
             arguments
                Sobj(1,1)  metalSurface
                SurfInd(1,1) {mustBeNumeric,...
                    mustBeNonNan,mustBeFinite,mustBeInteger,...
                    mustBePositive,mustBeValidNumber(Sobj,SurfInd)};
            end
            obj.PrivateInputType = Sobj.InputType;
            if strcmpi( obj.PrivateInputType,'Layer')
                obj.PrivateLayerNumber = Sobj.LayerNumber;
            elseif strcmpi( obj.PrivateInputType,'Cadnet')
                obj.PrivateCadnetName = Sobj.CadnetName;
            end
            obj.PrivateSurfaceInd = SurfInd;
        end
    end
    methods %-------Set/Get-------- %
        function SPinCnt = get.NumPins(obj)
            SPinCnt = SurfaceDataPin(obj,obj.PrivateSurfaceInd);
            SPinCnt = SPinCnt.NumPins;
            obj.NumPins = SPinCnt;
        end

         function SPinRecCnt = get.NumRectangle(obj)
             SPinRecCnt = SurfaceDataPin(obj,obj.PrivateSurfaceInd);
             SPinRecCnt = SPinRecCnt.NumPinRectangle;
             obj.NumRectangle = SPinRecCnt;
         end

        % function SPinPoly = get.ShapeRectangle(obj)
        %     [SPinPoly,~] = CreateSurfacePin(obj,obj.PrivateSurfaceInd);
        %     obj.ShapeRectangle = SPinPoly;
        % end

        function PinLocRec = get.CenterRectangle(obj)
            SPinData = SurfaceDataPin(obj,obj.PrivateSurfaceInd);
            PinLocRec = SPinData.CenterRectangle;
            obj.CenterRectangle = PinLocRec;
        end

         function PinRecLen = get.Length(obj)
            SPinData = SurfaceDataPin(obj,obj.PrivateSurfaceInd);
            PinRecLen = SPinData.Length;
            obj.Length = PinRecLen;
        end

        function PinRecWid = get.Width(obj)
            SPinData = SurfaceDataPin(obj,obj.PrivateSurfaceInd);
            PinRecWid = SPinData.Width;
            obj.Length = PinRecWid;
        end

        function SPinCirCnt = get.NumCircle(obj)
             SPinData = SurfaceDataPin(obj,obj.PrivateSurfaceInd);
             SPinCirCnt = SPinData.NumPinCircle;
            obj.NumCircle = SPinCirCnt;
        end

        % function SPinPoly = get.ShapeCircle(obj)
        %     % Need to add the implementation
        %     [~,SPinPoly] = CreateSurfacePin(obj,obj.PrivateSurfaceInd);
        %     %PinCnt = SPinData.NumPins;
        %     obj.ShapeCircle = SPinPoly;
        % end

        function PinLocCir = get.CenterCircle(obj)
            SPinData = SurfaceDataPin(obj,obj.PrivateSurfaceInd);
            PinLocCir = SPinData. CenterCircle;
            obj. CenterCircle = PinLocCir;
        end

        function PinDrillDia = get.HoleDiameter(obj)
            SPinData = SurfaceDataPin(obj,obj.PrivateSurfaceInd);
            PinDrillDia = SPinData.PinHoleDiameter;
            obj.HoleDiameter = PinDrillDia;
        end

        function PinDia = get.Diameter(obj)
            SPinData = SurfaceDataPin(obj,obj.PrivateSurfaceInd);
            PinDia = SPinData.PinDiameter;
            obj.Diameter = PinDia;
        end   
    end

    methods (Hidden)
        function SPinData = SurfaceDataPin(obj,SurfaceIndex)
            %  SurfaceDataPin  returns the data of the Pins w.r.t the surface in
            %  a layer

            %   Copyright 2023 The MathWorks, Inc.

            if strcmpi( obj.PrivateInputType,'Layer')
                % Get the Actual surface ID w.r.t layer
                Lid = obj.PrivateLayerNumber;
                % Get the actual surface Index in the data base
                % Logic to map the actual suface index w.r.t the layer
                Surf_LayerId = getLayerSurfaceId(int32(Lid));
            else
                Surf_LayerId = getCadnetSurfaceIndexList(obj.PrivateCadnetName)';
            end
            Sidx = SurfaceIndex;

            % Pinhole data
            PData = struct;
            pinCount = getSurfacePinCount(int32(Surf_LayerId(Sidx)));
            PData.NumPins = pinCount;

            PinLocRectangle = [];
            PinLocCircle = [];
            for pinIdx = 1 : pinCount
                pinData(pinIdx) = getSurfacePinData(int32(Surf_LayerId(Sidx)),int32(pinIdx));

                if pinData(pinIdx).diameter==0
                    %pinstr{pinIdx} = ['PinDataRectangle',num2str(pinIdx)];
                    %PinDataRectangle(pinIdx,:) =  [pinData(pinIdx).xCoord,pinData(pinIdx).yCoord,pinData(pinIdx).rectWidth,pinData(pinIdx).rectHeight];
                    PinLocRectangle(pinIdx,:) =  [pinData(pinIdx).xCoord,pinData(pinIdx).yCoord];
                    PLength(pinIdx,:) =  pinData(pinIdx).rectWidth;
                    PWidth(pinIdx,:)  =  pinData(pinIdx).rectHeight;
                else
                    %pinstr{pinIdx} = ['PinDataRectangle',num2str(pinIdx)];
                    %PinDataCircle(pinIdx,:) =  [pinData(pinIdx).xCoord,pinData(pinIdx).yCoord,pinData(pinIdx).diameter];
                    PinLocCircle(pinIdx,:) =  [pinData(pinIdx).xCoord,pinData(pinIdx).yCoord];
                    PinDiameter(pinIdx,:) =  pinData(pinIdx).diameter;
                    PinHoleDiameter(pinIdx,:) =  pinData(pinIdx).drillHoleDia;
                end
                % pinstr{pinIdx} = ['PinHoleData',num2str(pinIdx)];
                % PinHoleData = setfield(PinHoleData,pinstr{pinIdx},pinData);
            end
            if ~isempty(PinLocRectangle)
                Id = [];
                for i = 1:size(PinLocRectangle,1)
                    if all(PinLocRectangle(i,:)==0)
                        Id(end+1)=i;
                    end
                    if all(PLength(i,:)==0)
                        Id(end+1)=i;
                    end
                    if all(PWidth(i,:)==0)
                        Id(end+1)=i;
                    end
                end
                PinLocRectangle(Id,:) = [];
                PLength(Id,:) = [];
                PWidth(Id,:) = [];
                PData.NumPinRectangle = size(PinLocRectangle,1);
                PData.CenterRectangle = PinLocRectangle;
                PData.Length = PLength;
                PData.Width = PWidth;
            else
                PData.NumPinRectangle = 0;
                PData.CenterRectangle = [];
                PData.Length = [];
                PData.Width = [];
            end
            if ~isempty(PinLocCircle)
                Id = [];
                for i = 1:size(PinLocCircle,1)
                    if all(PinLocCircle(i,:)==0)
                        Id(end+1)=i;
                    end
                    if all(PinDiameter(i,:)==0)
                        Id(end+1)=i;
                    end
                    if all(PinHoleDiameter(i,:)==0)
                        Id(end+1)=i;
                    end
                end
                PinLocCircle(Id,:) = [];
                PinDiameter(Id,:) = [];
                PinHoleDiameter(Id,:) = [];
                PData.NumPinCircle = size(PinLocCircle,1);
                PData. CenterCircle = PinLocCircle;
                PData.PinDiameter = PinDiameter;
                PData.PinHoleDiameter = PinHoleDiameter;
            else
                PData.NumPinCircle = 0;
                PData. CenterCircle = [];
                PData.PinDiameter = [];
                PData.PinHoleDiameter = [];
            end
            SPinData = PData;
        end

        function [SurfPinRec,SurfPinCir] = CreateSurfacePin(obj,surfInd)
            % This function is used to create the pin polygon

            if strcmpi( obj.PrivateInputType,'Layer')
                % Get the Actual surface ID w.r.t layer
                Lid = obj.PrivateLayerNumber;
                Surf_LayerId = getLayerSurfaceId(int32(Lid))';
            else
                Surf_LayerId = getCadnetSurfaceIndexList(obj.PrivateCadnetName)';
            end
            surfIdx = Surf_LayerId(surfInd);

            % Get the pin count
            pinCount = getSurfacePinCount(int32(surfIdx));
            orig_state = warning('off','MATLAB:polyshape:boundary3Points');
            orig_state1 = warning('off','MATLAB:polyshape:repairedBySimplify');
            % Create the Pin poly with polyshape
            if ~(pinCount == 0)
                pinRectangleVertices = [nan, nan];
                pinCircleVertices = [nan, nan];
                separator = [nan,nan];
                for pinIdx = 1 : pinCount
                    pinData(pinIdx) = getSurfacePinData(int32(Surf_LayerId(surfInd)),int32(pinIdx));

                    if  pinData(pinIdx).diameter==0
                        % This function returns all the pin vertices(rec and cir)
                        [PinX, PinY, PinHoleX, PinHoleY] = getSurfacePinPolygonData(int32(surfIdx), int32(pinIdx));
                        pinVertices = [PinX(:), PinY(:)];
                        pinRectangleVertices = [pinRectangleVertices; separator; pinVertices];
                        % [sz2,~] = size(PinHoleX);
                        % if sz2 > 0
                        %     holeVertices = [PinHoleX(:), PinHoleY(:)];
                        %     pinRectangleVertices = [pinRectangleVertices; separator; holeVertices];
                        % end
                    else
                        % This function returns all the pin vertices(rec and cir)
                        [PinX, PinY, PinHoleX, PinHoleY] = getSurfacePinPolygonData(int32(surfIdx), int32(pinIdx));
                        pinVertices = [PinX(:), PinY(:)];
                        pinCircleVertices = [pinCircleVertices; separator; pinVertices];
                        [sz2,~] = size(PinHoleX);
                        if sz2 > 0
                            holeVertices = [PinHoleX(:), PinHoleY(:)];
                            pinCircleVertices = [pinCircleVertices; separator; holeVertices];
                        end
                    end
                end
                PinRectangle = polyshape(pinRectangleVertices(:,1),pinRectangleVertices(:,2),"KeepCollinearPoints",true);
                PinCircle = polyshape(pinCircleVertices(:,1),pinCircleVertices(:,2),"KeepCollinearPoints",true);
                if ~isempty(PinRectangle.Vertices)
                    SurfPinRec = antenna.Polygon('Vertices',PinRectangle.Vertices);
                else
                    SurfPinRec = [];
                end
                if ~isempty(PinCircle.Vertices)
                    SurfPinCir = antenna.Polygon('Vertices',PinCircle.Vertices);
                else
                    SurfPinCir = [];
                end
            else
                SurfPinRec = [];
                SurfPinCir = [];
            end
            warning(orig_state1);
            warning(orig_state);
        end        
    end

    methods
        function S = shapes(obj)
            %shapes returns the shape of the pins polygon in a surfaces.
            %
            % S = shapes(obj) returns the shapes of pins in a surfaces.
            %

            % Copyright 2023 The MathWorks, Inc.

            surfInd = obj.PrivateSurfaceInd;
            [~,PinCircle] = CreateSurfacePin(obj,surfInd);
            if ~isempty(PinCircle)
            PinCircle.Name = 'PinCircle';
            end
            [PinRectangle,~] = CreateSurfacePin(obj,surfInd);
            if ~isempty(PinRectangle)
            PinRectangle.Name = 'PinRectangle';
            end
            Spoly = [PinCircle,PinRectangle];

            if ~isempty(Spoly)
                S = struct;
                for i = 1:length(Spoly)
                    polystr{i} = Spoly(i).Name;
                    S = setfield(S,polystr{i},Spoly(i));
                end
            else
                S = [];
            end
        end
    end

    methods (Access=protected)
        function group = getPropertyGroups(obj)
            % Full "show details" form of command-line display

            % PinDataRectangle
            % PinDataCircle

            % INITIAL / uncategorized
            %group = matlab.mixin.util.PropertyGroup(s,'');
            title = '';
            plist = {'NumPins'};
            group = matlab.mixin.util.PropertyGroup(plist,title);
            % PinDataRectangle
            plist = { ...
                'NumRectangle'
                'CenterRectangle'
                'Length'
                'Width'};
            group(end+1) = matlab.mixin.util.PropertyGroup(plist,'PinDataRectangle: ');

            % PinDataCircle
            plist = { ...
                'NumCircle'
                'CenterCircle'
                'HoleDiameter'
                'Diameter'};
            group(end+1) = matlab.mixin.util.PropertyGroup(plist,'PinDataCircle:');
        end

        function props = getObjectProperties(obj)
            G = getPropertyGroups(obj);
            props = fields(G.PropertyList);
        end

    end
end
function mustBeValidNumber(SurfObj,value)
SurfaceInd = value;
SurfaceIndExp = SurfObj.SurfaceInfo.SurfaceIndex;
if any(SurfaceInd==SurfaceIndExp)
    value = value;  %#ok<ASGSL>
else
    eid = 'Value:notValid';
    msg = getString(message('rfpcb:rfpcberrors:SurfaceIndex',num2str(SurfaceIndExp')));
    throwAsCaller(MException(eid,msg));
end
end