function wvstring(action)
%WVSTRING Animation of waves on a semi-infinite string.
%
%         <DESCRIPTION>
%         wvstring is a graphical interface for animating D'Alembert's 
%         solution of the wave equation on a semi-infinite string with given 
%         initial displacement and anti-derivative of initial velocity:
%
%                 u_tt = u_xx,  x > 0, t>0
%                 u(x,0) = f(x)
%                 u_t(x,0) = G'(x)
%                 
%                 u(0,t) = 0 OR u_x(0,t) = 0
%
%         <TO RUN>
%         Type wvstring at the MATLAB prompt.
%
%         <TO USE>
%         Once started, controls of the animation may be set:
%
%             Time t   -  Animate the solution u(x,t) over the time interval t0<t<t1
%             Range x  -  Plot u(x,t) in the ux-plane over the interval x0<x<x1
%             Animation - Slider to adjust the speed of animation.
%             Boundary  - Radio control to select either a string with pinned
%                         end (u(0,t)=0) or free end (u_x(0,t)=0).
%             f(x)      - Field to define the initial string position u(x,0)
%             G(x)      - Field to define the antiderivative of the initial
%                         string velocity.
%
%         Once set, press the PLAY button to animate.  The animation can
%         then be PAUSED and RESUMED by pressing the PLAY button.

% Created:  5/95 by R. Knobel
% Last Modified: 5/99 by R. Knobel
% Requires:  MATLAB 4.2(c) - MATLAB 5.3

if nargin < 1
   action = 'start';
end

if ~strcmp(action,'start'),
   handles=get(gcf,'UserData');
   hPlot = handles(1);
   hAxes = handles(2);
   hRing = handles(3);
   hInitialPos = handles(4);
   hInitialVelocity = handles(5);
   hXmin = handles(6);
   hXmax = handles(7);
   hTmin = handles(8);
   hTmax = handles(9);
   hSpeed = handles(10);
   hBC1 = handles(11);
   hBC2 = handles(12);
   hPlay = handles(13);
end;

C = 1;   % string speed for now.  Have it a uicontrol later.

