! monthly_report_tmp.f90
!   Mar. 2010,  by I. Tamagawa

! make monthly report of TAKAYAMA AWS
!  http://sateco-archive.green.gifu-u.ac.jp/AWS1/

module typedef
 type date_time
   integer :: year
   integer :: month
   integer :: day
   integer :: hour
   integer :: min
   integer :: sec
 end type

 type stat
  real :: max
  real :: min
  real :: ave
  double precision  :: sum
  integer :: num
 end type

 integer, parameter :: maxch = 30
 type awsdata
  integer :: minute
  character(len=80) :: date
  real :: dat( maxch )
 end type


end module

module mod_nodata
implicit none
 integer, parameter :: NODATA = -9999
 logical, external  :: is_nodata
end module



program main
use typedef
use mod_nodata
implicit none

integer :: command_argument_count
integer :: argc
character(len=80) :: argv
integer :: year, month                   ! Target Year and Month
integer :: duration_min, extent_min
type(date_time) :: start

integer :: total_ch, total_num, dt
type(awsdata), allocatable  :: data(:)

character(len=1024) :: file1, file2
integer :: ch1, ch2, shift1, shift2, wsch, wdirch, precch1, precch2
integer :: uch, vch, prec24_1, prec24_2, prec2_1, prec2_2

 extent_min = 0 ! 24*60  ! extent of data duration for moving average etc...
 dt = 10             ! 10 minute interval data

 file1 = '00_All_AWS1_10Min.csv ' ; ch1 = 9; shift1 = 0
 	wsch = 2; wdirch = 3; precch1 = 7; precch2 = 9
	uch = 10; vch = 11; prec24_1 = 12; prec24_2 = 13
	prec2_1 = 14; prec2_2 = 15 ! and more about humidity ...
	
 file2 = '00_All_AWS2_10Min.csv ' ; ch2 = 5; shift2 = 20

 argc = command_argument_count()
 if( argc >= 2 ) then
  call get_command_argument(1, argv)
  read(argv, *) year
  call  get_command_argument(2, argv)
  read(argv, *) month
 else
  write(0,*) 'Please add year and month like  ./a.out 2010 3'
  stop
 end if
 write(0,*) 'year/momth =', year, '/', month
 call setparam( year, month, start, duration_min )

 total_num = ( duration_min + 2*extent_min )/dt

 allocate( data(1:total_num) )

 call initdata( data, total_num )

 call read_copy( file1, ch1, shift1,  &
 	start, duration_min, extent_min, dt, total_num, data )

 call read_copy( file2, ch2, shift2,  &
 	start, duration_min, extent_min, dt, total_num, data )

 call testout( data, total_num, ch1, shift1, ch2, shift2 )


end


subroutine testout( data, total_num, ch1, shift1, ch2, shift2 )
use typedef
implicit none
integer :: total_num, ch1, shift1, ch2, shift2
type(awsdata) :: data(total_num)

integer :: i, j

do i=1, total_num
 write(*,*) i, data(i)%date(1:len_trim(data(i)%date)), &
   data(i)%minute, (data(i)%dat(j), j=shift1+1, shift1+ch1), &
    (data(i)%dat(j), j=shift2+1, shift2+ch2)
! write(*,*) i, data(i)%date(1:len_trim(data(i)%date)), &
!   data(i)%minute, (data(i)%dat(j), j=1, maxch)
   
end do

end


subroutine initdata( data, total_num )
use typedef
use mod_nodata
implicit none
integer :: total_num
type(awsdata) :: data(total_num)

integer :: i, j

do i=1, total_num
  data(i)%dat = NODATA
end do


end



subroutine  read_copy( file1, ch1, shift1,  &
		start, duration_min, extent_min, dt, total_num, data )
use typedef
use mod_nodata
implicit none
character(len=*) :: file1
integer :: ch1, shift1
type(date_time) :: start, now
integer :: duration_min, extent_min, dt
integer :: total_num
type(awsdata)   :: data(total_num)

character(len=1024) :: buf, eachcol(maxch)
integer :: i, j, colnum, calc_diffmin, diffmin

 write(0,*) 'Open ', file1
 open(unit=10, file=file1, status='old', err=999)
! skip 4 lines headder
 do i=1,4
   read(10, '(A)',  end=900, err=900) buf
 end do


 do while( .TRUE.  )
   read(10, '(A)',  end=900, err=900) buf
   call devidecsv( buf(1:len_trim(buf)), eachcol, maxch, colnum )

   read(eachcol(1), "(1x,I4,1x,I2,1x,I2,1x,I2,1x,I2,1x,I2)") &
         now%year, now%month, now%day, now%hour, now%min, now%sec 

   diffmin = calc_diffmin( now, start )

   if(diffmin + extent_min > 0 .AND. diffmin - extent_min <= duration_min) then
   !  COPY
      i = (diffmin+extent_min)/dt

      data(i)%minute = diffmin;
      data(i)%date = eachcol(1)(1:len_trim( eachcol(1) ) )
      do j=1, colnum-1
       read( eachcol(1+j), *) data(i)%dat(j+shift1) 
      end do
      if( colnum < ch1 ) then
       do j=colnum+1, ch1
        data(i)%dat(j) = NODATA
       end do
      end if

    else if( diffmin - extent_min > duration_min ) then
     exit
    end if

 end do

