program spectrum_sum
  use gkernel_interfaces
  use gildas_def
  use image_def
  use phys_const
  ! Local
  character(len=filename_length) :: mapdata,mapsort,polygon,polyfile,name
  integer :: i, ier, ngon, mgon
  real(8), allocatable :: gons(:,:)
  real(4), allocatable :: s1(:)                    !
  integer(4), allocatable :: s0(:)                 !
  integer(size_length) :: n
  real :: scale
  real(8) :: bound(5)
  logical :: error
  type(gildas) :: x,y
  !
  call gildas_open
  call gildas_char('IN$',mapdata)
  call gildas_char('OUT$',mapsort)
  call gildas_char('POLY$',polygon)
  call gildas_close
  !
  ! Input file
  if (len_trim(mapdata).eq.0) goto 100
  if (mapsort.eq.' ') goto 100
  !
  call gildas_null(x)
  x%gil%ndim = 3
  call gdf_read_gildas(x, mapdata,'.lmv',error)
  name = mapdata
  if (error) then
    write(6,*) 'F-SPECTRUM_SUM,  Cannot read input cube'
    goto 100
  endif
  !
  ! Read Polygon File
  call sic_parsef(polygon,polyfile,' ','.pol')
  open (unit=1,file=polyfile,status='OLD', iostat=ier)
  if (ier.ne.0) then
    call gagout('F-SPECTRUM_SUM,  Cannot read polygon file ')
    call putios('E-SPECTRUM_SUM,  ',ier)
    goto 100
  endif
  i = 0
  do while (.true.)
    read (1,*,end=10)
    i = i+1
  enddo
10 rewind(1)
  ngon = i
  !
  ! Define the polygon
  mgon = ngon+1
  allocate (gons(mgon,4),s0(x%gil%dim(3)),s1(x%gil%dim(3)), stat=ier)
  if (ier.ne.0) goto 100
  call define_poly(x,ngon,gons,bound)
  !
  ! Compute the integrated spectrum
  call spectre(ngon,s1,s0,bound,gons,x%r3d,x%gil%bval,x%gil%eval)
  ! Compute the scale
  scale = abs(x%gil%inc(1)*x%gil%inc(2))   ! Pixel area
  if (x%gil%majo.ne.0) then
    scale = scale/pi/x%gil%majo/x%gil%mino*4.0*log(2.0)
  endif
  !
  ! Output file
  call gildas_null(y,type = 'TABLE')
  call sic_parsef(mapsort,y%file,' ','.tab')
  if (error) goto 100
  !
  y%gil%dim(1) = x%gil%dim(3)
  y%gil%dim(2) = 2
  allocate (y%r2d(y%gil%dim(1),2), stat=ier)
  if (ier.ne.0) goto 100
  !
  ! Compute values
  do n=1,y%gil%dim(1) 
    y%r2d(n,1) = (dble(n)-x%gil%ref(3))*x%gil%inc(3)+x%gil%val(3)
  enddo
  !
  ! Intensity values
  y%r2d(:,2) = s1 * scale
  !
  ! Write data
  call gdf_write_image(y,y%r2d,error)
  if (error) goto 100
  call gagout('S-SPECTRUM_SUM,  Successful completion')
  call sysexi(1)  ! Success
  !
