function NyqRespObj = nyplot(RespObj,Systems,X,Y,PlotStyle);
%NYPLOT Create a Nyquist Response Object for the Control System Toolbox

%   Authors: Karen Gondoly, 2-17-98
%   Revised: Adam W. DiVergilio, 11-99
%   Copyright 1986-2000 The MathWorks, Inc. 
%   $Revision: 1.29 $  $Date: 2000/06/19 21:02:56 $

ni = nargin;

%---Properties
NyqRespObj = struct(...
   'Frequency',[],...
   'FrequencyUnits','',...
   'MagnitudeUnits','',...
   'PhaseUnits','',...
   'PeakResponse','off',...
   'PeakResponseValue',[],...
   'StabilityMargin','off',...
   'StabilityMarginValue',[],...
   'AllStabilityMargin','off',...
   'AllStabilityMarginValue',[]);

%---Return cases (ni==0,1)
switch ni
case 0
   RespObj = response;
   NyqRespObj = class(NyqRespObj,'nyplot',RespObj);
   return
case 1
   if ~isa(RespObj,'response')
      error('Invalid Response Object passed to NYPLOT')
   elseif isa(RespObj,'nyplot')
      NyqRespObj = RespObj;
   else
      NyqRespObj = class(NyqRespObj,'nyplot',RespObj);
   end
   return
end

%---Initialize NyqRespObj
NyqFlag = isa(RespObj,'nyplot');
if NyqFlag
   NyqRespObj = RespObj;
   RespObj = NyqRespObj.response;
else
   Preferences = get(RespObj,'Preferences');
   NyqRespObj.FrequencyUnits = Preferences.FrequencyUnits;
   NyqRespObj.MagnitudeUnits = Preferences.MagnitudeUnits;
   NyqRespObj.PhaseUnits = Preferences.PhaseUnits;
   set(get(RespObj,'PlotAxes'),'XScale','linear','YScale','linear');
end

%---Access needed parent property values
PV = get(RespObj,{'PlotAxes','UIContextMenu','SystemNames'});
[LTIdisplayAxes,ContextMenu,SystemNames] = deal(PV{:});
if NyqFlag
   RH0 = get(RespObj,'ResponseHandles');
else
   RH0 = {};
end

%---Get dimension info and names of new systems
[numout,numin] = size(LTIdisplayAxes);
NumOldSys = length(RH0);                      % number of existing systems
NewSystemNames = SystemNames(NumOldSys+1:end);
NumNewSys = length(NewSystemNames);           % number of added systems

%---Assign empty system names. This is how the code knows it needs to
%----Calculate the Plot Options for this particular system
PeakRespVals = struct('System',cell(NumNewSys,1),...
   'Frequency',[],'Peak',[],'ResponseAtPeak',[]);
MarginVals = struct('System',cell(NumNewSys,1),...
   'Stable',[],'GainMargin',[],'GMFrequency',[],'PhaseMargin',[],'PMFrequency',[]);
AllMarginVals = struct('System',cell(NumNewSys,1),...
   'Ts',cell(NumNewSys,1),'Margins',cell(NumNewSys,1));

% Draw Real/Imag axes lines
% RE: Do it here to make them lowest in the HG stack
XColor = get(LTIdisplayAxes(1),'XColor');
YColor = get(LTIdisplayAxes(1),'YColor');
XaxisLines = zeros(numout,numin);
YaxisLines = zeros(numout,numin);
for ctAx=1:numin*numout
   XaxisLines(ctAx) = line([NaN NaN],[0 0],'LineStyle',':','Color',YColor,'HitTest','off',...
      'HandleVis','off','Parent',LTIdisplayAxes(ctAx),'Tag','PZxaxisLine');
   YaxisLines(ctAx) = line([0 0],[NaN NaN],'LineStyle',':','Color',XColor,'HitTest','off',...
      'HandleVis','off','Parent',LTIdisplayAxes(ctAx),'Tag','PZyaxisLine');
end

% Draw critical points
Critical = zeros(numout,numin);
for ctAx=1:numin*numout
   Critical(ctAx) = line(-1,0,'Color','r',...
      'Parent',LTIdisplayAxes(ctAx),'Marker','+',...
      'Visible','off','Tag','ExtraNyquist','HitTest','off'); %,'LineWidth',2);
end

%---Initialize ResponseHandles array and LTIresponseLine's UserData
ResponseHandles = cell(NumNewSys,1);

