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

subroutine ANVarGetReal(var, value, nvalue, err)
    use an_types, only: AN_VARIABLE
    use netcdf_f77
    use dc_error
    type(AN_VARIABLE), intent(inout):: var
    real, intent(out):: value(*)
    integer, intent(in):: nvalue
    logical, intent(out):: err
    real, allocatable:: buffer(:)
    integer:: siz, stat, i
    if (associated(var%count)) then
        siz = product(var%count)
    else
        siz = 1
    endif
    allocate (buffer(siz))
    if (var%varid > 0) then
        stat = nf_get_vars_real(var%fileid, var%varid, &
            start=var%start, count=var%count, stride=var%stride, &
            rvals=buffer)
    else if (var%dimid >= 1) then
        buffer(1: siz) = (/(real(i), i = var%start(1), &
            (var%start(1) + var%stride(1) * (var%count(1) - 1)))/)
    else
        stat = NF_ENOTVAR
        goto 999
    endif
    siz = min(siz, nvalue)
    value(1: siz) = buffer(1: siz)
    deallocate(buffer)
999 continue
    call StoreError(stat, "ANVarGetReal", err)
end subroutine

subroutine ANVarGetReal1(var, value, err)
    use an_types, only: AN_VARIABLE
    use dc_error
    use netcdf_f77
    type(AN_VARIABLE), intent(inout):: var
    real, pointer:: value(:)
    logical, intent(out), optional:: err
    integer:: stat, ix, nx, ndims, i
    ndims = size(var%allcount)
    if (ndims < 1) then
        stat = NF_EINVALCOORDS
        goto 999
    endif
    !
    ! 入力対象次元を決める
    !
    do, ix = 1, ndims
        if (var%count(ix) > 1) exit
    enddo
    if (ix > ndims) ix = 1
    ! ix 番目の次元の入力範囲が1の場合最大化する
    if (var%count(ix) <= 1) then
        var%start(ix) = 1
        var%stride(ix) = 1
        var%count(ix) = var%allcount(ix)
    endif
    nx = var%count(ix)
    !
    ! 入力変数を確保
    !
    allocate(value(nx), stat=stat)
    if (stat /= 0) then
        stat = NF_ENOMEM
        goto 999
    endif
    !
    ! いざ入力!
    !
    if (var%varid >= 1) then
        stat = nf_get_vars_real(var%fileid, var%varid, &
            start=var%start, count=var%count, stride=var%stride, &
            rvals=value)
    else if (var%dimid >= 1) then
        value(1: nx) = (/(real(i), i = var%start(ix), &
            (var%start(ix) + var%stride(ix) * (var%count(ix) - 1)))/)
    else
        stat = NF_ENOTVAR
    endif
999 continue
    call StoreError(stat, "ANVarGetReal1", err)
end subroutine

subroutine ANVarGetReal2(var, value, err)
    use an_types, only: AN_VARIABLE
    use netcdf_f77
    use dc_error
    type(AN_VARIABLE), intent(inout):: var
    real, pointer:: value(:, :)
    logical, intent(out), optional:: err
    integer:: stat, ix, iy, nx, ny, ndims
    ndims = size(var%allcount)
    if (ndims < 2) then
        call StoreError(NF_EINVALCOORDS, "ANVarGetReal2", err)
        return
    endif
    !
    ! 入力対象次元を決める
    !
    do, ix = 1, ndims
        if (var%count(ix) > 1) exit
    enddo
    if (ix > ndims) ix = 1
    do, iy = ix + 1, ndims
        if (var%count(ix) > 1) exit
    enddo
    if (iy > ndims) iy = ix + 1
    if (iy > ndims) then
        iy = ix
        ix = 1
        if (iy == ix) iy = 2
    endif
    ! 入力範囲が1の場合最大化する
    if (var%count(ix) == 1) then
        var%start(ix) = 1
        var%stride(ix) = 1
        var%count(ix) = var%allcount(ix)
    endif
    if (var%count(iy) == 1) then
        var%start(iy) = 1
        var%stride(iy) = 1
        var%count(iy) = var%allcount(iy)
    endif
    nx = var%count(ix)
    ny = var%count(iy)
    ! 
    ! 3 次元以上の変数であっては困るので var%count をスライス
    !
    var%count(:) = 1
    var%count((/ix, iy/)) = (/nx, ny/)
    !
    ! 入力変数を確保
    !
    allocate(value(nx, ny), stat=stat)
    if (stat /= 0) then
        call StoreError(NF_ENOMEM, "ANVarGetReal2", err)
        return
    endif
    !
    ! いざ入力!
    !
    stat = nf_get_vars_real(var%fileid, var%varid, &
        start=var%start, count=var%count, stride=var%stride, &
        rvals=value)
    call StoreError(stat, "ANVarGetReal2", err)
end subroutine

