! 
! Copyright 2008-2009 Shin'ya Murakami <murashin@epa.scitec.kobe-u.ac.jp>
! $Id:$
!
! 2次元格子点における矩形領域の範囲を, 格子点のインデックスで
! 保持する型 AreaRange に関するモジュール.
! 
! 
module mod_arearange
  
  use mod_boundaryinfo
  
  implicit none

  private
  ! type
  public :: AreaRange 
  ! subroutine, function
  public :: ar_set, ar_merge, ar_check_adjacency_direction, ar_is_at_boundary
  
  type AreaRange
     integer ix0 ! 領域の左端   (ix0,iy1) ------  (ix1,iy1)
     integer ix1 ! 領域の右端            |      |
     integer iy0 ! 領域の下端            | area |
     integer iy1 ! 領域の上端   (ix0,iy0) ------  (ix1,iy0)
  end type AreaRange

contains
  
  !
  ! 領域の範囲設定
  !
  subroutine ar_set(r, ix0, ix1, iy0, iy1)
    
    type(AreaRange), intent(inout) :: r
    integer,         intent(in)    :: ix0, ix1, iy0, iy1
    
    r%ix0 = ix0 
    r%ix1 = ix1
    r%iy0 = iy0
    r%iy1 = iy1   
  end subroutine ar_set
  
  ! 
  ! 領域の併合
  ! r1, r2の順に並んだ領域を併合する.
  ! dir == .true.のとき上下に隣接,
  !     == .false.のとき左右に隣接
  ! 
  function ar_merge(r1, r2, dir) result(retval)
    
    type(AreaRange), intent(in) :: r1, r2
    logical,         intent(in) :: dir
    
    type(AreaRange) retval
    
    if(dir)then !上下隣接
       retval%ix0 = r1%ix0
       retval%ix1 = r1%ix1
       retval%iy0 = r1%iy0
       retval%iy1 = r2%iy1
    else
       retval%ix0 = r1%ix0
       retval%ix1 = r2%ix1
       retval%iy0 = r1%iy0
       retval%iy1 = r1%iy1  
    end if
  end function ar_merge
  
  !
  ! ar1, ar2の隣接境界位置を調べる.
  ! dir == .true.のとき上下に隣接, 
  !     == .false.のとき左右に隣接
  ! need_swap == .true.のときpa1, pa2の順
  !           == .false.のときpa2, pa1の順
  subroutine ar_check_adjacency_direction(dir, need_swap, ar1, ar2)
    
    type(AreaRange), intent(in)  :: ar1, ar2
    logical,         intent(out) :: dir, need_swap
    
    if(ar1%ix0 == ar2%ix0)then ! 上下の隣接
       dir = .true. 
       if(ar1%iy0 < ar2%iy0)then ! ar1,ar2の順
          need_swap = .false.
       else ! ar2,ar1の順
          need_swap = .true.
       end if
    else ! 左右の隣接
       dir = .false.
       if(ar1%ix0 < ar2%ix0)then ! ar1,ar2の順
          need_swap = .false.
       else ! ar2,ar1の順
          need_swap = .true.
       end if
    end if
    
  end subroutine ar_check_adjacency_direction
  
  !
  ! エリア範囲と点から境界に位置するかを判定し, 
  ! 境界に位置する場合は境界情報をbに入れて返す.
  !
  logical function ar_is_at_boundary(ar, ix, iy, b) result(retval)
    
    type(AreaRange),    intent(in)  :: ar
    type(BoundaryInfo), intent(out) :: b
    integer,            intent(in)  :: ix, iy
    
    call bi_init(b)
    if(ar%ix0 == ix)then
       b%is_at_left = .true.
    else if(ar%ix1 == ix)then
       b%is_at_right = .true.
    end if
    if(ar%iy0 == iy)then
       b%is_at_bottom = .true.
    else if(ar%iy1 == iy)then
       b%is_at_top = .true.
    end if
    retval = bi_is_at_boundary(b)
    
  end function ar_is_at_boundary
  
end module mod_arearange
