      program rstime
c***********************************************************************
c Change the time (ibuf2) and/or time related elements of the DATA
c records in an agcm restart file.
c
c Larry Solheim ...Apr,2009
c
c***********************************************************************

      implicit none

c.....dimension sizes
      integer, parameter :: maxx=1169642
      integer, parameter :: nd_max=1000

c.....misc
      character(len=80) :: outname=' '
      real :: data1(nd_max), data2(nd_max), data3(nd_max)
      logical :: ok
      integer :: i,j,k,l,m,n
      integer, parameter :: iuin=1, iuout=2
      integer :: ndata1, ndata2, ndata3
      integer :: ios
      integer :: nc4to8
      integer :: verbose=1
      integer :: mon,dom,hour,steps_per_day,steps_per_year
      integer :: restart_year=-1
      integer :: restart_month=12
      integer :: monthd(12)
      data monthd/31,59,90,120,151,181,212,243,273,304,334,365/

c.....data record parameters that are (possibly) modified
      integer :: old_kount, kount = -1   ! current timestep number
      integer ::  old_iday, iday  = -1   ! day of the year
      integer ::  old_lday, lday  = -1   ! first day of next month
      integer ::  old_mday, mday  = -1   ! next mid month day (gt,sic,sicn)
      integer :: old_mdayt, mdayt = -1   ! next mid month day (chemistry forcing)
      integer :: old_ndays, ndays = -1   ! number of days since kount=0
      integer :: old_nsecs, nsecs = -1   ! number of seconds elapsed in the current day
      integer :: old_iyear, iyear = -1   ! current year
      integer :: old_iymdh, iymdh = -1   ! current date encoded as yyyymmddhh
      real    ::  old_delt,  delt = -1.0 ! model time step in seconds

c.....IO buffer
      integer :: ibuf(8),idat(2*maxx)
      common /icom/ ibuf,idat
      real :: wrk(maxx)

c.....space for a list of file names input on the command line
      character(len=256), dimension(10) :: flist=" "
      integer :: nfiles

c.....file names
      character(len=256) :: rsin,rsout

c.....usage info
      character(120) :: usage(100)
      integer        :: use_lines

c.....used to store command line arguments
      integer*4 iargc,iarg
      integer nargs
      character(256) :: clarg,strng
      character(256) :: var,val

c.....machine word size info
      integer :: me32o64,inteflt
      external   me32o64,inteflt

      integer ::       machine,intsize
      common /machtyp/ machine,intsize

c-----------------------------------------------------------------------
c.....Initialize machine and intsize (required for io routines)
      machine = me32o64(i)
      intsize = inteflt(i)

c-----------------------------------------------------------------------
c.....Define a usage message
      usage(1) ='Usage: rstime [options] RSIN RSOUT'
      usage(2) ='  RSIN is an existing restart file'
      usage(2) ='  RSOUT is the restart file to be created'
      usage(3) ='Options:'
      usage(4) ='  -h'
      usage(5) ='    ..display this usage message'
      usage(6) ='  out=fname'
      usage(7) ='    ..output file name (RSOUT overrides this)'
      usage(8) ='  kount=int'
      usage(9) ='    ..reset kount (ibuf2) in output restart file'
      usage(10) ='  iyear=year'
      usage(11) ='    ..reset iyear in output restart file'
      usage(12) ='  restart_year=year'
      usage(13) ='    ..set parameters for a restart year'
      usage(14) ='  restart_month=month'
      usage(15) ='    ..set parameters for a restart month. default 12'
      usage(16) ='  delt=delt'
      usage(17) ='    ..reset delt in the output restart file'
      use_lines= 17