if strcmp(action,'start'),
   
   bgcolor = 'black';
   fgcolor = 'white';
   
   figure;
   set(gcf, ...
      'NumberTitle','off', ...
      'Name','D''Alembert''s Semi-Infinite String', ...
      'backingstore','off',...
      'Units','normalized',...
      'Color',bgcolor);
   
   
   % Control Panel 
   
   top      =0.95;
   bottom   =0.05;
   left     =0.82;
   btnWid   =0.13;
   btnHt    =0.06;
   spacing  =0.02;
   frmBorder=0.02;
   frmPos=[.79 .05 btnWid+3*frmBorder .92];
   uicontrol( ...
      'Style','frame', ...
      'Units','normalized', ...
      'Position', frmPos, ...
      'ForegroundColor',fgcolor,...
      'BackgroundColor',bgcolor);
   
   %  Time Interval
   
   uicontrol( ...
      'Style','text',...
      'Units','normalized',...
      'Position', [.81 .905 .15 .04],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor','red',...
      'String','Time t');
   
   uicontrol( 'Style','text',...
      'Units','normalized',...
      'Position', [.81 .86 .08 .04],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor',fgcolor,...
      'String','Initial');
   min_t = 0;
   hTmin=uicontrol( ...
      'Style','edit',...
      'Units','normalized',...
      'Position', [.89 .86 .07 .04],...
      'BackgroundColor','white',...
      'ForegroundColor','black',...
      'String',num2str(min_t));
   
   uicontrol( 'Style','text',...
      'Units','normalized',...
      'Position', [.81 .81 .08 .04],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor',fgcolor,...
      'String','Final');
   max_t = 10;
   hTmax=uicontrol( ...
      'Style','edit',...
      'Units','normalized',...
      'Position', [.89 .81 .07 .04],...
      'BackgroundColor','white',...
      'ForegroundColor','black',...
      'String',num2str(max_t));
   
   % X Interval
   
   uicontrol( ...
      'Style','text',...
      'Units','normalized',...
      'Position', [.81 .73 .15 .04],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor','red',...
      'String','Range x');
   
   uicontrol( 'Style','text',...
      'Units','normalized',...
      'Position', [.81 .68 .06 .04],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor',fgcolor,...
      'String','Min');
   min_x = 0;
   hXmin=uicontrol( ...
      'Style','edit',...
      'Units','normalized',...
      'Position', [.87 .68 .09 .04],...
      'BackgroundColor','white',...
      'ForegroundColor','black',...
      'String',num2str(min_x));
   
   uicontrol( 'Style','text',...
      'Units','normalized',...
      'Position', [.81 .63 .06 .04],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor',fgcolor,...
      'String','Max');
   max_x = 10;
   hXmax=uicontrol( ...
      'Style','edit',...
      'Units','normalized',...
      'Position', [.87 .63 .09 .04],...
      'BackgroundColor','white',...
      'ForegroundColor','black',...
      'String',num2str(max_x));
   
   % Animation Speed Control
   
   uicontrol(...
      'Style','text',...
      'Units','normalized',...
      'Position',[.81 .55 .15 .04],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor','red',...
      'String','Animation');
   
   min_frames= 1;
   max_frames= 50;
   speed     = 25;
   hSpeed=uicontrol( ...
      'Style','slider',...
      'Units','normalized',...
      'Position',[.81 .50 .15 .04],...
      'Value',speed,...
      'Max',max_frames,...
      'Min',min_frames);
   uicontrol(...
      'Style','text',...
      'Units','normalized',...
      'Position',[.805 .46 .06 .04],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor',fgcolor,...
      'String','Fast'); 
   uicontrol(...
      'Style','text',...
      'Units','normalized',...
      'Position',[.91 .46 .055 .04],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor',fgcolor,...
      'String','Slow');
   
   % Boundary Condition Radio Control
   
   uicontrol(...
      'Style','frame',...
      'Units','normalized',...
      'Position',[.81 .3 .15 .14],...
      'BackGround',bgcolor,...
      'ForeGround','red');
   uicontrol(...
      'Style','text',...
      'String','Boundary',...
      'Units','normalized',...
      'Position',[.84 .39 .11 .04],...
      'BackGround',bgcolor,...
      'ForeGround',fgcolor);
   hBC1 = uicontrol(...
      'Style','radio',...
      'String','u(0,t)=0',...
      'BackGround',bgcolor,...
      'ForeGround',fgcolor,...
      'Units','normalized',...
      'Position',[left .35 btnWid .04],...
      'Value',1,...
      'CallBack','wvstring(''bc1'')');
   hBC2 = uicontrol(...
      'Style','radio',...
      'String','u_x(0,t)=0',...
      'BackGround',bgcolor,...
      'ForeGround',fgcolor,...
      'Units','normalized',...
      'Position',[left .31 btnWid .04],...
      'CallBack','wvstring(''bc2'')');
      
   % Play/Pause/Restart Button
   
   hPlay = uicontrol( ...
      'Style','push', ...
      'Units','normalized', ...
      'Position',[left .12+btnHt  btnWid btnHt], ...
      'String','Play', ...
      'Interruptible','yes',...
      'Callback', 'wvstring(''play_click'')' );
   
   % Close Button
   
   uicontrol('Style','Pushbutton', ...
      'Position',[left .1 btnWid btnHt], ...
      'Units','normalized',...
      'Callback','wvstring(''close'')',...
      'String','Close');
   
   
   % Fields to define initial position and velocity 
   
   f = 'exp( -(x-3)^2)'; 
   uicontrol( ...
      'Style','text',...
      'Unit','normalized',...
      'Position',[.03 .06 .10 .05],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor','red',...
      'String','Initial');
   uicontrol( ...
      'Style','text',...
      'Unit','normalized',...
      'Position',[.03 .02 .10 .05],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor','red',...
      'String','Position');
   uicontrol( ...
      'Style','text',...
      'Unit','normalized',...
      'Position',[.13 .04 .10 .05],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor',fgcolor,...
      'String','f(x) =');
   hInitialPos = uicontrol(...
      'Style','edit',...
      'Units','normalized',...
      'Position',[.23 .04 .15 .05],...
      'BackgroundColor','white',...
      'ForegroundColor','black',...
      'String',f);
   
   G = '0'; 
   uicontrol('Style','text',...
      'Units','normalized',...
      'Position',[.40 .10 .15 .05],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor','red',...
      'String','Antiderivative');
   uicontrol('Style','text',...
      'Units','normalized',...
      'Position',[.40 .06 .10 .05],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor','red',...
      'String','of Initial');
   uicontrol('Style','text',...
      'Units','normalized',...
      'Position',[.40 .02 .10 .05],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor','red',...
      'String','Velocity');
   uicontrol('Style','text',...
      'Units','normalized',...
      'Position',[.50 .04 .10 .05],...
      'BackgroundColor',bgcolor,...
      'ForegroundColor',fgcolor,...
      'String','G(x) =');

   hInitialVelocity = uicontrol(...
      'Style','edit',...
      'Units','normalized',...
      'Position',[.6 .04 .15 .05],...
      'BackgroundColor','white',...
      'ForegroundColor','black',...
      'String',G);
   
   % Setup main plot area   
   
   hAxes = axes(...
      'Units','normalized',...
      'Position',[.12 .28 .6 .6],...
      'XLim',[min_x max_x],...
      'YLim',[0 1],...
      'Color',bgcolor,...
      'XColor',fgcolor,...
      'YColor',fgcolor);
   hold on;
   xlabel('x');
   ylabel('u');
   
   hRing = plot(min_x,0,'ro','EraseMode','xor');
   hPlot = plot(min_x,0,'y','EraseMode','xor');
   
   handles=[hPlot hAxes hRing hInitialPos hInitialVelocity hXmin hXmax ... 
         hTmin hTmax hSpeed hBC1 hBC2 hPlay]; 
   set(gcf,'UserData',handles);
      
   wvstring('restart')
   
