function [RespObj,varargout]=ltiplot(PlotType,sys,varargin)
%LTIPLOT Plot an LTI system response without opening an LTI Viewer.
%   LTIPLOT(PLOTTYPE,SYS) plots the type of LTI system response
%   indicated by the string PLOTTYPE (e.g. 'step','bode') for
%   each LTI system in the cell array SYS. (For a single system, SYS
%   does not have to be a cell array.) The result will be an array of 
%   plots, one for each I/O channel, on the current axis.
%
%   LTIPLOT(PLOTTYPE,SYS,H,Y,X) uses the response data in Y and X
%   when plotting the response.  For 'impulse','sigma','nyquist' and 'nichols' 
%   Y and X are cell arrays containing the Y and X-axis data for each system 
%   in SYS.  For 'bode', each cell of Y should, in turn, be the cell array
%   [{MAGNITUDE},{PHASE}]. For 'step', each cell of Y should be the cell array 
%   [{AMPLITUDE},{DCGAIN}].
%
%   LTIPLOT(PLOTTYPE,SYS,H,Y,X,PlotStyle) passes a Nx3 cell array of colors,
%   linestyles, and markers for each system.

%---Expanded for Context Menu applications
%   RESPOBJ=LTIPLOT(...) returns the handle of the resulting Response Object.
%
%   [RespObj] = ...
%       LTIPLOT(PLOTTYPE,SYS,R,Y,X,PlotStyle,'PropertyName',PropertyValue) 
%       allows other properties of the response object to be set. 
%
%   Supported properties include:
%       1) 'SystemNames': A cell array of length SYS, containing the names
%              to use in the Systems context menu. (Default names: {'sys#'})
%       2) 'SystemVisibility': A cell array of length SYS indicating if the
%              system's plot should be visible {'on'} or invisible ('off').
%       3) 'SelectedChannels': A matrix of size(SYS) containing ones and zeros 
%              indicating which I/O channels are plotted ({1}=visible, 0=invisible)
%       4) 'SelectedModels': A cell array of size(SYS) where each cell contains
%              an ND array of ones and zeros indicating which models of the LTI 
%              array are plotted ({1}=visible, 0=invisible)
%       5) 'AxesGrouping': String indicating the grouping preference for the
%              Response axes ({'none'},'inputs','outputs','all')

%   Author(s): Karen Gondoly, 9-30-96
%   Copyright 1986-2000 The MathWorks, Inc. 
%   $Revision: 1.42 $  $Date: 2000/08/02 18:35:03 $

ni=nargin;
if ni<2 | ni==4,
   error('Wrong number of input arguments')
end

%---Process input arguments
if ~iscell(sys);
   sys = {sys};
end
nsys = length(sys);

%---Increase number of rows in Response Object for Magnitude/Phase plots
[NumRows,NumColumns]=size(sys{1});
switch PlotType,
case 'bode';
   NumRows=NumRows*2;
case 'margin',
   NumRows=2;
   NumColumns=1;
case {'sigma';'pzmap';'rlocus'};
   NumRows=1;
   NumColumns=1;
case {'lsim';'initial'},
   NumColumns=1;
end

if ni>2,
   BackAx=varargin{1};
   if ~ishandle(BackAx) | ~strcmp('axes',get(BackAx,'type')),
      % Need to update if Response Plots become HG Objects
      error('An invalid axes handle was passed to LTIPLOT.');
   elseif isempty(BackAx),
      BackAx=gca;
   end
else
   BackAx=gca;
end % if/else ni>2

%---If the BackAx is an LTIDisplayAxes, get its parent
if strcmp(get(BackAx,'Tag'),'LTIdisplayAxes'),
   udax=get(BackAx,'UserData');
   BackAx=udax.Parent;
end

% X and Y data
if ni>3,
   Ydata = varargin{2};
   Xdata = varargin{3};
else
   Xdata = cell(nsys,1);
   Ydata = cell(nsys,1);
end

% Extra arguments
SystemNames = cell(nsys,1); 
SystemNames(:) = {''};
SelectChan = []; 
ModelVis = []; 
SysVis = []; % Use Defaults
if ni>6,
   Pnames = varargin(5:2:end);
   Pvalues = varargin(6:2:end);
   if ~isequal(length(Pnames),length(Pvalues)),
      error('Property names and values must be entered in pairs');
   end
   
   %---Remove properties that will be set as part of InitData
   SysNameFlag = find(strncmpi('systemnames',Pnames,11));
   if ~isempty(SysNameFlag),
      SystemNames = cellstr(Pvalues{SysNameFlag});
      SystemNames = SystemNames(:); % Make sure it's a column vector
   end
   ChannelFlag = find(strncmpi('selectedc',Pnames,9));
   if ~isempty(ChannelFlag), 
      SelectChan = Pvalues{ChannelFlag}; 
   end
   ModelFlag = find(strncmpi('selectedm',Pnames,9));
   if ~isempty(ModelFlag), 
      ModelVis = Pvalues{ModelFlag}; 
   end 
   SysVisFlag = find(strncmpi('systemvis',Pnames,9));
   if ~isempty(SysVisFlag), 
      SysVis = Pvalues{SysVisFlag}; 
   end 
   RemoveInd = [SysNameFlag,ChannelFlag,ModelFlag,SysVisFlag];
   varargin(4+[RemoveInd,RemoveInd+1])=[];
