function ViewerObj = plotswitch(ViewerObj,varargin)
%PLOTSWITCH  Changes the Response types shown on the LTI Viewer.
%
%   PLOTSWITCH(ViewerObj) is called when the active plot types (plot types
%   for each area in the current configuration) is modified.  In this mode, 
%   PLOTSWITCH visits each plot area to see if its plot type matches the 
%   corresponding entry in the new list.  If not, the appropriate responses
%   are recomputed and plotted.
%
%   PLOTSWITCH(ViewerObj,HMenu) changes only the plot type for the area 
%   whose Plot Type menu has handle Hmenu. This is part of the callback 
%   when switching the plot type off a particular Response Plot.
%
%   PLOTSWITCH(ViewerObj,[],PlotAreas) switches plot type for the plot areas
%   indexed by PlotAreas.  This is used when new Response Areas are added 
%   via the Viewer Configuration window.

%   Authors: K. Gondoly, 1-5-98
%            P. Gahinet  99
%   Revised: A. DiVergilio
%   Copyright 1986-2000 The MathWorks, Inc. 
%   $Revision: 1.29 $  $Date: 2000/06/14 20:03:14 $

ni = nargin;

% Get system, system names for current list of systems
Systems = ViewerObj.Systems;
if isempty(Systems)
   % Empty Viewer: nothing to update
   return
end
SystemNames = namesys(ViewerObj);

% Resolve and hard-wire unspecified plot styles
ViewerObj = setstyle(ViewerObj);  % retrieve + format

% Parse input list
switch ni
case 1
    % Update all plots
    MyArea = 1:length(ViewerObj.BackgroundAxes);
case 2
    % Change plot type from right-click menu
    PlotTypeMenu = varargin{1};
    % Get index of plot area
    UICMenu = get(get(PlotTypeMenu,'Parent'),'Parent');
    RespObj = get(UICMenu,'UserData');
    MyArea = find(ViewerObj.BackgroundAxes==get(RespObj,'BackgroundAxes'));
    % Update active plots (read new plot type off selected menu item)
    ViewerObj.ActivePlotTypes(MyArea) = cellstr(get(PlotTypeMenu,'Tag'));
case 3
    % Specifying plot areas to update
    MyArea = varargin{2};
end

% Get context menus and active plot types
AllMenus = ViewerObj.UIContextMenu;
ActivePlotTypes = ViewerObj.ActivePlotTypes;
NewPlotType = ActivePlotTypes(MyArea);

% Make the NewPlotType string consistent with the internal plot type names
NewPlotType = lower(NewPlotType);
NewPlotType = strrep(NewPlotType,'pole/zero','pzmap');
NewPlotType = strrep(NewPlotType,'bode mag.','bodemag');

% Set flag indicating new LTI Viewer
if ~isempty(AllMenus)
   UIcontextMenu = AllMenus(MyArea);
   NewFlag = (UIcontextMenu==0);
else
   NewFlag = ones(length(MyArea),1);
end

