function BodeRespObj = bodplot(RespObj,Systems,X,Y,PlotStyle)    
%BODPLOT Create a Bode Response Object for the Control System Toolbox

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

ni = nargin;

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

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

%---Initialize BodeRespObj
BodeFlag = isa(RespObj,'bodplot'); % 1 if adding to existing BODPLOT object
BodeMag = isempty(Y{2});           % 1 if plotting magnitude only
if BodeFlag
   BodeRespObj = RespObj;
   RespObj = BodeRespObj.response;
else
   Preferences = get(RespObj,'Preferences');
   BodeRespObj.FrequencyUnits = Preferences.FrequencyUnits;
   BodeRespObj.MagnitudeUnits = Preferences.MagnitudeUnits;
   BodeRespObj.PhaseUnits = Preferences.PhaseUnits;
   BodeRespObj.UnwrapPhase = Preferences.UnwrapPhase;
   PA = get(RespObj,'PlotAxes');
   if BodeMag
      set(PA,'XScale',Preferences.FrequencyScale,'YScale',Preferences.MagnitudeScale);
   else
      set(PA(1:2:end-1),'XScale',Preferences.FrequencyScale,'YScale',Preferences.MagnitudeScale);
      set(PA(2:2:end),  'XScale',Preferences.FrequencyScale,'YScale','linear');
   end
end

%---Access needed parent property values
%   RE: SystemNames already contains all the system names
PV = get(RespObj,{'PlotAxes','UIContextMenu','SystemNames'});
[LTIdisplayAxes,ContextMenu,SystemNames] = deal(PV{:});
if BodeFlag
   % Adding to existing BODPLOT object
   RH0 = get(RespObj,'ResponseHandles');
else
   % New BODPLOT object
   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

%---Set initial values for BODPLOT-specific properties
%---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',[]);
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));

%---Initialize ResponseHandles array
ResponseHandles = cell(NumNewSys,1);
MagData = Y{1};
PhData = Y{2};

if BodeMag
   % Bode magnitude plot
   for ctR=1:length(ResponseHandles)  % each new system
      % Get plot data
      Xarray = X{ctR};
      AllMagdata = MagData{ctR};
      SizeArray = size(Xarray);
      NumArray = prod(SizeArray);
      dflag = abs(Systems{ctR}.Ts);

      % 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 with system name
      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);
            for ctArray=1:NumArray
               Xdata = unitconv(Xarray{ctArray},'rad/sec',BodeRespObj.FrequencyUnits);
               Magdata = unitconv(AllMagdata{ctArray},'abs',BodeRespObj.MagnitudeUnits);

               %---Response line UserData
               LineUd = struct('System',NewSystemNames{ctR},'Input',ctin,...
                  'Output',ctout,'Array',rguihelper('ind2sub',SizeArray,ctArray));

               %---Magnitude
               RH{ctArray} = line(Xdata,squeeze(Magdata(ctout,ctin,:)),...
                  'Color',CC,'Marker',MM,'LineStyle',LL,'UserData',LineUd,...
                  'Tag','LTIresponseLines','DeleteFcn','delresp(gcbo)',...
                  'Visible','off','Parent',LTIdisplayAxes(ctout,ctin),...
                  'ButtonDownFcn','rguifcn(''showbox'',gcbf);');

               %---Only draw Nyquist line when it is at the end of the data
               if dflag>0
                  NyqFreq = unitconv(pi/dflag,'rad/sec',BodeRespObj.FrequencyUnits);
                  if abs(Xdata(end)-NyqFreq)<NyqFreq/10
                     % RE: make handle invisible to prevent LEGEND from picking it up
                     RH{ctArray}(2,1) = line([NyqFreq NyqFreq],[0 1],'Color','k','Linestyle','-',...
                        'Parent',LTIdisplayAxes(ctout,ctin),'HandleVis','off','HitTest','off',...
                        'Visible','off','Tag','NyquistLines');
                  end
               end
            end
            LineHandle{ctout,ctin} = RH;
         end
      end
      ResponseHandles{ctR} = LineHandle;
   end

   %---Set the BackgroundAxes labels
   BackAxLabels = {...
         'Title','Bode Magnitude Diagram',...
         'Ylabel',sprintf('Magnitude (%s)',BodeRespObj.MagnitudeUnits),...
         'Xlabel',sprintf('Frequency (%s)',BodeRespObj.FrequencyUnits)};