900 close(10)
    write(0,*) file1, 'closed'

return

999 write(0,*) 'Error! Can not open ', file1
stop

end


integer function calc_diffmin( now, start )
!   now - start     in minute
use typedef
implicit none
type(date_time) :: start, now

 integer :: diffday

  call datedif( now%year, now%month, now%day, &
		start%year, start%month, start%day, diffday )

  calc_diffmin = (diffday*24 + (now%hour-start%hour))*60 &
			+(now%min - start%min)   !  + (now%sec - start%sec)/60
 
end






subroutine devidecsv( buf, eachcol, maxch, num )
implicit none
integer   :: maxch, num
character(len=*) :: buf, eachcol(maxch)
integer :: i, j, prev, now, now1, ll
logical :: quoted


ll = len_trim(buf)
quoted = .FALSE.
prev=0; now=1; i=1
do j=1, ll
 if(buf(j:j) == '"') then
    if( quoted ) then
    	quoted = .FALSE.
    else
        quoted = .TRUE.
    end if
 end if

 if(buf(j:j) == ',' .AND. (.NOT.quoted)) then
    now = j
    now1 = now -1
    if( now1 <prev+1 ) then
      eachcol(i) = ''
    else
      eachcol(i) = buf(prev+1:now1)
    end if
    i=i+1
    if( i > maxch ) then
        write(0,*) 'maxch is too small'
        stop
    end if

    prev=now
  end if
end do

if( prev < ll  ) then
 eachcol(i) =  buf(prev+1:ll)
 num = i
else
 num=i-1
end if

end



subroutine setparam( year, month, start, duration )

use typedef

implicit none
integer :: year, month
type(date_time) :: start
integer :: s_year, s_month, s_day, s_hour, s_min, duration
integer :: days
integer, parameter :: min_of_day = 60*24

  start%year = year; start%month = month
  start%day = 1
  start%hour = 0; start%min = 0; start%sec=0

 call days_of_month( year, month, days )
 duration = days * min_of_day

end
 



subroutine days_of_month(year, month, days)
! number of days in year/month
implicit none
integer :: year, month, days
  logical, external :: leepyear

 integer :: m(12)
  m(1) = 31; m(2) = 28; m(3) = 31; m(4) = 30
  m(5) = 31; m(6) = 30; m(7) = 31; m(8) = 31
  m(9) = 30; m(10) = 31; m(11) = 30; m(12) = 31

 if(leepyear(year)) then
  m(2) = 29
 end if

 days = m(month)


end


logical function leepyear( year )
implicit none
 integer :: year

 if( mod(year, 4) > 0 ) then
   leepyear  = .FALSE.
 else if( mod(year, 100) > 0 ) then
   leepyear = .TRUE.
 else if( mod(year, 400) > 0 ) then
   leepyear = .FALSE.
 else
   leepyear = .TRUE.
 end if

return
end


subroutine datedif( year1, month1, day1, year2, month2, day2, diffday )
!     difference between year1/month1/day1 and year2/month2/day2
!        
  implicit none
  integer :: year1, month1, day1
  integer :: year2, month2, day2
  integer :: diffday             ! diffday =  (y/m/d)1 - (y/m/d)2
  integer :: dayofyear
  integer :: fact, tmp, tmp2, d1, d2
  logical :: leepyear
  integer :: year1a, month1a, day1a
  integer :: year2a, month2a, day2a

  year1a = year1; month1a = month1; day1a = day1
  year2a = year2; month2a = month2; day2a = day2


  if( year1 > year2 ) then
    fact = 1
  else if( year1 < year2 ) then
    fact = -1
  else 
    if( month1 > month2 ) then
      fact = 1
    else if( month1 < month2 ) then
      fact = -1
    else
      if( day1 > day2 ) then
        fact = 1
      else if( day1 < day2 ) then
        fact = -1
      else
        fact = 0
      end if
    end if
  end if


  if( fact == 0 ) then
    diffday = 0
    return
  else if( fact == -1 ) then

    tmp = year1; year1 = year2; year2 = tmp
    tmp = month1; month1 = month2; month2 = tmp
    tmp = day1; day1 = day2; day2 = tmp

  end if

 diffday = 0
 do tmp=year2, year1-1
  if( leepyear(tmp) ) then
   diffday = diffday + 366
  else
   diffday = diffday + 365
  end if
 end do
  


! count 
! write(*,*) 'year :::', diffday

   d1 = dayofyear( year1, month1, day1 )
   d2 = dayofyear( year2, month2, day2 )

   diffday = fact*(diffday + d1 - d2)
  year1 = year1a; month1 = month1a; day1 = day1a
  year2 = year2a; month2 = month2a; day2 = day2a

   return
end


   
integer function dayofyear(year, month, day)
 integer :: year, month, day
 logical :: leepyear
 integer :: i
 integer :: m(12)
  m(1) = 31; m(2) = 28; m(3) = 31; m(4) = 30
  m(5) = 31; m(6) = 30; m(7) = 31; m(8) = 31
  m(9) = 30; m(10) = 31; m(11) = 30; m(12) = 31

 if( leepyear( year) ) then
  m(2) = 29
 end if

 dayofyear = 0

 do i=1, month-1
  dayofyear = dayofyear + m(i)
 end do

 dayofyear = dayofyear + day
 return

end




