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


module an_generic

    use an_types, only: an_variable

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

    !
    ! 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 an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(out):: var
            character(len = *), intent(in):: url
            logical, intent(in), optional:: writable
            logical, intent(out), optional:: err
        end subroutine
        !
        ! an ライブラリの変数は netCDF の変数と次元を統合したもの
        ! である。次元構造体は存在しない。そこで、an の立場では
        ! 変数は任意個の次元と呼ばれる変数を持つということになる。
        ! 従来次元変数と呼ばれていたものは、変数が自分自身のみを
        ! 次元としてもつ場合を指す。
        !
        ! open(var, src_var, dimord, [count_compact], [err]) は
        ! 既に開かれた変数 src_var の ord 番目の次元にあたる変数を
        ! 開き var に格納する。順序 ord は現在の入出力範囲が
        ! 幅１になっている (コンパクト化している）を飛ばした
        ! 順序であるが、count_compact に真を指定すると
        ! すべての次元のなかの順序になる。
        !
        subroutine ANVarOpenByDimOrd(var, src_var, dimord, err)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(out):: var
            type(AN_VARIABLE), intent(in):: src_var
            integer, intent(in):: dimord
            logical, intent(out), optional:: err
        end subroutine
    end interface

    interface search_dim
        integer function an_search_dim(var, dimname)
            use an_types, only: an_variable
            type(an_variable), intent(in):: var
            character(len = *), intent(in):: dimname
        end function
    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(out):: 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(out):: 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
        subroutine ANVarDel(varname, hint, stat)
            character(len = *), intent(in):: varname
            character(len = *), intent(in):: hint
            integer, intent(out):: stat
        end subroutine
    end interface

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

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

    ! mainly for PRINT debugging
    interface toString
        function ANVarToString(var) result(result)
            use dc_types, only: STRING
            use an_types, only: AN_VARIABLE
            character(string):: result
            type(AN_VARIABLE), intent(in):: var
        end function
    end interface

    interface inquire

        subroutine ANVarInquire(var, ndims, dimlen, growable, name, url, xtype)
            use an_types, only: an_variable
            type(an_variable), intent(in):: var
            ! 変数の次元数
            integer, intent(out), optional:: ndims
            ! 変数が１次元である場合、次元長
            integer, intent(out), optional:: dimlen
            ! 変数が成長可能次元を持つか
            logical, intent(out), optional:: growable
            ! 文字型引数が短いと値の切り詰めが起こりうる
            ! '?' のあとの変数名
            character(*), intent(out), optional:: name
            ! 変数名、少なくともファイル名を含む、なるべく長い名前
            character(*), intent(out), optional:: url
            ! 変数の型名
            character(*), intent(out), optional:: xtype
        end subroutine

        ! 引数は ndims 個でなければならない
        subroutine ANVarInquireIA(var, dimlen)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            integer, intent(out):: dimlen(:)
        end subroutine

        subroutine ANAttrInquire(var, attrname, xtype)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            character(len=*), intent(in):: attrname
            character(len=*), 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(in):: var
        end subroutine
    end interface

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

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

    interface get_attr

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

        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 AnAttrGetReal(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 AnAttrGetDouble(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 AnAttrGetInt(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, stat)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: to
            character(len = *), intent(in):: attrname
            type(AN_VARIABLE), intent(in):: from
            integer, intent(out):: stat
        end subroutine
    end interface

    !
    ! 入出力
    !

    interface get

        subroutine anvargetreal(var, start, count, stride, imap, &
        & siz, value, iostat)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            integer, intent(in):: start(:)
            integer, intent(in):: count(:)
            integer, intent(in):: stride(:)
            integer, intent(in):: imap(:)
            integer, intent(in):: siz
            real, intent(out):: value(siz)
            integer, intent(out):: iostat
        end subroutine

        subroutine anvargetdouble(var, start, count, stride, imap, &
        & siz, value, iostat)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            integer, intent(in):: start(:)
            integer, intent(in):: count(:)
            integer, intent(in):: stride(:)
            integer, intent(in):: imap(:)
            integer, intent(in):: siz
            double precision, intent(out):: value(siz)
            integer, intent(out):: iostat
        end subroutine

    end interface

    interface put

        subroutine anvarputreal(var, start, count, stride, imap, &
        & siz, value, iostat)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            integer, intent(in):: start(:)
            integer, intent(in):: count(:)
            integer, intent(in):: stride(:)
            integer, intent(in):: imap(:)
            integer, intent(in):: siz
            real, intent(in):: value(siz)
            integer, intent(out):: iostat
        end subroutine

        subroutine anvarputdouble(var, start, count, stride, imap, &
        & siz, value, iostat)
            use an_types, only: AN_VARIABLE
            type(AN_VARIABLE), intent(in):: var
            integer, intent(in):: start(:)
            integer, intent(in):: count(:)
            integer, intent(in):: stride(:)
            integer, intent(in):: imap(:)
            integer, intent(in):: siz
            double precision, intent(in):: value(siz)
            integer, intent(out):: iostat
        end subroutine

    end interface

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

    interface var_search
        
        subroutine ANVarSearchInit(iter, urlBase)
            use an_types, only: AN_VARIABLE_SEARCH
            type(AN_VARIABLE_SEARCH), intent(out):: iter
            character(len = *), intent(in):: urlBase
        end subroutine

        subroutine ANVarSearchNext(iter, url, end)
            use an_types, only: AN_VARIABLE_SEARCH
            type(AN_VARIABLE_SEARCH), intent(inout):: iter
            character(len = *), 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(in), optional:: var
            integer, intent(out), optional:: stat
        end subroutine
    end interface

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

end module