else
   % Full Bode plot
   for ctR=1:length(ResponseHandles)  % each new system
      % Initialize line UserData
      Xarray = X{ctR};
      AllMagdata = MagData{ctR};
      AllPhdata = PhData{ctR};
      SizeArray = size(Xarray);
      NumArray = prod(SizeArray);
      dflag = abs(Systems{ctR}.Ts);

      % 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:2:numout
            RH = cell(SizeArray);
            RH2 = cell(SizeArray);
            for ctArray=1:NumArray
               Xdata = unitconv(Xarray{ctArray},'rad/sec',BodeRespObj.FrequencyUnits);
               Magdata = unitconv(AllMagdata{ctArray},'abs',BodeRespObj.MagnitudeUnits);
               %---Wrap phase data if necessary, and convert to correct units
               Phdata = unitconv(AllPhdata{ctArray},'deg','rad');
               if strcmpi(BodeRespObj.UnwrapPhase,'off')
                  Phdata = mod(Phdata+pi,2*pi)-pi;
               end
               Phdata = unitconv(Phdata,'rad',BodeRespObj.PhaseUnits);

               %---Response line UserData
               LineUd = struct('System',NewSystemNames{ctR},'Input',ctin,...
                  'Output',ceil(ctout/2),'Array',rguihelper('ind2sub',SizeArray,ctArray));

               %---Magnitude
               RH{ctArray}(1,1)=line(Xdata,squeeze(Magdata(ceil(ctout/2),ctin,:)),...
                  'Color',CC,'Marker',MM,'LineStyle',LL,'UserData',LineUd,...
                  'Tag','LTIresponseLines','DeleteFcn','delresp(gcbo)',...
                  'Visible','off','Parent',LTIdisplayAxes(ctout,ctin),...
                  'ButtonDownFcn','rguifcn(''showbox'',gcbf);');

               %---Phase
               RH2{ctArray}(1,1)=line(Xdata,squeeze(Phdata(ceil(ctout/2),ctin,:)),...
                  'Color',CC,'Marker',MM,'LineStyle',LL,'UserData',LineUd,...
                  'Tag','LTIresponseLines','DeleteFcn','delresp(gcbo)',...
                  'Visible','off','Parent',LTIdisplayAxes(ctout+1,ctin),...
                  'ButtonDownFcn','rguifcn(''showbox'',gcbf);');

               %---Only draw Nyquist line when it is at the end of the data
               if dflag>0
                  NyqFreq = unitconv(pi/dflag,'rad/sec',BodeRespObj.FrequencyUnits);
                  if abs(Xdata(end)-NyqFreq)<NyqFreq/10
                     % RE: make handle invisible to prevent LEGEND from picking it up
                     RH{ctArray}(2,1)=line([NyqFreq,NyqFreq],[0 1],'Color','k','Linestyle','-',...
                        'Parent',LTIdisplayAxes(ctout,ctin),'HandleVis','off','HitTest','off',...
                        'Visible','off','Tag','NyquistLines');
                     RH2{ctArray}(2,1)=line([NyqFreq;NyqFreq],[0 1],'Color','k','Linestyle','-',...
                        'Parent',LTIdisplayAxes(ctout+1,ctin),'HandleVis','off','HitTest','off',...
                        'Visible','off','Tag','NyquistLines');
                  end
               end
            end
            LineHandle{ctout,ctin} = RH;
            LineHandle{ctout+1,ctin} = RH2;
         end
      end
      ResponseHandles{ctR} = LineHandle;
   end

   %---Set the BackgroundAxes labels
   BackAxLabels = {...
         'Title','Bode Diagram',...
         'Ylabel',sprintf('Phase (%s); Magnitude (%s)',BodeRespObj.PhaseUnits,BodeRespObj.MagnitudeUnits),...
         'Xlabel',sprintf('Frequency (%s)',BodeRespObj.FrequencyUnits)};
   
end

% Final touches...
if BodeFlag
   % Append data to existing BODPLOT object
   RespObj = pvset(RespObj,'UIContextMenu',ContextMenu,...
      'ResponseHandles',[RH0;ResponseHandles],BackAxLabels{:});
   BodeRespObj.PeakResponseValue = [BodeRespObj.PeakResponseValue;PeakRespVals];
   BodeRespObj.StabilityMarginValue = [BodeRespObj.StabilityMarginValue;MarginVals];
   BodeRespObj.AllStabilityMarginValue = [BodeRespObj.AllStabilityMarginValue;AllMarginVals];
   BodeRespObj.response = RespObj;

else
   %---No Grouping or I/O selection for SISO bode diagrams
   if numin==1 & numout==2-BodeMag
      set([ContextMenu.ChannelMenu,ContextMenu.GroupMenu.Main],'visible','off');
   end

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

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

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