for ctR=1:length(ResponseHandles)  % each new system
    % Get plot data
    Yarray = Y{ctR};
    SizeArray = size(Yarray);
    NumArray = prod(SizeArray);
    
    % Get the style and legend
    Style = struct2cell(PlotStyle(ctR));
    [CC,LL,MM,LegendStr] = deal(Style{:});
    if NumArray>1
        ArrayDimsStr = sprintf('%dx',SizeArray);
        LegendStr = sprintf('%s array: %s',ArrayDimsStr(1:end-1),LegendStr);
    end
    
    %---Add legend to system name for new systems
    set(ContextMenu.Systems.Names(NumOldSys+ctR),...
        'Label',sprintf('%s (%s)',NewSystemNames{ctR},LegendStr),...
        'ForegroundColor',CC)
    
    %---Generate plot and store handles
    LineHandle = cell(numout,numin);
    for ctin=1:numin
        for ctout=1:numout
            RH = cell(SizeArray);
            Extras = [Critical(ctout,ctin);XaxisLines(ctout,ctin);YaxisLines(ctout,ctin)];
            
            for ctArray=1:NumArray
                Re = real(Yarray{ctArray});
                Im = imag(Yarray{ctArray});
                X{ctR}{ctArray} = unitconv(X{ctR}{ctArray},'rad/sec',NyqRespObj.FrequencyUnits);
                RH{ctArray} = zeros(5,1);
                
                % Response lines
                LineUd = struct('System',NewSystemNames{ctR},'Input',ctin,...
                    'Output',ctout,'Array',rguihelper('ind2sub',SizeArray,ctArray),'Sign',[]);
                LineUd.Sign = 1;   % Positive frequencies
                RH{ctArray}(1) = line(squeeze(Re(ctout,ctin,:)),squeeze(Im(ctout,ctin,:)),...
                    'Color',CC,'Tag','LTIresponseLines','DeleteFcn','delresp(gcbo)',...
                    'ButtonDownFcn','rguifcn(''showbox'',gcbf);',...
                    'Marker',MM,'LineStyle',LL,'Parent',LTIdisplayAxes(ctout,ctin),...
                    'Visible','off','UserData',LineUd);
                LineUd.Sign = -1;  % Negative frequencies
                RH{ctArray}(2) = line(squeeze(Re(ctout,ctin,:)),-squeeze(Im(ctout,ctin,:)),...
                    'Color',CC,'Tag','LTIresponseLines',...
                    'ButtonDownFcn','rguifcn(''showbox'',gcbf);',...
                    'Marker',MM,'LineStyle',LL,'Parent',LTIdisplayAxes(ctout,ctin),...
                    'Visible','off','UserData',LineUd);
                
                % Arrows
                RH{ctArray}(3) = patch([NaN NaN NaN],[NaN NaN NaN],CC,...
                    'Parent',LTIdisplayAxes(ctout,ctin),...
                    'Visible','off','HitTest','off','Tag','NyquistArrow',...
                    'EdgeColor',CC,'UserData',1);
                RH{ctArray}(4) = patch([NaN NaN NaN],[NaN NaN NaN],CC,...
                    'Parent',LTIdisplayAxes(ctout,ctin),...
                    'Visible','off','HitTest','off','Tag','NyquistArrow',...
                    'EdgeColor',CC,'UserData',-1);
             
                % Add critical point and background lines
                % REVISIT: should be stored independently!
                RH{ctArray}(5:7) = Extras;
            end
            LineHandle{ctout,ctin} = RH;
        end
    end
    ResponseHandles{ctR} = LineHandle;
end

%---Set the BackgroundAxes labels
BackAxLabels = {...
      'Title','Nyquist Diagram',...
      'Ylabel','Imaginary Axis',...
      'Xlabel','Real Axis'};

if NyqFlag
   % Append data to existing NYPLOT object
   RespObj = pvset(RespObj,'UIContextMenu',ContextMenu,...
      'ResponseHandles',[RH0;ResponseHandles],...
      BackAxLabels{:});
   NyqRespObj.Frequency = [NyqRespObj.Frequency,X];
   NyqRespObj.PeakResponseValue = [NyqRespObj.PeakResponseValue;PeakRespVals];
   NyqRespObj.StabilityMarginValue = [NyqRespObj.StabilityMarginValue;MarginVals];
   NyqRespObj.AllStabilityMarginValue = [NyqRespObj.AllStabilityMarginValue;AllMarginVals];
   NyqRespObj.response = RespObj;
else
   % Add extra zoom options
   ContextMenu.ZoomMenu.ZoomTight = uimenu(ContextMenu.ZoomMenu.Main,...
      'label','Tight','ForegroundColor',CC,'Separator','on',...
      'Callback',['menufcn(''zoomcallback'')']);
   ContextMenu.ZoomMenu.ZoomCritical = uimenu(ContextMenu.ZoomMenu.Main,...
      'label','On (-1,0)','ForegroundColor',CC,...
      'Callback',['menufcn(''zoomcallback'')']);

   %---Add Characteristics menu
   ContextMenu.PlotOptions.PeakResponse = uimenu(ContextMenu.PlotOptions.Main,...
      'label',xlate('Peak Response'),...
      'Callback',['menufcn(''togglepeak'')']);

   RespObj = pvset(RespObj,'ResponseHandles',ResponseHandles,...
      'UIContextMenu',ContextMenu,BackAxLabels{:});
   NyqRespObj.Frequency = X;
   NyqRespObj.StabilityMarginValue = MarginVals;
   NyqRespObj.AllStabilityMarginValue = AllMarginVals;
   NyqRespObj.PeakResponseValue = PeakRespVals;
   NyqRespObj = class(NyqRespObj,'nyplot',RespObj);
end

%---Update HG pointer to Response Object
builtin('set',ContextMenu.Main,'userdata',NyqRespObj)