elseif strcmp(action,'restart'),
   
   f     = get(hInitialPos,'String');
   G     = get(hInitialVelocity,'String');
   min_t = str2num(get(hTmin,'String'));
   max_t = str2num(get(hTmax,'String'));
   min_x = str2num(get(hXmin,'String'));
   max_x = str2num(get(hXmax,'String'));
   
   x = linspace(min_x,max_x,50);
   delx = x(2)-x(1);
   
   if isempty(findstr(f,'x')),
      f = [f ' .* ones(size(x))'];
   end;
   l = length(f);
   for k = fliplr(find((f=='^') | (f=='*') | (f=='/')))
      if ~strcmp(f(k-1),'.')
         f = [f(1:k-1) '.' f(k:l)];
         l = l+1;
      end
   end
   vector_f = f;
   y1 = eval(vector_f);
   max_f = max(abs(y1(:)));
   
   if isempty(findstr(G,'x')),
      G = [G ' .* ones(size(x))'];
   end;
   l = length(G);
   for k = fliplr(find((G=='^') | (G=='*') | (G=='/')))
      if ~strcmp(G(k-1),'.')
         G = [G(1:k-1) '.' G(k:l)];
         l = l+1;
      end
   end
   vector_G = G;
   y2 = eval(vector_G);
   max_G = max(abs(y2(:)));
   
   max_u = 1.1*(max_f + max_G + eps);
   
   [a m] = min( abs(x) );
   set(hAxes, 'XLim',[min_x max_x], 'YLim',[-max_u max_u]);
   set(hRing, 'YData',y1(m))
   set(hPlot, 'XData',x,'YData',y1);
   
   set(hPlay,'String','Play')
   