subroutine ANVarGetReal3(var, value, err)
    use an_types, only: AN_VARIABLE
    use dc_error
    type(AN_VARIABLE), intent(inout):: var
    real, pointer:: value(:, :, :)
    logical, intent(out), optional:: err
    if (associated(value)) value = -999.0
    call StoreError(GT_EFAKE, "ANVarGetReal3", err)
end subroutine



subroutine ANVarGetDouble(var, value, nvalue, err)
    use an_types, only: AN_VARIABLE
    use netcdf_f77
    use dc_error
    type(AN_VARIABLE), intent(inout):: var
    double precision, intent(out):: value(*)
    integer, intent(in):: nvalue
    logical, intent(out):: err
    double precision, allocatable:: buffer(:)
    integer:: siz, stat, i
    if (associated(var%count)) then
        siz = product(var%count)
    else
        siz = 1
    endif
    allocate (buffer(siz))
    if (var%varid > 0) then
        stat = nf_get_vars_double(var%fileid, var%varid, &
            start=var%start, count=var%count, stride=var%stride, &
            dvals=buffer)
    else if (var%dimid >= 1) then
        buffer(1: siz) = (/(real(i), i = var%start(1), &
            (var%start(1) + var%stride(1) * (var%count(1) - 1)))/)
    else
        stat = NF_ENOTVAR
        goto 999
    endif
    siz = min(siz, nvalue)
    value(1: siz) = buffer(1: siz)
    deallocate(buffer)
999 continue
    call StoreError(stat, "ANVarGetDouble", err)
end subroutine

subroutine ANVarGetDouble1(var, value, err)
    use an_types, only: AN_VARIABLE
    use dc_error
    use netcdf_f77
    type(AN_VARIABLE), intent(inout):: var
    double precision, pointer:: value(:)
    logical, intent(out), optional:: err
    integer:: stat, ix, nx, ndims, i
    ndims = size(var%allcount)
    if (ndims < 1) then
        stat = NF_EINVALCOORDS
        goto 999
    endif
    !
    ! 入力対象次元を決める
    !
    do, ix = 1, ndims
        if (var%count(ix) > 1) exit
    enddo
    if (ix > ndims) ix = 1
    ! ix 番目の次元の入力範囲が1の場合最大化する
    if (var%count(ix) <= 1) then
        var%start(ix) = 1
        var%stride(ix) = 1
        var%count(ix) = var%allcount(ix)
    endif
    nx = var%count(ix)
    !
    ! 入力変数を確保
    !
    allocate(value(nx), stat=stat)
    if (stat /= 0) then
        stat = NF_ENOMEM
        goto 999
    endif
    !
    ! いざ入力!
    !
    if (var%varid >= 1) then
        stat = nf_get_vars_double(var%fileid, var%varid, &
            start=var%start, count=var%count, stride=var%stride, &
            dvals=value)
    else if (var%dimid >= 1) then
        value(1: nx) = (/(real(i), i = var%start(ix), &
            (var%start(ix) + var%stride(ix) * (var%count(ix) - 1)))/)
    else
        stat = NF_ENOTVAR
    endif
999 continue
    call StoreError(stat, "ANVarGetDouble1", err)
end subroutine

subroutine ANVarGetDouble2(var, value, err)
    use an_types, only: AN_VARIABLE
    use netcdf_f77
    use dc_error
    type(AN_VARIABLE), intent(inout):: var
    double precision, pointer:: value(:, :)
    logical, intent(out), optional:: err
    integer:: stat, ix, iy, nx, ny, ndims
    ndims = size(var%allcount)
    if (ndims < 2) then
        call StoreError(NF_EINVALCOORDS, "ANVarGetDouble2", err)
        return
    endif
    !
    ! 入力対象次元を決める
    !
    do, ix = 1, ndims
        if (var%count(ix) > 1) exit
    enddo
    if (ix > ndims) ix = 1
    do, iy = ix + 1, ndims
        if (var%count(ix) > 1) exit
    enddo
    if (iy > ndims) iy = ix + 1
    if (iy > ndims) then
        iy = ix
        ix = 1
        if (iy == ix) iy = 2
    endif
    ! 入力範囲が1の場合最大化する
    if (var%count(ix) == 1) then
        var%start(ix) = 1
        var%stride(ix) = 1
        var%count(ix) = var%allcount(ix)
    endif
    if (var%count(iy) == 1) then
        var%start(iy) = 1
        var%stride(iy) = 1
        var%count(iy) = var%allcount(iy)
    endif
    nx = var%count(ix)
    ny = var%count(iy)
    ! 
    ! 3 次元以上の変数であっては困るので var%count をスライス
    !
    var%count(:) = 1
    var%count((/ix, iy/)) = (/nx, ny/)
    !
    ! 入力変数を確保
    !
    allocate(value(nx, ny), stat=stat)
    if (stat /= 0) then
        call StoreError(NF_ENOMEM, "ANVarGetDouble2", err)
        return
    endif
    !
    ! いざ入力!
    !
    stat = nf_get_vars_double(var%fileid, var%varid, &
        start=var%start, count=var%count, stride=var%stride, &
        dvals=value)
    call StoreError(stat, "ANVarGetDouble2", err)
