function validReq = linearizeInput(self,label)
%LINEARIZEINPUT  Specify inputs to linearized model.
%
%   LINEARIZEINPUT and LINEARIZEOUTPUT are used in conjunction with
%   LINEARIZE to extract sparse linear models from structural PDE models.
%
%   LINEARIZEINPUT(pdemodel,LABELSTR) adds inputs for the load or
%   constraint with label LABELSTR. These inputs represent the x,y,z
%   coordinates of a uniform load or displacement at this boundary. You
%   must first attach the label LABELSTR to some displacement constraint
%   (structuralBC), external load (structuralBoundaryLoad), or body load
%   (structuralBodyLoad),
%
%   IN = LINEARIZEINPUT(...) returns a structure IN with the linearization
%   input description.
%
%   See also pde.StructuralModel/linearizeOutput, pde.StructuralModel/linearize,
%            pde.StructuralModel/structuralBC, pde.StructuralModel/structuralBoundaryLoad,
%            pde.StructuralModel/structuralBodyLoad.

%    Copyright 2021-2022 The MathWorks, Inc.

arguments
    self pde.StructuralModel
    label {mustBeTextScalar}
end

userReq=label;

if ~isempty(self.BoundaryConditions)
    numBC=numel(self.BoundaryConditions.StructuralBCAssignments);
else
    numBC=0;
end

if ~isempty(self.BodyLoads)
    numLoads=numel(self.BodyLoads.BodyLoadAssignments);
else
    numLoads=0;
end

if isequal(numBC,0) && isequal(numLoads,0)
    error(message('pde:linearize:NonExistingLabel',userReq));
elseif ~isequal(numBC,0) && isequal(numLoads,0)

    activeBC=findStructuralBC(self.BoundaryConditions,'Label',userReq);
    bc=validateBC(activeBC);
    [labelReq,validReq]=setLabels(bc,self,userReq);

elseif isequal(numBC,0) && ~isequal(numLoads,0)

    sbl=findBodyLoad(self.BodyLoads,'Label',userReq);
    bc=validateBC(sbl);
    [labelReq,validReq]=setLabels(bc,self,userReq);
else
    bc=self.BoundaryConditions;
    sbl=self.BodyLoads;

    %Assume the label exist in both BC and boundary loads
    bcFound  = true;
    loadFound = true;

    %If the label doesn't exist in BC records, set bcFound to false.
    try
        activeInput=findStructuralBC(bc,'Label',userReq);
    catch ME
        if strcmp(ME.identifier,'pde:linearize:NonExistingLabel')
            bcFound=false;
        end
    end

    % If the label doesn't exist in boundary load records, set loadFound to false.
    try
        activeInput=findBodyLoad(sbl,'Label',userReq);
    catch ME
        if strcmp(ME.identifier,'pde:linearize:NonExistingLabel')
            loadFound=false;
        end
    end

    %Error if the label exists in both BC and boundary load
    if bcFound && loadFound
        error(message('pde:linearize:StructuralLabel',userReq));
    elseif ~(bcFound || loadFound)
    %Error if the label is not found in either BC or heat source
        error(message('pde:linearize:NonExistingLabel',userReq));
    else
    %Valid case if the label exists in either BC or heat source
        bc=validateBC(activeInput);
        [labelReq,validReq]=setLabels(bc,self,userReq);
    end
end

self.LinearizeInputs=labelReq;
end

function [labelReq,validReq]=setLabels(bc,self,userReq)

labelReq=self.LinearizeInputs;
validReq=struct('RegionType',bc.RegionType,'RegionID',bc.RegionID,...
    'Label',bc.Label);
if isempty(labelReq)
    labelReq= validReq;
else
    if any(ismember({labelReq.Label},userReq))
        error(message('pde:linearize:RepeatedInput',userReq));
    end
    labelReq(end+1)=validReq;
end
end

function bc=validateBC(activeBC)
if isprop(activeBC,'TranslationalStiffness')
    if ~isempty(activeBC.TranslationalStiffness)
        error(message('pde:linearize:nonSupportedNVPairs','TranslationalStiffness'));
    end

    fh=[isa(activeBC.Displacement,'function_handle'),isa(activeBC.XDisplacement,'function_handle'),...
        isa(activeBC.YDisplacement,'function_handle'),isa(activeBC.ZDisplacement,'function_handle'),...
        isa(activeBC.Pressure,'function_handle') isa(activeBC.Force,'function_handle'),...
        isa(activeBC.SurfaceTraction,'function_handle')];
    NV={'Displacement','XDisplacement','YDisplacement','ZDisplacement',...
        'Pressure','Force','SurfaceTraction'};
    if any(fh)
        NV=NV(fh);
        error(message('pde:linearize:nonConstantVal',NV{:}));
    end
elseif isprop(activeBC,'GravitationalAcceleration')
    invalidNVPair={'AngularVelocity','Temperature'};
    exist=[~isempty(activeBC.AngularVelocity) ~isempty(activeBC.Temperature)];
    if any(exist)
        idx=find(exist);
        invalidNVPair=invalidNVPair{idx(1)};
        error(message('pde:linearize:nonSupportedNVPairs',invalidNVPair));
    end
end
bc=activeBC;
end