end

%---Determine input and output labels
[inNames,outNames] = respmrgname(sys{:}); % Get common I/O names

%---Create response object, taking NextPlot state into account
L = findobj(BackAx,'Tag','BackgroundResponseObjectLine');
if isempty(L), 
   %---BackAx does not contain any response plot. 
   %---Need some protection when menus/controls are associated with the figure/axis?
   % Rid BackAx from any legends
   legend(BackAx,'off')
   % Attach response object to BackAx
   RespObj = response(NumRows,NumColumns,BackAx,PlotType,SystemNames,inNames,outNames);
   HoldFlag = 0;
   NumOldSys = 0;
else
   %---Background axes already contains a Response Object
   RespObj = get(get(L,'UserData'),'UserData');
   %---Set axes hold state and update or clear RespObj 
   try
      [RespObj,HoldFlag,NumOldSys] = ...
         nextplot(RespObj,NumRows,NumColumns,PlotType,SystemNames,inNames,outNames);
   catch
      error(lasterr)
   end
end 

%---Assign non empty system names, and store names in Systems menu
RespObj = namesys(RespObj);

%---Set plot styles
PlotStyle = struct('Color',cell(nsys,1),'LineStyle',[],'Marker',[],'Legend',[]);
if ni>5,
   if strcmp(PlotType,'margin')   
      %---In the case of Margin, the sixth input argument is reserved for
      %-----inputing the margins. Margin can not be called with a plot string argument
      %---Remember to convert the gain margin to dB
      MarginData = varargin{4};
      MarginVals = struct('System',sys,...
         'GainMargin',{20*log10(MarginData(1))},...
         'GMFrequency',{MarginData(3)},...
         'PhaseMargin',{MarginData(2)},...
         'PMFrequency',{MarginData(4)});
   elseif ~isempty(varargin{4})
      PlotStyle = varargin{4};  
   end
end 
PlotStyle = setstyle(RespObj,PlotStyle,NumOldSys);

   
%---Pull out response properties for optimal speed
AllRespProps = get(RespObj,'undocumented');
BackAx = AllRespProps.BackgroundAxes;
ContextMenu = AllRespProps.UIContextMenu;


%---Create response-specific child objects
switch PlotType
case 'step',
   %---Pass data to STEPPLOT to make a step object
   RespObj = stepplot(RespObj,sys,Xdata,Ydata,PlotStyle);
   
case 'impulse'
   RespObj = impplot(RespObj,sys,Xdata,Ydata,PlotStyle);
   
case 'initial',
   RespObj = icplot(RespObj,sys,Xdata,Ydata,PlotStyle);
   
case 'lsim',
   RespObj = lsimplot(RespObj,sys,Xdata,Ydata,PlotStyle);
   
case {'bode','bodemag'}
   RespObj = bodplot(RespObj,sys,Xdata,Ydata,PlotStyle);
   
case 'margin',
   RespObj = margplot(RespObj,sys,Xdata,Ydata,PlotStyle,MarginVals);   
   
case 'nyquist',
   RespObj = nyplot(RespObj,sys,Xdata,Ydata,PlotStyle);
   
case 'nichols',
   RespObj = nicplot(RespObj,sys,Xdata,Ydata,PlotStyle);
   
case 'sigma',
   RespObj = svplot(RespObj,sys,Xdata,Ydata,PlotStyle);
   
case 'pzmap',
   RespObj = pzplot(RespObj,sys,Xdata,Ydata,PlotStyle);   
   
case 'rlocus',
   RespObj = rlplot(RespObj,sys,Xdata,Ydata,PlotStyle);
   
end % switch PlotType

%---If any of the systems are arrays, turn on the SelectArray menu
SizeSys = cell(nsys,1);
for ctSys=1:length(sys),
   SizeSys{ctSys} = size(sys{ctSys});
   if length(SizeSys{ctSys})>2,
      set(ContextMenu.ArrayMenu,'visible','on');      
   end % if length(SizeSys)
end % for ctSys

%---Set SelectedChannels Properties value
if isempty(SelectChan),
   if HoldFlag,
      SelectChan = AllRespProps.SelectedChannels;
   else 
      switch PlotType
      case {'sigma';'pzmap'},
         SelectChan = 1;
      case {'lsim';'initial'},
         SelectChan = ones(SizeSys{1}(1),1);
      otherwise
         SelectChan = ones(SizeSys{1}(1:2));
      end
   end
   SelectChan = logical(SelectChan);
end