% Update loop
ArrayUpdateHandles = ones(1,length(MyArea))*Inf;
for ct = 1:length(MyArea)
   % Get background axes
   BackgroundAxes = ViewerObj.BackgroundAxes(MyArea(ct));
   
   %---Get any extra arguments and preferences from the Viewer Object
   ExtraArg = {};
   switch NewPlotType{ct}
   case {'step','impulse'}
      if strcmp(ViewerObj.Preferences.TimeVectorMode,'manual') & ~isempty(ViewerObj.Preferences.TimeVector)
         ExtraArg = {ViewerObj.Preferences.TimeVector};
      end
   case 'initial'
      % Initial response
      if strcmp(ViewerObj.Preferences.TimeVectorMode,'manual') & ~isempty(ViewerObj.Preferences.TimeVector)
         ExtraArg = {ViewerObj.InitialCondition , ViewerObj.Preferences.TimeVector};
      else
         ExtraArg = {ViewerObj.InitialCondition};
      end
   case 'lsim'
      % Linear simulation
      ExtraArg = {ViewerObj.InputSignal.Value , ViewerObj.InputSignal.Time , ViewerObj.InputSignal.IC};
   case {'bode','bodemag','nyquist','nichols','sigma'}
      % Frequency response plots
      if strcmp(ViewerObj.Preferences.FrequencyVectorMode,'manual')
         FRDFlags = zeros(1,length(Systems));
         for ctSys=1:length(Systems)
            FRDFlags(ctSys) = isa(Systems{ctSys},'frd');
         end
         if ~any(FRDFlags)
            % No FRD model in sight
            FV = ViewerObj.Preferences.FrequencyVector;
            FU = ViewerObj.Preferences.FrequencyUnits;
            if iscell(FV)
               FV = {unitconv(FV{1},FU,'rad/sec') unitconv(FV{2},FU,'rad/sec')};
            else
               FV = unitconv(FV,FU,'rad/sec');
            end
            ExtraArg = {FV};
         else
            status(ViewerObj,'User-defined frequency vectors are ignored when displaying FRD response plots.',1);
         end
      end
   end

   %---Eliminate all systems that cannot be plotted for this plot type
   isValid = validsys(NewPlotType{ct},Systems);
   if ~any(isValid)
       line1 = sprintf(...
           'The plot type "%s" is not applicable to any of the',NewPlotType{ct});
       warndlg({line1;...
               sprintf('systems currently loaded in the Viewer.');...
               ''; ...
               sprintf('Use the right-click menu or, if a right-click menu is not'); ...
               sprintf('available, the Viewer Configuration window to select'); ...
               sprintf('a frequency-domain plot type.')}, ...
           'LTI Viewer Warning','modal');
       if ~NewFlag(ct)
           RespObj = get(UIcontextMenu(ct),'UserData');
           RespObj = deletesys(RespObj,1:length(get(RespObj,'SystemNames')));
           set(UIcontextMenu(ct),'UserData',RespObj)
       end
       continue
   end

   if ~NewFlag(ct)
       % Updating an existing response plot
       %---Store old Response Object Properties
      RespObj = get(UIcontextMenu(ct),'UserData');
      OldProps = get(RespObj,'Undocumented');

      %---Store any old I/O and Array Selector Figures
      SelectorHandle = get(OldProps.UIContextMenu.ChannelMenu,'UserData');
      ArrayHandle = get(OldProps.UIContextMenu.ArrayMenu,'UserData');

      %---Close any open Selectors for PZMAP/Sigma plots, SISO systems,
      % or Viewers that were initialized with Initial or Lsim.
      indok = find(isValid);
      sizes = size(Systems{indok(1)});
      if ( any(strcmpi(NewPlotType{ct},{'pzmap';'sigma'})) | ...
            isequal(prod(sizes(1:2)),1) ) | ...
            ( any(strcmpi(OldProps.ResponseType,{'initial';'lsim'})) )
         IOflag = 1; % Close any open I/O Selectors
      else
         IOflag = 0; % Leave the I/O Selectors on
      end
      ASflag = 0; % Leave Array Selector on
      cla(RespObj,IOflag,ASflag);
   end

   %---plot data and pass system names on the Response Object
   feval(NewPlotType{ct},BackgroundAxes,Systems{isValid},ViewerObj.PlotStyles(isValid),ExtraArg{:});
   RespObj = gcr(BackgroundAxes);
   % REVISIT: This is an expensive operation which needs updating down to the
   % response line userdata. System names should be passed to the @response
   % constructor directly...
   RespObj = pvset(RespObj,'SystemNames',SystemNames(isValid));

   %---Set XlimMode to manual when time vector is specified in Response Prefs
   %--- (to disable time range adjustment based on settling time)
   switch NewPlotType{ct}
   case {'step';'impulse';'initial'}
      if ~isempty(ViewerObj.Preferences.TimeVector)
         set(RespObj,'XlimMode','manual')
      end
   end
   
   %---Update Context Menus with LTI Viewer specific options
   RespObj = respfcn('viewermenus',RespObj);

   %---Get new properties
   NewProps = get(RespObj,'Undocumented');
   TempMenu = NewProps.UIContextMenu;

   if ~NewFlag(ct)
      %---Update any old response properties
      [ResetPropStr,NewProps] = LocalGetResets(NewProps,OldProps,NewPlotType{ct},ViewerObj);
      if ~isempty(ResetPropStr)
         set(RespObj,ResetPropStr{:})
      end

      %---Re-parent any open I/O or Array Selector windows
      if ishandle(SelectorHandle)
         set(SelectorHandle,'Name',[xlate('I/O Selector: '),NewPlotType{ct}],...
            'UserData',TempMenu.Main);
         set(TempMenu.ChannelMenu,'UserData',SelectorHandle);
      end

      if ishandle(ArrayHandle)
         set(TempMenu.ArrayMenu,'UserData',ArrayHandle)
         ArrayUpdateHandles(ct) = ArrayHandle;
      end

      %---Add any Plot Options
      RespObj = LocalAddOptions(RespObj,OldProps,NewProps);
   end

   set(TempMenu.Main,'UserData',RespObj); % Make sure to store new properties
   AllMenus(MyArea(ct),1) = TempMenu.Main;

