! Copyright (C) GFD Dennou Club, 2000.  All rights reserved.

! ある次元 dimord についての入出力範囲を後方スライドする。
! 成功すれば stat=0, 範囲終了なら stat=GT_ENOMOREDIMS,
! エラーなら stat<0 (GT_ENOMOREDIMS 以外の値) となる。
! stride が全て 1 ならば、dimord=0 または dimord を欠いて
! ANVarSliceNext を呼べば全配列を走査することができる。

subroutine ANVarSliceNext(var, stat, dimord)
    use an_types, only: AN_VARIABLE
    use netcdf_f77, only: NF_NOERR, NF_EINVAL
    use dc_error, only: GT_ENOMOREDIMS
    implicit none
    type(AN_VARIABLE), intent(inout):: var
    integer, intent(out):: stat
    integer, intent(in), optional:: dimord
    integer:: idim, ilast, alldims
    ! イテレートしようがない変数では終端だと報告
    !  (何かのループで戻ってこられても困るがエラーにするほどではない)
    if (.not. (associated(var%start) .and. associated(var%count) &
    & .and. associated(var%stride) .and. associated(var%allcount))) then
        stat = GT_ENOMOREDIMS
        return
    endif
    ! 次元番号が指定されていない場合
    if (.not. present(dimord)) goto 100
    if (dimord == 0) goto 100
    ! 次元番号のエラー
    if (dimord < 0 .or. dimord > size(var%allcount)) then
        stat = NF_EINVAL
        return
    endif
    call internal_slice_next(dimord)
    return

    ! すべての次元について試してみる
100 continue
    do, idim = 1, size(var%allcount)
        call internal_slice_next(idim)
        if (stat == 0) exit
    enddo
    return
contains

    subroutine internal_slice_next(id)
        integer, intent(in):: id
        ! 次のスライスの最大添字が次元長を超えたら終端
        ilast = var%start(id) + (var%count(id) * 2 - 1) * var%stride(id)
        if (ilast > var%allcount(id)) then
            stat = GT_ENOMOREDIMS
            return
        endif
        ! スライスを進める処理
        var%start(id) = var%start(id) + var%count(id) * var%stride(id)
        stat = 0
    end subroutine internal_slice_next

end subroutine ANVarSliceNext