100 call sysexi(fatale)  ! Error
!
contains
!
subroutine spectre(np,s1,s0,bound,gons,map,bb,eb)
  use gkernel_interfaces
  integer(kind=4), intent(in)  :: np          !
  real(kind=4),    intent(out) :: s1(:)       !
  integer(kind=4), intent(out) :: s0(:)       !
  real(kind=8),    intent(in)  :: bound(5)    !
  real(kind=8),    intent(in)  :: gons(:,:)   !
  real(kind=4),    intent(in)  :: map(:,:,:)  !
  real(kind=4),    intent(in)  :: bb          !
  real(kind=4),    intent(in)  :: eb          !
  ! Local
  integer(kind=size_length) :: i,j,imin,imax,jmin,jmax,nk
  real(kind=8) :: x,y
  !
  s0(:) = 0.
  s1(:) = 0.
  nk = 0
  !
  ! Avoid exploring all the Map by finding IMIN,IMAX,JMIN,JMAX
  imin = max (1, int(bound(2)) )
  imax = min (ubound(map,1),int(bound(3))+1 )
  jmin = max (1, int(bound(4)) )
  jmax = min (ubound(map,2),int(bound(5))+1 )
  !
  ! Now explore a reasonable part of the map
  if (eb.lt.0.0) then
    do j=jmin,jmax
      do i=imin,imax
        x = dble(i)
        y = dble(j)
        if (gr8_in(x,y,np,gons,bound)) then
          s0 = s0 + 1
          s1 = s1 + map(i,j,:)
        endif
      enddo
    enddo
  else
    do j=jmin,jmax
      do i=imin,imax
        x = dble(i)
        y = dble(j)
        if (gr8_in(x,y,np,gons,bound)) then
          nk = nk+1
          where (abs(map(i,j,:)-bb).gt.eb)
            s0 = s0 + 1
            s1 = s1 + map(i,j,:)
          end where
        endif
      enddo
    enddo
    !
    ! Renormalize to mean in this case:
    !  - s1(ichan) is the sum of all the non-blanked pixels (in the polygon)
    !              for this channel,
    !  - s0(ichan) is the number of non-blanked pixels (in the polygon) for
    !              this channel; it can be different from one channel to
    !              another.
    !  - nk        is the total number of pixels (in the polygon), identical
    !              for all channels (obviously)
    ! We rescale the sum with factor nk/s0 so that the sum is corrected for
    ! the blanked pixels.
    where (s0.ne.0) s1 = nk*s1/s0
  endif
end subroutine spectre
!
subroutine define_poly(x,np,gons,bound)
  use gildas_def
  use image_def
  type(gildas),    intent(in)  :: x          !
  integer(kind=4), intent(in)  :: np         !
  real(kind=8),    intent(out) :: gons(:,:)  !
  real(kind=8),    intent(out) :: bound(5)   !
  ! Local
  integer(kind=4) :: i,ngon
  real(kind=8) :: xgon1,xgon2,ygon1,ygon2,a
  !
  ! Setup the polygon data structure
  ngon = np
  do i=1,ngon
    read(1,*) gons(i,1),gons(i,2)  ! not yet absolute
    ! Convert User coordinates to Pixels
    gons(i,1) = (gons(i,1) - x%gil%val(1))/x%gil%inc(1) + x%gil%ref(1)
    gons(i,2) = (gons(i,2) - x%gil%val(2))/x%gil%inc(2) + x%gil%ref(2)
    a = nint(gons(i,1))
    if (abs(gons(i,1)-a).lt.1e-3) gons(i,1) = a
    a = nint(gons(i,2))
    if (abs(gons(i,2)-a).lt.1e-3) gons(i,2) = a
  enddo
  !
  gons(ngon+1,1) = gons(1,1)
  gons(ngon+1,2) = gons(1,2)
  xgon1 = gons(1,1)
  xgon2 = gons(1,1)
  ygon1 = gons(1,2)
  ygon2 = gons(1,2)
  do i=1,ngon
    gons(i,3) = gons(i+1,1)-gons(i,1)
    if (gons(i+1,1).lt.xgon1) then
      xgon1 = gons(i+1,1)
    elseif (gons(i+1,1).gt.xgon2) then
      xgon2 = gons(i+1,1)
    endif
    gons(i,4) = gons(i+1,2)-gons(i,2)
    if (gons(i+1,2).lt.ygon1) then
      ygon1 = gons(i+1,2)
    elseif (gons(i+1,2).gt.ygon2) then
      ygon2 = gons(i+1,2)
    endif
  enddo
  bound(1) = xgon1-0.01*(xgon2-xgon1)
  bound(2) = xgon1
  bound(3) = xgon2
  bound(4) = ygon1
  bound(5) = ygon2
end subroutine define_poly
!
end program spectrum_sum