end

%---Update UIContextMenu, ActivePlotTypes and SystemNames
ViewerObj.UIContextMenu = AllMenus;
ViewerObj.ActivePlotTypes = ActivePlotTypes;
ViewerObj.SystemNames = SystemNames;  % RE: RespObj's SystemNames already set

%---Update the Array Selectors, if necessary (must be done after setting names)
for ct = 1:length(MyArea)
   if ~NewFlag(ct)
      if ishandle(ArrayUpdateHandles(ct))
         paramsel('#refresh',get(AllMenus(MyArea(ct)),'UserData'));
      end
   end
end

status(ViewerObj,'Configuration change completed.',1);


%%%%%%%%%%%%%%%%%%%%%%%
%%% LocalAddOptions %%%
%%%%%%%%%%%%%%%%%%%%%%%
function RespObj = LocalAddOptions(RespObj,OldProps,NewProps);

%---If going between time domain responses (or frequency domain responses),
%     save the settings of common Plot Options

OldPlotType = OldProps.ResponseType;
NewPlotType = NewProps.ResponseType;

if any(strcmpi(OldPlotType,{'step';'impulse';'initial';'lsim'})) & ...
      any(strcmpi(NewPlotType,{'step';'impulse';'initial';'lsim'})),
   % Going from a time response plot to another time response plot
   if isfield(OldProps,'PeakResponse') & isfield(NewProps,'PeakResponse') & ...
         strcmp(OldProps.PeakResponse,'on')
      set(RespObj,'PeakResponse','on')   
   end
   if isfield(OldProps,'SettlingTime') & isfield(NewProps,'SettlingTime') & ...
         strcmp(OldProps.SettlingTime,'on')
      set(RespObj,'SettlingTime','on')  
   end
   
elseif any(strcmpi(OldPlotType,{'bode';'bodemag';'nyquist';'nichols';'sigma'})) & ...
      any(strcmpi(NewPlotType,{'bode';'bodemag';'nyquist';'nichols';'sigma'})),
   % Going from a frequency response plot to another frequency response plot
   if isfield(OldProps,'PeakResponse') & isfield(NewProps,'PeakResponse') & ...
         strcmp(OldProps.PeakResponse,'on')
      set(RespObj,'PeakResponse','on')   
   end
   if isfield(OldProps,'StabilityMargin') & ...
         any(strcmpi(NewPlotType,{'bode';'nyquist';'nichols'})) & ...
         strcmp(OldProps.StabilityMargin,'on')
      % RE: 'StabilityMargin' is not defined for bodemag even though it's a property of @bodplot
      set(RespObj,'StabilityMargin','on')   
   end
   if isfield(OldProps,'AllStabilityMargin') & ...
         any(strcmpi(NewPlotType,{'bode';'nyquist';'nichols'})) & ...
         strcmp(OldProps.AllStabilityMargin,'on')
      set(RespObj,'AllStabilityMargin','on')   
   end