%---Set SelectedModels Property
if isempty(ModelVis)
   ModelVis = cell(nsys,1);
   for ctSys=1:nsys,
      ModelVis{ctSys} = logical(ones([SizeSys{ctSys}(3:end) 1 1]));
   end   
end
if HoldFlag,
   ModelVis = [AllRespProps.SelectedModels;ModelVis];
end

%---Set SystemVisibility property
if isempty(SysVis)
   SysVis = cell(nsys,1);
   SysVis(:) = {'on'};
end
if HoldFlag,
   SysVis = [AllRespProps.SystemVisibility;SysVis];
end

%---Store and set data for initializing plots
RespObj = respfcn('InitializeResponse',RespObj,SysVis,SelectChan,ModelVis);

%---Modify any additional Response Object Properties
if length(varargin)>4
   set(RespObj,varargin{5:end})
end

if HoldFlag, % Check for any displayed Plot Options
   RespObj = LocalCheckOptions(PlotType,RespObj,[NumOldSys+1:NumOldSys+length(sys)]);
end

%---Store the Reponse Object in the ContextMenu
builtin('set',ContextMenu.Main,'UserData',RespObj)

%---Make the first Plot Axis the figure's current axis
set(get(BackAx,'Parent'),'CurrentAxes',AllRespProps.PlotAxes(1))


%--------------------------Internal Functions-----------------------
%%%%%%%%%%%%%%%%%%%%%%
%%% LocalCheckData %%%
%%%%%%%%%%%%%%%%%%%%%%
function [Xdata,Ydata,ErrFlag,ErrString] = LocalCheckData(PlotType,sys,Ydata,Xdata);

ErrFlag=0;
ErrString='';

%---Take care of pzmap input
%-----Problem checking size of X/Ydata for systems with singular dimensions
if strcmp(PlotType,'pzmap'),
%   for ctSys = 1:length(sys),
%      if (~isempty(Ydata{ctSys}) & ~isequal(ndims(Ydata{ctSys}),ndims(sys{ctSys})) ) | ...
%            (~isempty(Xdata{ctSys}) & ~isequal(ndims(Xdata{ctSys}),ndims(sys{ctSys})) ) ,
%         ErrFlag = 1;
%         ErrString = 'The dimensions of all systems and their pole-zero data do not match.'; 
%      end % if
%   end % for
   return   
end % if strcmp(pzmap

if ~strcmp(PlotType,'margin')
   if ~isequal(length(Xdata),length(sys)),
      ErrFlag=1;
      ErrString = 'The amount of data does not match the number of systems in LTIPLOT.';
      return   
   end
   
   if ndims(sys{1})==2,
      %---Check if data is in old format (Not in cell arrays)
      for ctX=1:length(Xdata),
         if ~iscell(Xdata{ctX}),
            Xdata(ctX)={Xdata(ctX)};
         end
      end
      for ctY=1:length(Ydata),
         switch PlotType
         case {'sigma','impulse','initial','lsim','nyquist'}
            if ~iscell(Ydata{ctY}),
               Ydata(ctY)={Ydata(ctY)};
            end
         case {'bode','nichols','margin'}
            if ~iscell(Ydata{ctY}{1}),
               Ydata{1}{ctY}= {Ydata{1}{ctY}};
               Ydata{2}{ctY}= {Ydata{2}{ctY}};
            end
         case 'step',
            if ~iscell(Ydata{ctY}{1})
               Ydata{ctY}{1}= {Ydata{ctY}{1}};
            end
         end  % switch PlotType
      end % for ctY
   end % if isequal
   
else
   Xdata = {Xdata};
   Ydata = {Ydata};
end % if/else ~strcmp(margin)
%---May want to do additional data checking here

%%%%%%%%%%%%%%%%%%%%%%%%%
%%% LocalCheckOptions %%%
%%%%%%%%%%%%%%%%%%%%%%%%%
function RespObj = LocalCheckOptions(PlotType,RespObj,IndShow)

if any(strcmpi(PlotType,{'step';'impulse';'initial';...
         'bode';'bodemag';'sigma';'nyquist';'nichols'})) & ...
      strcmp(get(RespObj,'PeakResponse'),'on');
   RespObj= respfcn('showpeak',RespObj,IndShow);   
end

if any(strcmpi(PlotType,{'step';'impulse'})) & ...
      strcmp(get(RespObj,'SettlingTime'),'on');
   RespObj= respfcn('showsettling',RespObj,IndShow);   
end

if strcmp(PlotType,'step')
   if strcmp(get(RespObj,'RiseTime'),'on');
      RespObj = respfcn('showrise',RespObj,IndShow);   
   end   
   if strcmp(get(RespObj,'SteadyState'),'on');
      RespObj = respfcn('showsteady',RespObj,IndShow);   
   end
end

if any(strcmpi(PlotType,{'bode';'nyquist';'nichols'})) & ...
      strcmp(get(RespObj,'StabilityMargin'),'on');
   RespObj= respfcn('showmargin',RespObj,IndShow);   
end
