c----------------------------------------------------------------------
      subroutine parse_command(line,command,angx,angy,angz)
c----------------------------------------------------------------------
c
c         This subroutine parses the Command Line and sets the logical
c     flags accordingly.  It will also retrieve the numerical values
c     specified for the angles, etc.
c
c     Commands implemented :           (3/14/88)
c
c          ! or /   (recall) last command
c          ad[d]    { bo[nd] | pa[rtial bond] }
c          ad[d] la[bel]
c          cu[t] {to[p] distance | bo[ttom] distance | sp{here} at's distance}
c          de[lete] bo[nd] la[bel]
c          dr[aw]
c          hi[de] {[at1 at2 ...], no[ne] }
c          mo[re]
c          ne[w]
c          pa[n]    well ... actually it's "unzoom"
c          qu[it]
c          ro[tate] angle1 [axis1] [angle2 axis2] [angle3 axis3]
c          se[t]    label { nu[mber] | ch[aracter] | no[ne] }
c          se[t]    mo[del] { wi[reframe] | ba[ll and stick] | su[perimposed] }
c          se[t]    pr[ojection] { or[thographic] | pe[rspective] }
c          se{t}    hb[onds] {on| of[f] | le[ngth] length | an[gle] angle |
c                             do[nor] do1 to don | ac[ceptor] ac1 to acn }
c          st[op]
c          te[ll]   {di[stance] [at1 at2] | an[gle] [at1 at2 at3] |
c                    dih[edral] [at1 at2 at3 at4] | to[rsion] [at1 at2 at3 at4]}
c          tu[rn]   angle1 [axis1] [angle2 axis2] [angle3 axis3]
c          wr[ite] 
c          zo[om]
c
c     Commands in the process of being added :
c
c          de[lete] at[om]
c          se[t]    mo[del] { we[dge] | sp[ace filling] }
c          se[t]    pr[ojection] st[ereo]
c          se[t]    sc[reen] numx x numy y
c          se[t]    autoscale { no | yes}
c
      parameter (natom = 10000) 
      parameter (nbond = 50000) 
c 
      real rea,max_z,min_z
      integer hbnd_d,hbnd_h,hbnd_a
      integer nint,nrea,ncha,inva,start,end,start1,end1,at1,at2,at3,at4
      integer atom,sp_cntr, reversed
      character*80 line,form,old_line
      character*20 str_val,str_val1,str_val2,str_val3,str_val4
      character*30 cha
      character*2 command,qual1,qual2,qual3
      logical wireframe,ball_and_stick,need_sort,label_num,
     &        label_cha,old_la_n,old_la_c,need_lim,perspective,
     &        old_perspective,show_atom,cut_top,cut_bottom,cut_sphere,
     &        round_bonds,old_round,autoscl,showhb,havehb
c
      dimension inva(40),rea(40),cha(40)
      dimension sp_cntr(1000)
c
      common/bonds/numbonds,ibond(nbond),jbond(nbond),nbonds(nbond),
     &             lastbond(natom),numpoint
      common /hyd_bonds/ hbndlength,hbangle,hbnd_d(natom/3),
     &			 hbnd_h(natom/3),hbnd_a(natom/3),
     &			 nhbdon,nhbhyd,nhbacc
      common/draw_spec/rad_fact,bond_fact,top_z,bottom_z
      common/draw_log/wireframe,ball_and_stick,need_sort,label_num,
     &                label_cha,need_lim,perspective,round_bonds,
     &                autoscl,showhb,havehb
      common/per_color/iatcolor(105), reversed
      common/font_num/ifont
      common/show/show_atom(natom)
      common/mol_num/numat,num(natom),co(3,natom),atrad(natom)
      common/sortseq/iseq(natom),irank(natom)
      common/useratt/user_scale
c
      command   = '  '
      qual1     = '  '
      qual2     = '  '
      qual3     = '  '
      nrea      = 0
      rea(1)    = 0.0e0
      angx      = 0.0e0
      angy      = 0.0e0
      angz      = 0.0e0
      old_la_n  = label_num
      old_la_c  = label_cha
      old_round = round_bonds
      old_hblen = hbndlength
      old_hbang = hbangle
c
c     to deal with recall of previous command :
c
      if (line(1:1).eq.'/' .or. line(1:1) .eq. '!') line=old_line
      old_line = line
c
c     Break down the line into components :
c
      call freeread(line,nint,nrea,ncha,inva,rea,cha,form)
c
c     First convert to uppercase to avoid doing double comparisons. 
c     At the same time retrieve the primary command and two qualifiers :
c
      if (ncha.gt.0) then
           do i=1,ncha
                call upcase(cha(i))
           enddo
           command=cha(1)(1:2)
           if (ncha.gt.1) then
c
c               if DIH[edral] was specified, substitute for TO[rsion] :
c
                if (cha(2)(1:3).eq.'DIH') cha(2)(1:2)='TO'
                qual1=cha(2)(1:2)
           endif
           if (ncha.gt.2) qual2=cha(3)(1:2)
           if (ncha.gt.3) qual3=cha(4)(1:2)
      endif
c
c     Now proceed according to the command given :
c
      if (command.eq.'SE') then
c
c     SEtting options here :
c
          if (qual1.eq.'MO') then
c
c         SEtting MOdel
c
               if (qual2.eq.'WI') then
                    command='DR'
                    wireframe=.true.
                    ball_and_stick=.false.
                    need_sort=.false.
               else if (qual2.eq.'BA') then
                    command='DR'
                    wireframe=.false.
                    ball_and_stick=.true.
                    need_sort=.true.
               else if (qual2.eq.'SP') then
                    command='  '
               else if (qual2.eq.'WE') then
                    command='  '
               else if (qual2.eq.'SU') then
                    command='DR'
                    wireframe=.true.
                    ball_and_stick=.true.
                    need_sort=.true.
               else
                    command='  '
               endif
          else if (qual1.eq.'PR') then
c
c              SEtting PRojection :
c
               if (qual2.eq.'OR') then
                    perspective=.false.
               else if (qual2.eq.'PE') then
                    perspective=.true.
               else 
                    command='  '
               endif
               if (old_perspective.ne.perspective) then
                    command='DR'
               endif
               old_perspective=perspective
          else if (qual1.eq.'LA') then
c
c              SEtting LAbels :
c
               if (qual2.eq.'NO') then
                    label_num=.false.
                    label_cha=.false.
               else if (qual2.eq.'NU') then
                    label_num=.true.
                    label_cha=.false.
               else if (qual2.eq.'CH') then
                    label_num=.false.
                    label_cha=.true.
               else
                    command='  '
               endif
               if(label_num.ne.old_la_n .or. label_cha.ne.old_la_c) then
                    command='DR'
               else
                    command='  '
               endif
          else if (qual1.eq.'DI') then
c
c              SEtting DIsplay mode
c
            if (ncha.lt.3) then
c
c              if no additional qualifier, assume "normal" display
c
               qual2  = 'NO'
            endif
            if (qual2.eq.'NO') then
c
c              SEt DIsplay NOrmal
c
               reversed = 0
               command = 'DR'
            else if (qual2.eq.'RE') then
c
c              SEt DIsplay REversed for colored bonds and clear atoms
c
              reversed = 1
              command = 'DR'
            else if (qual2.eq.'CL') then
c
c              SEt DIsplay CLear for clear bonds and atoms.
c
               reversed = 2
               command = 'DR'
            endif
          else if (qual1.eq.'FO') then
c
c             SEtting FOnt styles
c
              ifont = 0
              if (nint.gt.0) then
                  ifont = inva(1)
              endif
             call fontstyle(ifont)
             call notify('Changed font style. ')
             command='DR'
          else if (qual1.eq.'LI') then
c
c             SEtting LIne styles
c
              if (nint.gt.0) then
                  istyle = inva(1)
              endif
             call line_style(istyle)
             command='DR'
          else if (qual1.eq.'SC') then
c
c           SEtting SCale factors :
c
c           in case some decimal point(s) were omitted convert all 
c           integers to reals preserving the order :
c
            call allrea(form,inva,rea,nint,nrea)
            if (nint .eq. 0 .and. nrea .eq. 0) then
               autoscl = .not.autoscl
               if (autoscl) then
                  call notify ('Automatic scaling ON. ')
               else
                  call notify ('Automatic scaling OFF. ')
               endif
               command = '  '
            else
               if( rea(1) .ne. 0.0) user_scale = rea(1)
               command='DR'
            endif
          else if (qual1.eq.'HB') then
c
c           SEtting HBonds
c
            if (ncha.lt.3) then
c
c              if no additional qualifier, assume an {ON|OFF} toggle
c
               showhb = .not.showhb
               qual2  = 'OFF'
               if (showhb) qual2 = 'ON'
            endif
            if (qual2.eq.'ON') then
c
c              SEt HBonds ON
c
               showhb = .true.
               call notify('Showing Hydrogen Bonds. ')
               if (.not.havehb) call calchbonds
               command = 'DR'
            else if (qual2.eq.'OF') then
c
c              SEt HBonds OFf
c
               showhb = .false.
               call notify('Not showing Hydrogen Bonds. ')
               command = 'DR'
            else if (qual2.eq.'LE') then
c
c              SEt HBonds LEngth
c
c              in case the decimal point was omitted convert all 
c              integers to reals preserving the order :
c
               call allrea(form,inva,rea,nint,nrea)
               if(nrea.ge.1 .and. rea(1).ne.0.0) hbndlength = rea(1)
               if (hbndlength.ne.old_hblen) then
                  havehb = .false.
                  call clearhbonds
                  call calchbonds
                  showhb = .true.
                  call notify('Showing Hydrogen Bonds. ')
                  command = 'DR'
               else
                  command = '  '
               endif
            else if (qual2.eq.'AN') then
c
c              SEt HBonds ANgle
c
c              in case the decimal point was omitted convert all 
c              integers to reals preserving the order :
c
               call allrea(form,inva,rea,nint,nrea)
               if(nrea.ge.1 .and. rea(1).ne.0.0) hbangle = rea(1)
               if (hbangle.ne.old_hbang) then
                  havehb = .false.
                  call clearhbonds
                  call calchbonds
                  showhb = .true.
                  call notify('Showing Hydrogen Bonds. ')
                  command = 'DR'
               else
                  command = '  '
               endif
            else if (qual2.eq.'DO') then
c
c              SEt HBonds DOnor
c
            else if (qual2.eq.'AC') then
c
c              SEt HBonds ACceptor
c
            endif
c
          else if (qual1.eq.'TE') then
c
c           SEtting TExt height :
c
            call allrea(form,inva,rea,nint,nrea)
            if( rea(1) .ne. 0.0) text_height = rea(1)
            call text_style(text_height)
            command='DR'
          else if (qual1.eq.'BO') then
c
c           SEtting BOnd caps as either rounded or straight :
c
            if (qual2.eq.'RO') then
                 round_bonds = .true.
            else if (qual2.eq.'CA') then
                 round_bonds = .false.
            endif
            if (old_round .ne. round_bonds) command='DR'
          else if (qual1.eq.'AU') then
c
c           SEtting autoscale as on, off, or toggle
c
            if (qual2(1:1).eq.'Y') then
               autoscl = .true.
            else if (qual2(1:1).eq.'N') then
               autoscl = .false.
            else
               autoscl = .not.autoscl
            endif
            if (autoscl) then
               call notify ('Automatic scaling ON. ')
            else
               call notify ('Automatic scaling OFF. ')
            endif
            command = '  '
          endif
c
      else if (command .eq. 'TE') then
c
c     TEll option is processed here :
c
            if (qual1 .eq. 'DI') then
c
c           TEll DIstance :
c
                 if (nint.gt.1) then
                      at1=inva(1)
                      at2=inva(2)
                 else
                      call pick_dis(at1,at2)
                 endif
                 write(str_val1,'(i10)') at1
                 write(str_val2,'(i10)') at2
                 call limits(str_val1,i1,j1)
                 call limits(str_val2,i2,j2)
                 write(str_val,'(f10.4)')at_dist(at1,at2)
                 call limits(str_val,start,end)
                 call notify('The distance '//str_val1(i1:j1)//'-'//
     &                      str_val2(i2:j2)//' is '//
     &                      str_val(start:end))
                 command='  '
c
c           TEll ANgle :
c
            else if (qual1 .eq. 'AN') then
                 if (nint.gt.2) then
                      at1=inva(1)
                      at2=inva(2)
                      at3=inva(3)
                 else
                      call pick_ang(at1,at2,at3)
                 endif
                 write(str_val1,'(i10)') at1
                 write(str_val2,'(i10)') at2
                 write(str_val3,'(i10)') at3
                 call limits(str_val1,i1,j1)
                 call limits(str_val2,i2,j2)
                 call limits(str_val3,i3,j3)
                 write(str_val,'(f10.4)')angle(at1,at2,at3)
                 call limits(str_val,start,end)
                 call notify('The angle '//str_val1(i1:j1)//'-'//
     &                      str_val2(i2:j2)//'-'//str_val3(i3:j3)//
     &                      ' is '//str_val(start:end))
                 command='  '
            elseif (qual1 .eq. 'NU') then
                 call notify('Click on the atom. ')
                 call pick_atom(iatomp,ibutton)
                 write(*,*)'Clicked on atom number ',iatomp
                 call flush(6)
                 command = ' '
c
c           TEll TOrsion :
c
            else if (qual1 .eq. 'TO') then
                 if (nint.gt.3) then
                      at1=inva(1)
                      at2=inva(2)
                      at3=inva(3)
                      at4=inva(4)
                 else
                      call pick_dih(at1,at2,at3,at4)
                 endif
                 write(str_val1,'(i10)') at1
                 write(str_val2,'(i10)') at2
                 write(str_val3,'(i10)') at3
                 write(str_val4,'(i10)') at4
                 call limits(str_val1,i1,j1)
                 call limits(str_val2,i2,j2)
                 call limits(str_val3,i3,j3)
                 call limits(str_val4,i4,j4)
                 write(str_val,'(f10.4)')dihedral(at1,at2,at3,at4)
                 call limits(str_val,start,end)
                 call notify('The dihedral angle '//str_val1(i1:j1)//
     &                      '-'//str_val2(i2:j2)//'-'//str_val3(i3:j3)
     &                      //'-'//str_val4(i4:j4)//
     &                      ' is '//str_val(start:end))
                 command='  '
c
c           TEll LImits :
c
            else if (qual1 .eq. 'LI') then
c
c               actualize sorting and ranking, if needed :
c
                if (need_lim) then
                     call get_limits(3,min_z,max_z)
                     need_lim=.false.
                endif
c
c               write out the MOLECULAR limits :
c
                write(str_val,'(f10.4)') min_z
                call limits(str_val,start,end)
                write(str_val1,'(f10.4)') max_z
                call limits(str_val1,start1,end1)
                call notify('Molecule Z limits are '
     &                     //str_val(start:end)
     &                     //' to '//str_val1(start1:end1))
c
c               write out the VIEW limits :
c
                write(str_val,'(f10.4)') bottom_z
                call limits(str_val,start,end)
                write(str_val1,'(f10.4)') top_z
                call limits(str_val1,start1,end1)
                call notify('View Z limits are '//str_val(start:end)
     &                     //' to '//str_val1(start1:end1))
                command='  '
            else
	         command='  '
            endif
c
c      HIde atoms :
c
      else if (command .eq. 'HI') then
           if (qual1.eq.'NO') then
                do nathide=1,numat
                     show_atom(nathide)=.true.
                enddo
                call notify('All atoms visible. ')
                if (need_lim) then
                     call get_limits(3,min_z,max_z)
                     need_lim=.false.
                endif
                top_z = max_z
                bottom_z = min_z
           else
c
c               if no atom numbers were given go pick, else hide those given :
c
                if (nint.eq.0) then
                     ibutton = 0
                     call notify(
     &               'Click on the atoms, finish with middle button. ')
                     do while(ibutton .ne. 2)
                        call pick_atom(inva(1),ibutton)
                        show_atom(inva(1))=.false.
                     enddo
                     call notify('Atom(s) hidden. ')
                else
                   do atom=1,nint
                        show_atom(inva(atom))=.false.
                   enddo
                endif
           endif
           command='DR'
c
c     CUt :
c
      else if (command .eq. 'CU') then
           cut_top=.false.
           cut_bottom=.false.
           cut_sphere=.false.
c
c          assign the type of cut based on QUAL1 :
c
           if (qual1.eq.'TO') then
                cut_top = .true.
           else if (qual1.eq.'BO') then
                cut_bottom = .true.
           else if (qual1.eq.'SP') then
                cut_sphere = .true.
           else
                command='  '
                return
           endif
c
c          get the value to cut, if not given as real try as integer, else
c          clear the command and return. Do not assume a default :
c
           if (nrea.gt.0) then
                cut_inc = rea(1)
           else if (nint.gt.0) then
                cut_inc = inva(1)
c
c               when cutting a sphere, if the radius was given as an
c               integer, left-shift the remaining elements in the INVA
c               array :
c
                if (cut_sphere) then
                     nint=nint-1
                     do i=1,nint
                          inva(i)=inva(i+1)
                     enddo
                endif
           else 
                command = '  '
                return
           endif
c
c          actualize sorting and ranking, if needed :
c
           if (need_lim) then
                call get_limits(3,min_z,max_z)
                need_lim=.false.
           endif
c
c          actualize view limits for top & bottom cuts:
c
          if (cut_top .or. cut_bottom) then
c        write(99,*) ' before cutting, top,bottom:',top_z,bottom_z
c       write(99,*) '                 min_z, max_z:',min_z,max_z
                if (cut_bottom) then
                     bottom_z = bottom_z + cut_inc
c                     write(99,*) ' cut bottom of : ',cut_inc
                     if (bottom_z.lt.min_z) bottom_z = min_z
                     if (bottom_z.gt.max_z) bottom_z = max_z
                else if (cut_top) then
c                     write(99,*) ' cut top of : ',cut_inc
                     top_z = top_z - cut_inc
                     if (top_z.lt.min_z) top_z = min_z
                     if (top_z.gt.max_z) top_z = max_z
                endif
           endif
c
c          do the cutting :
c
           if (cut_top .or. cut_bottom) then
c                write(99,*) 'top,bottom:',top_z,bottom_z
                do atom=1,numat
                     if (co(3,atom).le.top_z .and. co(3,atom).ge.
     &                                        bottom_z ) then
                          show_atom(atom) = .true.
                     else
                          show_atom(atom) = .false.
                     endif
                enddo
                command='DR'
           else if (cut_sphere) then
c
c    first transfer the centers of the spheres to the sp_cntr array.  This can
c               be done in one of two forms :
c
                if (qual2.eq.'TO') then
c
c                    if a range was specified generate a full list :
c     
                     ncenters=inva(2)+1-inva(1)
                     do kounter=1,ncenters
                          sp_cntr(kounter)=inva(1)+kounter-1
                     enddo
                else
c
c                    if one or more lists were given transfer them :
c
                     ncenters=nint
                     do i=1,ncenters
                          sp_cntr(i)=inva(i)
                     enddo
                endif
c
c               now do the cut :
c
                do atom=1,numat
                     show_atom(atom)=in_sphere(atom,cut_inc,ncenters,
     &                                         sp_cntr)
                enddo
                command='DR'
           endif
c
c      ZOom :
c
      else if (command .eq. 'ZO') then
            call zoom
            call notify('  ')
            command='DR'
c
c     PAn :
c
      else if (command .eq. 'PA') then
            call pan
            call notify('Full view. ')
            command='DR'
c
c     ROtate or TUrn :
c
      else if (command.eq.'TU' .or. command.eq.'RO') then
            command='TU'
c     
c           in case some decimal point(s) were ommited convert all 
c           integers to reals preserving the order :
c
            call allrea(form,inva,rea,nint,nrea)
            if ((nrea.eq.1).and.(ncha.eq.1)) then
c 
c                only one angle given with no name; assume angz
c
                 angz=-rea(1)
            else if (nrea.gt.(ncha-1)) then
c
c                number of angles and names don't match, blank
c                the command as a flag, return
c
                 command='  '
            else
c
c                 match the angles with their names :
c
                  do i=1,3
                       if (cha(i+1).eq.'Z') angz=-rea(i)
                       if (cha(i+1).eq.'Y') angy=rea(i)
                       if (cha(i+1).eq.'X') angx=-rea(i)
                  enddo
                  need_sort=((angy.ne.0.0e0 .or. angx.ne.0.0e0) )
                  need_lim=need_sort
            endif
c
c     QUit
c
      else if (command.eq.'QU') then
           command='QU'
c
c     STereo
c
      else if (command.eq.'ST') then
           if (qual1.eq.'VI') then
              command='SV'
           else
              command='SP'
           endif
c
c     GRid
c
      else if (command.eq.'GR') then
         call toggle_grid
         command='DR'
c
c     DRaw :
c
      else if (command.eq.'DR') then
           command='DR'
c
c     PLot :
c         The FIle qualifier will send the plot to a file instead
c         of the default printer.
c
      else if (command.eq.'PL') then
           if (qual1.eq.'FI') then
              command='FI'
           else
              command='PL'
           endif
c
c     ADd command :
c

      else if (command.eq.'AD') then
c
c          ADd BOnd :
c
           if (qual1.eq.'BO') then
                 if (nint.gt.1) then
                      at1=inva(1)
                      at2=inva(2)
                 else
                      call pick_add_bond(at1,at2)
                 endif
                 call add_bond(at1,at2,.true.)
                 call notify('Added full bond. ')
                 command='DR'
c
c          ADd PArtial :
c
           else if (qual1.eq.'PA') then
                 if (nint.gt.1) then
                      at1=inva(1)
                      at2=inva(2)
                 else
                      call pick_add_bond(at1,at2)
                 endif
                 call add_bond(at1,at2,.false.)
                 call notify('Added partial bond. ')
                 command='DR'
c
c ADd LAbel
c
           else if (qual1.eq.'LA') then
                 call add_label
                 command=' '
c
c ADd ARc
c
           else if (qual1.eq.'AR') then
                 call add_arc
                 command=' '
c
c ADd LIne 
c
           else if (qual1.eq.'LI') then
                 call add_line
                 command=' '
c
c ADd HEad 
c
           else if (qual1.eq.'HE') then
                 call add_arrow
                 command=' '
           else
               command='  '
           endif
c
c     DElete command :
c
      else if (command.eq.'DE') then
           if (qual1.eq.'BO') then
                 if (nint.gt.1) then
                      at1=inva(1)
                      at2=inva(2)
                 else
                      call pick_del_bond(at1,at2)
                 endif
               call del_bond(at1,at2)
               call notify('Deleted bond. ')
               command='DR'
           else if (qual1.eq.'AT') then
               command='  '
           else if (qual1.eq.'LA') then
               call delete_label
               command='DR'
           else if (qual1.eq.'LI') then
               call delete_arc
               command='DR'
           else
               command='  '
           endif
      else if (command.eq.'NE') then
           command='NE'
      else if (command.eq.'MO') then
           if (qual1 .eq. 'LA') then
              call move_label
              command='DR'
           else  
              command='MO'
           endif
      else if (command.eq.'WR') then
           if (qual1.eq.'AL') then
              call write_file(.true.)
           else
              call write_file(.false.)
           endif
           command='  '
      else if (command.eq.'HE') then
           command='  '
c
c          COmplete valences :
c
      else if (command.eq.'CO') then
c
c          if no atom numbers were given go pick, else hide those given :
c
           if (nint.eq.0) then
                ibutton = 0
                call notify(
     &          'Click on the atoms, finish with middle button. ')
                do while(ibutton .ne. 2)
                    nint=nint+1
                    call pick_atom(inva(nint),ibutton)
                enddo
           endif
           do atom=1,nint
               if (inva(atom).eq.1) then
                   inibond = 1
               else
                   inibond = lastbond(inva(atom)-1)+1
               endif
               do i=inibond,lastbond(inva(atom))
                    j=nbonds(i)
                    if (ibond(j).eq.inva(atom)) then
                         show_atom(jbond(j))=.true.
                    else
                         show_atom(ibond(j))=.true.
                    endif
                enddo
           enddo
           nint=0
           call notify('Atom(s) completed. ')
           command='DR'
      else if (command.eq.'CR') then
           call notify('rotating ... ')
      else
           command='  '
      endif
      return
      end
