! netcdf_dimension.f90 - object-oriented netCDF interface (dimension)
! vi: set sw=4:
! Copyright (C) TOYODA Eizi, 2000.  All rights reserved.
!
! 2000-01-11 豊田英司	初版

module netcdf_dimension
    use iso_varying_string
    use netcdf_error
    use netcdf_file
    use netcdf_filename
    use netcdf_v3
    implicit none
    private

    public:: NC_DIMENSION, NC_DIMENSION_ERROR
    type NC_DIMENSION
	type(NC_FILE)::		file
	integer::		id
    end type

    !
    ! --- 次元の取得と利用 ----
    !

    public:: Dimension, Len, Name, Fullname, Id
    public:: operator(==), operator(.error.)

    interface operator(==)
	module procedure NetcdfDimensionEquiv
    end interface

    interface Dimension
	module procedure NetcdfNewDimension
	module procedure NetcdfFindDimension
    end interface

    interface Len
	module procedure NetcdfDimensionLength
	module procedure dim_array_len
    end interface

    interface Name;  module procedure NetcdfDimensionName;  end interface

    interface Fullname
	module procedure NetcdfDimensionFullname
    end interface

    interface operator(.error.)
	module procedure NetcdfDimensionError
    end interface

    interface Id
	module procedure NetcdfDimensionId
    end interface

contains

    type(NC_DIMENSION) function NC_DIMENSION_ERROR() result(result)
	result%file = NC_FILE_ERROR
	result%id = -1
    end function

    !
    ! --- ファイルに次元を作成 ---
    !

    function NetcdfNewDimension(file, name, len) result(result)
	type(NC_DIMENSION)::			result
	type(NC_FILE), intent(inout)::		file
	character(len=*), intent(in)::		name
	integer, intent(in)::			len
	integer::				status, dimid
    continue
	result = NC_DIMENSION_ERROR()
	call DefineMode(file)
	status = nf_def_dim(Id(file), name, len, dimid)
	if (status == NF_NOERR) then
	    result = NC_DIMENSION(file, dimid)
	else
	    call NetcdfSaveError(status, 'NetcdfNewDimension', &
		& Filename(file))
	endif
    end function

    !
    ! --- ファイルから次元関係情報の取得 ---
    !

    function NetcdfFindDimension(file, name) result(result)
	type(NC_DIMENSION)::			result
	type(NC_FILE), intent(in)::		file
	character(len=*), intent(in)::		name
	integer::				status
    continue
	status = nf_inq_dimid(Id(file), name, result%id)
	if (status /= NF_NOERR) then
	    call NetcdfSaveError(status, &
		& 'NetcdfFindDimension', Filename(file))
	    result = NC_DIMENSION_ERROR()
	    return
	endif
	result%file = file
    end function

    !
    ! --- 次元の情報取得 ---
    !

    logical function NetcdfDimensionError(dim) result(result)
    	type(NC_DIMENSION), intent(in)::	dim
    continue
    	result = (dim%id <= 0)
    end function

    integer function NetcdfDimensionId(dim) result(result)
    	type(NC_DIMENSION), intent(in)::	dim
    continue
    	result = dim%id
    end function

    !
    ! --- 次元の利用 ---
    !

    ! 次元の長さを知る
    integer function NetcdfDimensionLength(dim) result(result)
	type(NC_DIMENSION), intent(in)::	dim
	integer::				status
    continue
	status = nf_inq_dimlen(Id(dim%file), dim%id, result)
	if (status /= NF_NOERR) then
	    call NetcdfSaveError(status, 'NetcdfDimensionLength', &
		& dim%id)
	    result = 0
	endif
    end function

    ! Fortran 95 ならば elemental にすればよいのだが....
    function dim_array_len(dim) result(result)
	type(NC_DIMENSION), intent(in):: dim(:)
	integer, dimension(size(dim)):: result
	integer:: i
    continue
	result(:) = (/(len(dim(i)), i = 1, size(dim))/)
    end function

    function NetcdfDimensionName(dim) result(result)
	type(VARYING_STRING)::			result
	character(len=NF_MAX_NAME)::		buffer
	type(NC_DIMENSION), intent(in)::	dim
	integer:: 				status
    continue
	status = nf_inq_dimname(Id(dim%file), dim%id, buffer)
	if (status /= NF_NOERR) then
	    call NetcdfSaveError(status, 'NetcdfDimensionName', &
		& dim%id)
	    result = ''
	endif
	result = trim(buffer)
    end function

    function NetcdfDimensionFullname(dim) result(result)
	type(VARYING_STRING)::			result
	type(NC_DIMENSION), intent(in)::	dim
    continue
	result = Name(dim%file) // '#' // Name(dim)
    end function

    logical function NetcdfDimensionEquiv(dima, dimb) result(result)
	type(NC_DIMENSION), intent(in)::	dima, dimb
    continue
	result = ((dima%file == dimb%file) .and. (dima%id == dimb%id))
    end function

end module