elseif strcmp(action,'move'),
   
   one_over_2c = 1/(2*C);
   
   min_x = str2num(get(hXmin,'String'));
   max_x = str2num(get(hXmax,'String'));
   x     = linspace(min_x,max_x,100);
   X     = x;
   [a m] = min( abs(x) );
   
   min_t = str2num(get(hTmin,'String'));
   max_t = str2num(get(hTmax,'String'));
   speed = get(hSpeed,'Value');
   frames= fix(speed * (max_t - min_t));
   del_t  = (max_t - min_t) / frames;
   
   f     = get(hInitialPos,'String');
   G     = get(hInitialVelocity,'String');
   
   if isempty(findstr(f,'x')),
      f = [f ' .* ones(size(x))'];
   end;
   l = length(f);
   for k = fliplr(find((f=='^') | (f=='*') | (f=='/')))
      if ~strcmp(f(k-1),'.')
         f = [f(1:k-1) '.' f(k:l)];
         l = l+1;
      end
   end
   vector_f = f;
   
   if isempty(findstr(G,'x')),
      G = [G ' .* ones(size(x))'];
   end;
   l = length(G);
   for k = fliplr(find((G=='^') | (G=='*') | (G=='/')))
      if ~strcmp(G(k-1),'.')
         G = [G(1:k-1) '.' G(k:l)];
         l = l+1;
      end
   end
   vector_G = G;
   
   set(hPlay,'String','Pause')
   
   if get(hBC1,'Value')==1,
      
      for j=1:frames,
         
         t = min_t + j*del_t;
         x = X + C*t;
         y1 = eval(vector_f);
         y2 = eval(vector_G);
         u1 = .5*y1 + one_over_2c * y2; 
         
         x = X - C*t;
         x_pos = x>=0; % full( spones(.5 * ( x + abs(x)) )); 
         x_neg = x<=0; % full( spones(.5 * ( x - abs(x)) )); 
         y1 = eval(vector_f);
         y2 = eval(vector_G);
         u2 = ( .5*y1 - one_over_2c * y2 ) .* x_pos;
         
         x = -x;
         y1 = eval(vector_f);
         y2 = eval(vector_G);
         u3 = ( -.5*y1 - one_over_2c * y2) .* x_neg;
         
         u = u1 + u2 + u3;
         set(hPlot,'XData',X,'YData',u)
         set(hRing,'YData',0)
         pause(0.01)
         
         while strcmp(get(hPlay,'String'),'Resume'),
            pause(0.01)
         end
         
      end
      
   elseif get(hBC2,'Value')==1,
      
      for j=1:frames,
         
         t = min_t + j*del_t;
         x = X + C*t;
         y1 = eval(vector_f);
         y2 = eval(vector_G);
         u1 = .5*y1 + one_over_2c * y2; 
         
         x = X - C*t;
         x_pos = x>=0; % full( spones(.5 * ( x + abs(x)) )); 
         x_neg = x<=0; % full( spones(.5 * ( x - abs(x)) )); 
         y1 = eval(vector_f);
         y2 = eval(vector_G);
         u2 = ( .5*y1 - one_over_2c * y2 ) .* x_pos;
         
         x = -x;
         y1 = eval(vector_f);
         y2 = eval(vector_G);
         u3 = ( .5*y1 + one_over_2c * y2) .* x_neg;
         
         x  = zeros(size(y2));
         y1 = eval(vector_f);
         y2 = eval(vector_G);
         u4 = -2*one_over_2c * y2 .* x_neg;
         
         u = u1 + u2 + u3 + u4;
         set(hRing,'YData',u(m))
         set(hPlot,'XData',X,'YData',u)
         pause(0.01)
         
         while strcmp(get(hPlay,'String'),'Resume'),
            pause(0.01)
         end
         
      end
      
   end;
   
   set(hPlay','String','Restart')
   
elseif strcmp(action,'play_click')
   
   cur_string = get(hPlay,'String');
   
   if strcmp(cur_string,'Restart'),
      wvstring('restart')
   elseif strcmp(cur_string,'Play'),
      wvstring('move')
   elseif strcmp(cur_string,'Pause'),
      set(hPlay,'String','Resume')
   elseif strcmp(cur_string,'Resume')
      set(hPlay,'String','Pause')
   end;
   
elseif strcmp(action(1:2),'bc'),
   
   if strcmp(action,'bc1'),
      set(hBC1,'Value',1);
      set(hBC2,'Value',0);
   else
      set(hBC1,'Value',0);
      set(hBC2,'Value',1);
   end;
      
elseif strcmp(action,'close'),
   
   close
   
end