end

% Plot-specific characteristics
if strcmpi(OldPlotType,'step') & strcmpi(NewPlotType,'step'),
   % Going from a time response plot to another time response plot
   if isfield(OldProps,'RiseTime') & isfield(NewProps,'RiseTime') & ...
         strcmp(OldProps.RiseTime,'on')
      set(RespObj,'RiseTime','on')   
   end
   if isfield(OldProps,'SteadyState') & isfield(NewProps,'SteadyState') & ...
         strcmp(OldProps.SteadyState,'on')
      set(RespObj,'SteadyState','on')  
   end
end

%%%%%%%%%%%%%%%%%%%%%%
%%% LocalGetResets %%%
%%%%%%%%%%%%%%%%%%%%%%
function [ResetPropStr,NewProps] = ...
   LocalGetResets(NewProps,OldProps,NewPlotType,ViewerObj);

ResetPropStr = {};  % List of property to be reset and their values

% Find locations of shared names
% Code below amounts to a fast INTERSECT
NewNames = NewProps.SystemNames;
OldNames = OldProps.SystemNames;
[names,perm] = sortrows(char(NewNames{:},OldNames{:}));
d = find(all(names(1:end-1,:)==names(2:end,:),2));
iNew = min(perm(d),perm(d+1));
iOld = max(perm(d),perm(d+1))-length(NewNames);

% Axis grouping
if ~strcmp(OldProps.AxesGrouping,'none');
   ResetPropStr=[ResetPropStr , {'AxesGrouping' , OldProps.AxesGrouping}];
end

% Selected channels
[numinold,numoutold]=size(OldProps.SelectedChannels);
[numinnew,numoutnew]=size(NewProps.SelectedChannels);
if ~all(OldProps.SelectedChannels) & ~any(strcmpi(NewPlotType,{'pzmap';'sigma'})) & ...
      ~any(strcmpi(OldProps.ResponseType,{'pzmap';'sigma'})) & ...
      isequal(numinold,numinnew) & isequal(numoutold,numoutnew),
   NewProps.SelectedChannels = OldProps.SelectedChannels;
   ResetPropStr = [ResetPropStr, {'SelectedChannels' , NewProps.SelectedChannels}];
end

% System visibility
if ~all(strcmpi('on',OldProps.SystemVisibility(iOld))),
   % REVISIT: hack so that hidden system does not suddenly become visible after 
   % becoming invalid (disappears from system list). Eventually the number of systems
   % in RespObj should remain constant, and the NaN's should simply be ignored
   NewProps.SystemVisibility(:) = {'off'};
   NewProps.SystemVisibility(iNew) = OldProps.SystemVisibility(iOld);
   ResetPropStr = [ResetPropStr, {'SystemVisibility' , NewProps.SystemVisibility}];
end

% Selected models
ArrayChange=0;
for ctSM=1:length(iOld)
   if ~all(OldProps.SelectedModels{iOld(ctSM)}) & ...
         isequal(size(OldProps.SelectedModels{iOld(ctSM)}),size(NewProps.SelectedModels{iNew(ctSM)})),
      NewProps.SelectedModels(iNew(ctSM)) = OldProps.SelectedModels(iOld(ctSM));
      ArrayChange=1;
   end
end % for ctSM

if ArrayChange,
   ResetPropStr = [ResetPropStr,{'SelectedModels',NewProps.SelectedModels}];
end
