! an_generic.f90 - 抽象 netCDF インターフェイスの総称宣言
! Copyright (C) GFD Dennou Club, 2000.  All rights reserved.


module an_generic

    !
    ! === 基本開閉動作 ===
    !

    !
    ! an ライブラリでは「ファイル」ではなく「変数」を開いたり閉じたりする。
    ! すべてのものは変数とその属性である。

    interface open
        ! 
        ! open(var, url, [writable], [err]) は url で識別される
        ! 変数を開き var に格納する。ここで変数とは netCDF 変数または
        ! netCDF 次元である。次元と同名の netCDF 変数がある場合には両者は
        ! 同一視される。writable を真に指定すると書き込み可で開こうとする。
        ! デフォルトは writable=.FALSE. である。エラーが発生した場合は
        ! err が真となる。err を与えなければプログラムは停止する。
        !
        recursive subroutine ANVarOpen(var, url, writable, err)
            use dc_string, only: VSTRING    
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: var
            type(VSTRING), intent(in):: url
            logical, intent(in), optional:: writable
            logical, intent(out), optional:: err
        end subroutine
        !
        ! open(dimvar, var, dimord, [count_compact], [err]) は
        ! 既に開かれた変数 var の ord 番目の次元にあたる変数を
        ! 開き dimvar に格納する。順序 ord は現在の入出力範囲が
        ! 幅１になっている (コンパクト化している）を飛ばした
        ! 順序であるが、count_compact に真を指定すると
        ! すべての次元のなかの順序になる。
        !
        subroutine ANVarOpenByDimOrd(dimvar, var, dimord, &
            count_compact, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: dimvar
            type(AN_VARIABLE), intent(in):: var
            integer, intent(in):: dimord
            logical, intent(in), optional:: count_compact
            logical, intent(out), optional:: err
        end subroutine
    end interface

    interface create
        !
        ! 従属変数 create
        !
        ! create(var, url, dims, [xtype], [overwrite], [err]) は
        ! 場所 url に次元 dims を持った変数を作成し、それを開いた
        ! ものを var に格納する。型 xtype を省略すると real と
        ! みなされる。既存変数があるとき失敗するが
        ! overwrite が真であれば続行する。
        ! ゼロ次元変数を作るには dims に長さゼロの配列を渡すこと。
        !
        subroutine ANVarCreate(var, url, xtype, dims, overwrite, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: var
            character(len = *), intent(in):: url
            character(len = *), intent(in):: xtype
            type(AN_VARIABLE), intent(in):: dims(:)
            logical, intent(in), optional:: overwrite
            logical, intent(out), optional:: err
        end subroutine
        !
        ! 次元変数 create
        !
        ! create(var, url, xtype, length, [overwrite], [err]) は
        ! 長さ length の次元変数を作成する。
        !
        subroutine ANVarCreateD(var, url, xtype, length, overwrite, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: var
            character(len = *), intent(in):: url
            character(len = *), intent(in):: xtype
            integer, intent(in):: length
            logical, intent(in), optional:: overwrite
            logical, intent(out), optional:: err
        end subroutine
    end interface

    interface close
        subroutine ANVarClose(var, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: var
            logical, intent(out), optional:: err
        end subroutine
    end interface

    !
    ! === 変数に関する問い合わせ万般 ===
    !

    ! おもに PRINT デバッグ用。
    interface toString
        type(VSTRING) function ANVarToString(var)
            use dc_string, only: VSTRING
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
        end function
    end interface

    interface inquire

        ! --- 変数の次元数 ---
        ! 変数は状態として slice で設定される入出力範囲を記憶している。
        ! ndims は現在の入出力範囲の次元数を返す。
        ! 変数全体の入出力範囲を得るには alldims を用いる。

        subroutine ANVarInquire(var, xtype, ndims, alldims, name, url, allcount)
            use an_types, only: AN_VARIABLE
            use dc_string, only: VSTRING
            type(AN_VARIABLE), intent(in):: var
            type(VSTRING), intent(out), optional:: xtype, name, url
            integer, intent(out), optional:: ndims, alldims, allcount
        end subroutine

        subroutine ANAttrInquire(var, attrname, xtype)
            use an_types, only: AN_VARIABLE
            use dc_string, only: VSTRING
            type(AN_VARIABLE), intent(in):: var
            character(len=*), intent(in):: attrname
            type(VSTRING), intent(out), optional:: xtype
        end subroutine

    end interface

    !
    ! === 属性関係 ===
    !

    ! すべては変数という an ライブラリの立場から、
    ! 大域属性は変数属性とみなされる。
    ! 属性読み取り時には変数属性の次に大域属性を検索する。
    ! 属性書き込み時には一部の例外を除き変数属性として書き込む。
    ! gtool4 規約で大域属性と規定された属性 Conventions,
    ! gt_version, title, gt_subtitle, comment, source,
    ! institution, production, history についてはまず
    ! 大域属性として書き込もうとする。既存の値があった
    ! 場合 Conventions, gt_version は gtool4 同士ならば
    ! 版数が大きくなるようにする。history は規定どおり
    ! 追加動作を行う。その他の属性名については既存と異なる
    ! 属性値があれば変数属性として書き込む。

    !
    ! --- 属性の列挙 ---
    !

    ! ある変数 var に付随した属性をすべて取得するにはまず
    ! attr_rewind(var) を呼び出してから無限ループの中で
    ! attr_next(var, name, [end]) を呼び出す。name がひとつ
    ! ひとつの属性名を与える。name が空文字列になったとき、
    ! すべての属性を探索し終えたことになる。このとき end を
    ! 与えていればそれが真になることでも判定できる。

    interface attr_rewind
        subroutine ANVarAttrRewind(var)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: var
        end subroutine
    end interface

    interface attr_next
        subroutine ANVarAttrNext(var, name, end)
            use an_types, only: AN_VARIABLE
            use dc_string, only: VSTRING    
            type(AN_VARIABLE), intent(inout):: var
            type(VSTRING), intent(out):: name
            logical, intent(out), optional:: end
        end subroutine
    end interface

    ! 変数 var の属性 name を取得し存在すればそれを真偽値と
    ! して解釈して返す。属性が存在しなければ default を
    ! 返す。このとき default を省略すると偽を返す。

    interface attr_true
        logical function ANVarAttrTrue(var, name, default)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            character(len = *), intent(in):: name
            logical, intent(in), optional:: default
        end function
    end interface

    ! 変数 var の属性 name を取得して value に格納する。
    ! 属性が存在しないか value の長さが不足している場合
    ! default が補われる。属性の型はなんでもよく型変換をする。

    interface get_attr

        subroutine ANVarGetAttrSC(var, name, value, default)
            use dc_string, only: VSTRING    
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            character(len = *), intent(in):: name
            type(VSTRING), intent(out):: value
            character(len = *), intent(in), optional:: default
        end subroutine

        ! attr_true と得られる情報は同じ
        subroutine ANVarGetAttrLogical(var, name, value, default)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            character(len = *), intent(in):: name
            logical, intent(out):: value
            logical, intent(in), optional:: default
        end subroutine

        ! お客様向きではないけれど、情報落ちのないインターフェイスということで....
        ! stat = -1:  その属性は存在しなかった
        ! stat = 0 ... size(value):  その属性を全部読み取った。サイズは stat 個
        ! stat > size(value):  配列長不足のため属性が全部読み取れなかった。
        !                      サイズは stat 個必要

        subroutine ANVarGetAttrRA(var, name, value, stat, default)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            character(len = *), intent(in):: name
            real, intent(out):: value(:)
            integer, intent(out):: stat
            real, intent(in), optional:: default
        end subroutine

        subroutine ANVarGetAttrDA(var, name, value, stat, default)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            character(len = *), intent(in):: name
            double precision, intent(out):: value(:)
            integer, intent(out):: stat
            double precision, intent(in), optional:: default
        end subroutine

        subroutine ANVarGetAttrIA(var, name, value, stat, default)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            character(len = *), intent(in):: name
            integer, intent(out):: value(:)
            integer, intent(out):: stat
            integer, intent(in), optional:: default
        end subroutine

    end interface

    ! 変数 var の属性 name に value を格納する。
    ! 属性の型は value の型に適合するように設定される。
    ! 論理型は 1 文字の文字型として格納され、真は T,
    ! 偽は F となる。

    interface put_attr

        subroutine ANVarPutAttrReal(var, name, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            character(len = *), intent(in):: name
            real, intent(in):: value(:)
            logical, intent(out), optional:: err
        end subroutine

        subroutine ANVarPutAttrDouble(var, name, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            character(len = *), intent(in):: name
            double precision, intent(in):: value(:)
            logical, intent(out), optional:: err
        end subroutine

        subroutine ANVarPutAttrInt(var, name, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            character(len = *), intent(in):: name
            integer, intent(in):: value(:)
            logical, intent(out), optional:: err
        end subroutine

        subroutine ANVarPutAttrLogical(var, name, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            character(len = *), intent(in):: name
            logical, intent(in):: value
            logical, intent(out), optional:: err
        end subroutine

        subroutine ANVarPutAttrChar(var, name, value, xtype, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            character(len = *), intent(in):: name
            character(len = *), intent(in):: value
            character(len = *), intent(in), optional:: xtype
            logical, intent(out), optional:: err
        end subroutine

    end interface

    interface del_attr
        subroutine ANVarDelAttr(var, name, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            character(len = *), intent(in):: name
            logical, intent(out), optional:: err
        end subroutine
    end interface

    interface copy_attr
        subroutine ANVarAttrCopy(to, attrname, from, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: to
            character(len = *), intent(in):: attrname
            type(AN_VARIABLE), intent(in):: from
            logical, intent(out), optional:: err
        end subroutine
    end interface

    !
    ! === 次元関係 ===
    !
    ! an ライブラリの変数は netCDF の変数と次元を統合したもの
    ! である。次元構造体は存在しない。そこで、an の立場では
    ! 変数は任意個の次元と呼ばれる変数を持つということになる。
    ! 従来次元変数と呼ばれていたものは、変数が自分自身のみを
    ! 次元としてもつ場合を指す。

    ! --- 入出力範囲の設定 ---
    ! 変数 var の dimord
    ! dimord は 1 から alldims(var) の間である。コンパクト次元も数える。
    !

    interface slice

        ! 原始的界面。格子番号で開始、個数、間隔を指定
        ! start, count, stride のいずれかを省略すると、対応する指定を
        ! なるべく変更しないように動作する。
        ! 開始点には負値を指定できて、逆順に数えた位置を指す。
        ! 個数には負値を指定できて、絶対値が評価される。
        subroutine ANVarSlice(var, dimord, start, count, stride)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: var
            integer, intent(in):: dimord
            integer, intent(in), optional:: start
            integer, intent(in), optional:: count
            integer, intent(in), optional:: stride
        end subroutine

        ! 上位界面。座標変数の値による指定が可能。
        ! 下限省略時は座標変数の小さいほうが仮定される。
        ! ただし上限が格子番号指定である場合、1 となる。
        ! 上限省略時は座標変数の大きいほうが仮定される。
        ! ただし下限が格子番号指定である場合、-1 となる。
        ! 間隔省略時は連続走査が仮定される。
        subroutine ANVarSliceS4(var, dimname, lower, upper, interval)
            use an_types, only: AN_VARIABLE
            use dc_string, only: VSTRING
            type(AN_VARIABLE), intent(inout):: var
            type(VSTRING), intent(in):: dimname
            type(VSTRING), intent(in):: lower
            type(VSTRING), intent(in):: upper
            type(VSTRING), intent(in):: interval
        end subroutine
    end interface


    interface get_slice
        subroutine ANVarGetSlice(var, dimord, start, count, stride)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            integer, intent(in):: dimord
            integer, intent(out), optional:: start
            integer, intent(out), optional:: count
            integer, intent(out), optional:: stride
        end subroutine
    end interface

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

    interface slice_next
        subroutine ANVarSliceNext(var, stat, dimord)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: var
            integer, intent(out):: stat
            integer, intent(in), optional:: dimord
        end subroutine
    end interface

    !
    ! 入出力
    !

    interface get

        subroutine ANVarGetReal(var, value, nvalue, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: var
            real, intent(out):: value(*)
            integer, intent(in):: nvalue
            logical, intent(out):: err
        end subroutine

        subroutine ANVarGetReal1(var, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: var
            real, pointer:: value(:)
            logical, intent(out), optional:: err
        end subroutine

        subroutine ANVarGetReal2(var, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: var
            real, pointer:: value(:, :)
            logical, intent(out), optional:: err
        end subroutine

        subroutine ANVarGetReal3(var, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: var
            real, pointer:: value(:, :, :)
            logical, intent(out), optional:: err
        end subroutine

        subroutine ANVarGetDouble(var, value, nvalue, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: var
            double precision, intent(out):: value(*)
            integer, intent(in):: nvalue
            logical, intent(out):: err
        end subroutine

        subroutine ANVarGetDouble1(var, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: var
            double precision, pointer:: value(:)
            logical, intent(out), optional:: err
        end subroutine

        subroutine ANVarGetDouble2(var, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: var
            double precision, pointer:: value(:, :)
            logical, intent(out), optional:: err
        end subroutine

        subroutine ANVarGetDouble3(var, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout):: var
            double precision, pointer:: value(:, :, :)
            logical, intent(out), optional:: err
        end subroutine

    end interface

    interface put

        subroutine ANVarPutReal(var, value, nvalue, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            real, intent(in):: value(*)
            integer, intent(in):: nvalue
            logical, intent(out):: err
        end subroutine

        subroutine ANVarPutReal1(var, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            real, intent(in):: value(:)
            logical, intent(out), optional:: err
        end subroutine

        subroutine ANVarPutReal2(var, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            real, intent(in):: value(:, :)
            logical, intent(out), optional:: err
        end subroutine

        subroutine ANVarPutReal3(var, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            real, intent(in):: value(:, :, :)
            logical, intent(out), optional:: err
        end subroutine

        subroutine ANVarPutDouble(var, value, nvalue, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            double precision, intent(in):: value(*)
            integer, intent(in):: nvalue
            logical, intent(out):: err
        end subroutine

        subroutine ANVarPutDouble1(var, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            double precision, intent(in):: value(:)
            logical, intent(out), optional:: err
        end subroutine

        subroutine ANVarPutDouble2(var, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            double precision, intent(in):: value(:, :)
            logical, intent(out), optional:: err
        end subroutine

        subroutine ANVarPutDouble3(var, value, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            double precision, intent(in):: value(:, :, :)
            logical, intent(out), optional:: err
        end subroutine
    end interface

    !
    ! === ファイル名から変数をさがす ===
    !

    interface var_search
        
        subroutine ANVarSearchInit(iter, urlBase)
            use dc_string, only: VSTRING
            use an_types, only: AN_VARIABLE_SEARCH
            type(AN_VARIABLE_SEARCH), intent(out):: iter
            type(VSTRING), intent(in):: urlBase
        end subroutine

        subroutine ANVarSearchNext(iter, url, end)
            use dc_string, only: VSTRING
            use an_types, only: AN_VARIABLE_SEARCH
            type(AN_VARIABLE_SEARCH), intent(inout):: iter
            type(VSTRING), intent(out):: url
            logical, intent(out):: end
        end subroutine

    end interface        

    !
    ! 非常脱出用。このルーチンは SysDepAbort からも呼ばれるため、
    ! 自分で StoreError することはない。
    !

    interface
        subroutine ANVarSync(var, stat)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(inout), optional:: var
            integer, intent(out), optional:: stat
        end subroutine
    end interface

    !
    ! an 層の内部的使用のためのルーチン
    !
    interface
        subroutine ANXTypeName(ixtype, xtype)
            use dc_string, only: VSTRING
            integer, intent(in):: ixtype
            type(VSTRING), intent(out):: xtype
        end subroutine
    end interface

end module