c-----------------------------------------------------------------------
c.....Process command line arguments
      nfiles=0
      nargs=iargc()
      if (nargs.gt.0) then
        do i=1,nargs
          iarg=i
          call getarg(iarg,clarg)
          if (clarg(1:1).eq.'-') then
            !--- This is an option
            if (clarg(1:2).eq.'-h') then
              !--- print the usage message and exit
              do k=1,use_lines
                write(6,*)trim(usage(k))
              enddo
              call xit("RSTIME",-11)
            else
              write(6,*)'RSTIME: Unknown command line option ',
     &                 trim(clarg)
              do k=1,use_lines
                write(6,*)trim(usage(k))
              enddo
              call xit("RSTIME",-12)
            endif
          else if (index(clarg,'=').gt.0) then
            !--- This argument is of the form vname=value
            k=index(clarg,'=')
            if (k.eq.1) then
              write(6,*)'RSTIME: Invalid parameter definition ',
     &                 trim(adjustl(clarg))
              do k=1,use_lines
                write(6,*)trim(usage(k))
              enddo
              call xit("RSTIME",-13)
            endif
            var=' '
            val=' '
            var=trim(adjustl(clarg(1:k-1)))
            val=trim(adjustl(clarg(k+1:)))
            if (len_trim(var) .le. 0) then
              write(6,*)'RSTIME: Invalid parameter definition ',
     &                 trim(adjustl(clarg))
              do k=1,use_lines
                write(6,*)trim(usage(k))
              enddo
              call xit("RSTIME",-14)
            endif
            if (len_trim(val) .le. 0) then
              write(6,*)'RSTIME: ',trim(var),
     &                 ' was supplied with a missing value.'
              do k=1,use_lines
                write(6,*)trim(usage(k))
              enddo
              call xit("RSTIME",-15)
            endif
            select case (trim(adjustl(var)))
              case ('out') !--- Set the output file name
                outname = ' '
                outname = trim(val)
              case ('kount')
                if (verify(trim(val),'+-.0123456789eEdD') .ne. 0) then
                  !--- This will find multiple or invalid numbers
                  write(6,*)trim(val),' is not a valid number'
                  call xit("RSTIME",-16)
                endif
                read(val,*,iostat=ios)kount
                if (ios.ne.0) then
                  !--- This will trap everything else
                  write(6,*)'Error ',ios,' reading value ',trim(val)
                  call xit("RSTIME",-17)
                endif
              case ('iyear')
                if (verify(trim(val),'+-.0123456789eEdD') .ne. 0) then
                  !--- This will find multiple or invalid numbers
                  write(6,*)trim(val),' is not a valid number'
                  call xit("RSTIME",-18)
                endif
                read(val,*,iostat=ios)iyear
                if (ios.ne.0) then
                  !--- This will trap everything else
                  write(6,*)'Error ',ios,' reading value ',trim(val)
                  call xit("RSTIME",-19)
                endif
              case ('restart_year')
                if (verify(trim(val),'+-.0123456789eEdD') .ne. 0) then
                  !--- This will find multiple or invalid numbers
                  write(6,*)trim(val),' is not a valid number'
                  call xit("RSTIME",-20)
                endif
                read(val,*,iostat=ios)restart_year
                if (ios.ne.0) then
                  !--- This will trap everything else
                  write(6,*)'Error ',ios,' reading value ',trim(val)
                  call xit("RSTIME",-21)
                endif
              case ('restart_month')
                if (verify(trim(val),'+-.0123456789eEdD') .ne. 0) then
                  !--- This will find multiple or invalid numbers
                  write(6,*)trim(val),' is not a valid number'
                  call xit("RSTIME",-201)
                endif
                read(val,*,iostat=ios)restart_month
                if (ios.ne.0) then
                  !--- This will trap everything else
                  write(6,*)'Error ',ios,' reading value ',trim(val)
                  call xit("RSTIME",-211)
                endif
                if(restart_month.gt.12.or.restart_month.lt.1)
     &               call xit("RSTIME",-212)
              case ('delt')
                if (verify(trim(val),'+-.0123456789eEdD') .ne. 0) then
                  !--- This will find multiple or invalid numbers
                  write(6,*)trim(val),' is not a valid number'
                  call xit("RSTIME",-22)
                endif
                read(val,*,iostat=ios)delt
                if (ios.ne.0) then
                  !--- This will trap everything else
                  write(6,*)'Error ',ios,' reading value ',trim(val)
                  call xit("RSTIME",-22)
                endif
              case default
                write(6,*)'Invalid variable name ',trim(var)
                call xit("RSTIME",-24)
            end select
          else
            !--- This is assumed to be a file name
            nfiles=nfiles+1
            flist(nfiles)=clarg
          endif
        enddo
      endif

      if (nfiles.le.0) then
        write(6,*)'RSTIME: There must be at least one file',
     &            ' name specified on the command line.'
        do k=1,use_lines
          write(6,*)trim(usage(k))
        enddo
        call xit("RSTIME",-1)
      endif

      !--- Determine input and output file names
      rsin=flist(1)
      rsout=' '
      if (nfiles.gt.1) then
        rsout=trim(flist(2))
      else if (len_trim(outname).gt.0) then
          rsout=trim(outname)
      endif
      if (len_trim(rsout).le.0) then
        write(6,*)'No output file name supplied on the command line.'
        call xit("RSTIME",-2)
      endif

      if (verbose.gt.0) then
        write(6,*)'Input  restart file: ',trim(rsin)
        write(6,*)'Output restart file: ',trim(rsout)
      endif

      !--- open the input restart file
      open(iuin,file=trim(rsin),form='unformatted')
      rewind iuin

      !--- Initialize data records to zero
      data1(:)=0.0
      data2(:)=0.0
      data3(:)=0.0

      !--- read the first DATA record from the rs file
      call getfld2(iuin,data1,nc4to8("DATA"),-1,nc4to8("DATA"),1,
     &             ibuf,maxx,ok)
      ndata1=ibuf(5)
      if (verbose.gt.1) then
        write(6,'(a,1x,a4,1x,i10,1x,a4,1x,5i8)')" READ: ",ibuf(1:8)
      endif
      if (.not.ok) call xit("RSTIME",-3)
      if (verbose.gt.2) write(6,*)'DATA 1: ',data1(1:ndata1)

      !--- read the second DATA record from the rs file
      call getfld2(iuin,data2,nc4to8("DATA"),-1,nc4to8("DATA"),2,
     &             ibuf,maxx,ok)
      ndata2=ibuf(5)
      if (verbose.gt.1) then
        write(6,'(a,1x,a4,1x,i10,1x,a4,1x,5i8)')" READ: ",ibuf(1:8)
      endif
      if (.not.ok) call xit("RSTIME",-4)
      if (verbose.gt.2) write(6,*)'DATA 2: ',data2(1:ndata2)

      !--- read the third DATA record from the rs file (if it exists)
      call getfld2(iuin,data3,nc4to8("DATA"),-1,nc4to8("DATA"),3,
     &             ibuf,maxx,ok)
      if (ok) then
        ndata3=ibuf(5)
        old_iyear = data3(1)
        old_iymdh = data3(2)
        if (verbose.gt.1) then
          write(6,'(a,1x,a4,1x,i10,1x,a4,1x,5i8)')" READ: ",ibuf(1:8)
        endif
        if (verbose.gt.2) write(6,*)'DATA 3: ',data3(1:ndata3)
      else
        ndata3=0
        !--- Set iyear to a default value
        old_iyear = 2000
        old_iymdh = 2000010100
      endif

      !--- store old parameter values
      old_kount = nint(data1(1))
      old_delt  = data2(4)
      old_iday  = nint(data2(5))
      old_lday  = nint(data2(6))
      old_mday  = nint(data2(7))
      old_mdayt = nint(data2(8))
      old_ndays = nint(data2(9))
      old_nsecs = nint(data2(10))

      !--- set output values from existing restart unless
      !--- they have been specified on the command line
      if ( iday.lt.0)  iday=old_iday
      if ( lday.lt.0)  lday=old_lday
      if ( mday.lt.0)  mday=old_mday
      if (mdayt.lt.0) mdayt=old_mdayt
      if (ndays.lt.0) ndays=old_ndays
      if (nsecs.lt.0) nsecs=old_nsecs
      if ( delt.lt.0)  delt=old_delt

      if (delt.le.0.0) then
        write(6,*)'Invalid delt=',delt
        call xit("RSTIME",-5)
      endif

      !--- determine the number of time steps per day and per year
      steps_per_day=nint(86400.0/delt)
      steps_per_year=nint((86400.0*365.0)/delt)

      if (restart_year.gt.0) then
        write(*,*)'restart_year=',restart_year
        write(*,*)'restart_month=',restart_month
        !--- Assume that the output restart file is for last day of restart_month of restart_year
        !--- set kount such that kount=0 corresponds to 00Z on Jan 1 of year 1
        kount=(restart_year-1)*steps_per_year+
     &       monthd(restart_month)*steps_per_day
        !--- Set ndays to correspond with this kount value
        ndays=kount/steps_per_day
        !--- Set other parameters to correspond to 1st of the next month
        if(restart_month.eq.12) then
          iday=1
          lday=1
          mday=366
          if (ndata3.gt.0) then
            mdayt=16
          else
            mdayt=1
          endif
          nsecs=0
        else
          write(*,*)'iday=',iday
          write(*,*)'lday=',lday
          write(*,*)'mday=',mday
          write(*,*)'mdayt=',mdayt
        endif
      endif

      !--- special treatment for iyear
      if (iyear.lt.0) then
        !--- if iyear is not set on the command line then
        !--- use the value found in the old restart file or
        !--- the default values, if not found in old restart
        iyear=old_iyear
        iymdh=old_iymdh
      else
        !--- if iyear is set on the command line then use this value
        !--- to determine iymdh
        if(restart_month.eq.12) then
          mon=1
        else
          mon=restart_month+1
        endif
        dom=1
        hour=0
        iymdh=iyear*1000000+mon*10000+dom*100+hour
      endif

      !--- special treatment for kount
      if (kount.lt.0) then
        !--- if kount is not set on the command line nor is it set according
        !--- to iyear then use the value found in the old restart file
        kount=old_kount
      else
        !--- if kount is set on the command line then use this kount value
        !--- to determine a consistent set of all parameter values
        ndays=kount/steps_per_day
        iday=mod(ndays,365)+1
      endif

      !--- Reassign data record values with (possibly) modified
      !--- kount,delt,iday,lday,mday,mdayt,ndays,nsecs,iyear,iymdh
      data1(1)  = kount
      data2(4)  = delt
      data2(5)  = iday
      data2(6)  = lday
      data2(7)  = mday
      data2(8)  = mdayt
      data2(9)  = ndays
      data2(10) = nsecs
      data3(1)  = iyear
      data3(2)  = iymdh

      if (verbose.gt.0) then
        write(6,*)'kount: old=',old_kount
        write(6,*)'       new=',kount
        write(6,*)' iday: old=',old_iday
        write(6,*)'       new=',iday
        write(6,*)' lday: old=',old_lday
        write(6,*)'       new=',lday
        write(6,*)' mday: old=',old_mday
        write(6,*)'       new=',mday
        write(6,*)'mdayt: old=',old_mdayt
        write(6,*)'       new=',mdayt
        write(6,*)'ndays: old=',old_ndays
        write(6,*)'       new=',ndays
        write(6,*)'nsecs: old=',old_nsecs
        write(6,*)'       new=',nsecs
        write(6,*)'iyear: old=',old_iyear
        write(6,*)'       new=',iyear
        write(6,*)'iymdh: old=',old_iymdh
        write(6,*)'       new=',iymdh
        write(6,*)' delt: old=',old_delt
        write(6,*)'       new=',delt
      endif

      !--- rewind the input restart file
      rewind iuin

      !--- open the output restart file
      open(iuout,file=trim(rsout),form='unformatted')
      rewind iuout

      !--- Copy the input file to the output file replacing DATA records
      !--- and resetting the kount (ibuf2) value
      ok=.true.
      do while (ok)
        call getfld2(iuin,wrk,-1,-1,-1,-1,ibuf,maxx,ok)
        if (.not.ok) exit

        ibuf(2)=kount

        if (ibuf(3).eq.nc4to8("DATA")) then
          if (ibuf(4).eq.1) then
            !--- first DATA record
            call putfld2(iuout,data1,ibuf,maxx)
          else if (ibuf(4).eq.2) then
            !--- second DATA record
            call putfld2(iuout,data2,ibuf,maxx)
          else if (ibuf(4).eq.3) then
            !--- third DATA record
            call putfld2(iuout,data3,ibuf,maxx)
          else
            write(6,*)'Invalid DATA record. ibuf(4)=',ibuf(4)
            call xit("RSTIME",-6)
          endif
        else
          !--- Otherwise copy the record verbatim
          call putfld2(iuout,wrk,ibuf,maxx)
        endif
 
      enddo

      close(iuin)
      close(iuout)

      if (verbose.gt.0) then
        write(6,*)'Created new restart file ',trim(rsout),
     &    ' from existing file ',trim(rsin)
      endif

      call xit('RSTIME',0)
      end