end subroutine

subroutine ANVarGetDouble3(var, value, err)
    use an_types, only: AN_VARIABLE
    use dc_error
    type(AN_VARIABLE), intent(inout):: var
    double precision, pointer:: value(:, :, :)
    logical, intent(out), optional:: err
    if (associated(value)) value = -999.0
    call StoreError(GT_EFAKE, "ANVarGetDouble3", err)
end subroutine



subroutine ANVarPutReal(var, value, nvalue, err)
    use an_types, only: AN_VARIABLE
    use dc_error
    use netcdf_f77
    use an_file, only: ANFileDataMode
    type(AN_VARIABLE), intent(inout):: var
    real, intent(in):: value(*)
    integer, intent(in):: nvalue
    logical, intent(out):: err
    integer:: stat
    stat = NF_NOERR
    if (var%varid <= 0) then
        stat = NF_ENOTVAR;  goto 999
    endif
    stat = ANFileDataMode(var%fileid)
    if (stat /= NF_NOERR) goto 999
    if (associated(var%count)) then
        stat = NF_EINVAL 
        if (nvalue < product(var%count)) goto 999
        stat = nf_put_vars_real(var%fileid, var%varid, &
            start=var%start, count=var%count, stride=var%stride, &
            rvals=value)
    else
        stat = NF_EINVAL 
        if (nvalue < 1) goto 999
        stat = nf_put_var_real(var%fileid, var%varid, rvals=value)
    endif
999 continue
    call StoreError(stat, "ANVarPutReal", err)
end subroutine

subroutine ANVarPutReal1(var, value, err)
    use an_types, only: AN_VARIABLE
    use dc_error
    type(AN_VARIABLE), intent(inout):: var
    real, intent(in):: value(:)
    logical, intent(out), optional:: err
    call StoreError(GT_EFAKE, "ANVarPutReal1", err)
end subroutine

subroutine ANVarPutReal2(var, value, err)
    use an_types, only: AN_VARIABLE
    use dc_error
    type(AN_VARIABLE), intent(inout):: var
    real, intent(in):: value(:, :)
    logical, intent(out), optional:: err
    call StoreError(GT_EFAKE, "ANVarPutReal2", err)
end subroutine

subroutine ANVarPutReal3(var, value, err)
    use an_types, only: AN_VARIABLE
    use dc_error
    type(AN_VARIABLE), intent(inout):: var
    real, intent(in):: value(:, :, :)
    logical, intent(out), optional:: err
    call StoreError(GT_EFAKE, "ANVarPutReal3", err)
end subroutine

subroutine ANVarPutDouble(var, value, nvalue, err)
    use an_types, only: AN_VARIABLE
    use dc_error
    use netcdf_f77
    use an_file, only: ANFileDataMode
    type(AN_VARIABLE), intent(inout):: var
    double precision, intent(in):: value(*)
    integer, intent(in):: nvalue
    logical, intent(out):: err
    integer:: stat
    stat = NF_NOERR
    if (var%varid <= 0) then
        stat = NF_ENOTVAR;  goto 999
    endif
    stat = ANFileDataMode(var%fileid)
    if (stat /= NF_NOERR) goto 999
    if (associated(var%count)) then
        stat = NF_EINVAL 
        if (nvalue < product(var%count)) goto 999
        stat = nf_put_vars_double(var%fileid, var%varid, &
            start=var%start, count=var%count, stride=var%stride, &
            dvals=value)
    else
        stat = NF_EINVAL 
        if (nvalue < 1) goto 999
        stat = nf_put_var_double(var%fileid, var%varid, dvals=value)
    endif
999 continue
    call StoreError(stat, "ANVarPutDouble", err)
end subroutine

subroutine ANVarPutDouble1(var, value, err)
    use an_types, only: AN_VARIABLE
    use dc_error
    type(AN_VARIABLE), intent(inout):: var
    double precision, intent(in):: value(:)
    logical, intent(out), optional:: err
    call StoreError(GT_EFAKE, "ANVarPutDouble1", err)
end subroutine

subroutine ANVarPutDouble2(var, value, err)
    use an_types, only: AN_VARIABLE
    use dc_error
    type(AN_VARIABLE), intent(inout):: var
    double precision, intent(in):: value(:, :)
    logical, intent(out), optional:: err
    call StoreError(GT_EFAKE, "ANVarPutDouble2", err)
end subroutine

subroutine ANVarPutDouble3(var, value, err)
    use an_types, only: AN_VARIABLE
    use dc_error
    type(AN_VARIABLE), intent(inout):: var
    double precision, intent(in):: value(:, :, :)
    logical, intent(out), optional:: err
    call StoreError(GT_EFAKE, "ANVarPutDouble3", err)
end subroutine
