!
#define TRACEBACK write (gol,'("in ",a," (",a,", line",i5,")")') rname, __FILE__, __LINE__; call goErr
#define IF_NOTOK_RETURN(action) if (status/=0) then; TRACEBACK; action; return; end if
#define IF_ERROR_RETURN(action) if (status> 0) then; TRACEBACK; action; return; end if
!
#include "tm5.inc"
!
!#################################################################

module user_output
!BOP
!
! !MODULE:      USER_OUTPUT
!
! !DESCRIPTION:  Contains calls to user-specific output routines, e.g.
!                instantaneous mix files, station output, output of flight 
!                tracks etc.
!\\
!\\
! !INTERFACE: 
!
!MODULE USER_OUTPUT

  use GO, only : gol, goPr, goErr, goBug, goLabel
  use user_output_noaa,only : noaa_data  

  implicit none

  ! --- in/out ------------------------

  private

  public :: user_output_step, user_output_init, user_output_done
  public :: user_output_mean

  ! --- const -------------------------

  character(len=*), parameter  ::  mname = 'user_output'
  
  ! --- var ---------------------------

  logical           ::  settings_data = .false.     ! signal for model settings output

  logical                     :: flask_data = .false.  ! signal for flask output

  logical           :: flight_data = .false.  ! signal for flight output

  logical           :: station_data = .true.  ! signal for station output

  logical           :: mix_data = .false.     ! signal for mix output
  integer           :: mix_data_dhour         ! every dhour hour

  logical           :: mmix_data = .false.     ! signal for mean mix output

  logical           ::  forecast_data = .false.     ! signal for model settings output

#ifdef with_retro_output
  logical           ::  output_retro = .false.
  integer           ::  output_retro_dhour         ! every dhour hour
#endif


#ifdef with_cf_output
  logical           ::  output_cf = .false.
  integer           ::  output_cf_dhour         ! every dhour hour
#endif

contains


  !-------------------------------------------------------------
  ! user_output_init:
  !      Initialise user-specified model output (all regions)
  !-------------------------------------------------------------

  subroutine user_output_init( status )

    use GO,                  only : TrcFile, Init, Done, ReadRc
    use global_data,         only : rcfile
    use User_Output_Settings, only : User_Output_Settings_Init
    use User_Output_Common,   only : User_Output_Common_Init
    use user_output_mmix,    only : mmix_init
    use user_output_station, only : read_stationlist, init_station_output
    use user_output_noaa,    only : init_noaa_events
    use user_output_forecast,    only : user_output_forecast_init
    use user_output_mix,     only : output_mix_init
    use user_output_flask,	only: user_output_flask_init
#ifdef with_retro_output
    use user_output_retro  , only : output_retro_init
#endif
#ifdef with_cf_output
    use user_output_cf     , only : output_cf_init
#endif
 
    ! --- in/out -----------------------------
    
    integer, intent(inout)      ::  status
    
    ! --- const ------------------------------

    character(len=*), parameter ::  rname = mname//'/user_output_init'
    
    ! --- local -------------------------------

    type(TrcFile)           ::  rcF

    ! --- begin -------------------------------

    ! init common stuff:
    call User_Output_Common_Init( status )
    IF_NOTOK_RETURN(status=1)
    
    call Init( rcF, rcfile, status )
    IF_NOTOK_RETURN(status=1)

    ! put out settings ?
    call ReadRc( rcF, 'settings.output', settings_data, status, default=.false. )
    IF_ERROR_RETURN(status=1)
    ! apply ?
    if ( settings_data ) then
      write (gol,'(a,":   user output settings ...")') rname; call goPr
      call User_Output_Settings_Init( rcF, status )
      
      IF_NOTOK_RETURN(status=1)
    end if 

    call ReadRc( rcF, 'output.forecast', forecast_data, status )
    IF_NOTOK_RETURN(status=1)
    if ( forecast_data ) then
        call user_output_forecast_init(status)
        IF_NOTOK_RETURN(status=1)
    endif

    call ReadRc( rcF, 'output.station', station_data, status )
    IF_NOTOK_RETURN(status=1)
    if ( station_data ) then
       call read_stationlist(status)
       IF_NOTOK_RETURN(status=1)
       call init_station_output(status)
       IF_NOTOK_RETURN(status=1)
    end if

    call ReadRc( rcF, 'output.noaa', noaa_data, status, default=.false. )
    IF_NOTOK_RETURN(status=1)
    if ( noaa_data ) then
       call init_noaa_events(status)
       IF_NOTOK_RETURN(status=1)
    end if

    call ReadRc( rcF, 'output.flight', flight_data, status )
    IF_NOTOK_RETURN(status=1)

    call ReadRc( rcF, 'output.mix', mix_data, status )
    IF_NOTOK_RETURN(status=1)
    if ( mix_data ) then
      call ReadRc( rcF, 'output.mix.dhour', mix_data_dhour, status )
      write (gol,*) trim(mname)//'/mix_data_dhour:', mix_data_dhour; call goPr
      IF_NOTOK_RETURN(status=1)
      call output_mix_init(status)
      IF_NOTOK_RETURN(status=1)
    end if

    ! initialise accumulation of the mean mixing ratio fields
    call ReadRc( rcF, 'output.mmix', mmix_data, status )
    IF_NOTOK_RETURN(status=1)
    if ( mmix_data ) then
      call mmix_Init(status)
      IF_NOTOK_RETURN(status=1)
    end if  

    call ReadRc( rcF, 'output.flask', flask_data, status, default=.false.)
    IF_NOTOK_RETURN(status=1)
    if(flask_data) then
       call user_output_flask_init(rcF,status)
       IF_NOTOK_RETURN(status=1)
    endif
    
#ifdef with_retro_output
    ! put out in retro format ?
    call ReadRc( rcF, 'output.retro', output_retro, status, default=.false. )
    IF_NOTOK_RETURN(status=1)
    ! init if necessary:
    if ( output_retro ) then
      ! init output; return ouptut time step
      call Output_RETRO_Init( rcF, output_retro_dhour, status )
      IF_NOTOK_RETURN(status=1)
    end if
#endif

#ifdef with_cf_output
    ! put out in retro format ?
    call ReadRc( rcF, 'output.cf', output_cf, status, default=.false. )
    IF_NOTOK_RETURN(status=1)
    ! init if necessary:
    if ( output_cf ) then
      ! init output; return ouptut time step
      call Output_CF_Init( rcF, output_cf_dhour, status )
      IF_NOTOK_RETURN(status=1)
    end if
#endif



    ! close rcfile:
    call Done( rcF, status  )
    IF_NOTOK_RETURN(status=1)

    ! ok
    status = 0

  end subroutine user_output_init


  !-------------------------------------------------------------
  ! user_output_done:
  !      Finalise user-specified model output for the region given
  !-------------------------------------------------------------

  subroutine user_output_done( status )

    use dims,                only : nregions
    use User_Output_Settings, only : User_Output_Settings_Done
    use User_Output_Common,   only : User_Output_Common_Done
    use user_output_mmix,    only : write_mmix, mmix_Done
    use user_output_station, only : free_stationfields
    use user_output_noaa,     only : write_noaa_events
    use user_output_forecast, only : user_output_forecast_done
    use user_output_mix    , only : output_mix_close
    use user_output_flask,	only : user_output_flask_done
#ifdef with_retro_output
    use user_output_retro  , only : output_retro_done
#endif
#ifdef with_cf_output
    use user_output_cf     , only : output_cf_done
#endif
    
    ! --- in/out -----------------------------
    
    integer, intent(out)      ::  status
    
    ! --- const ------------------------------

    character(len=*), parameter ::  rname = mname//'/user_output_done'
    
    ! --- begin -----------------------------

    ! settings output enabled ?
    if ( settings_data ) then
      ! done with module:
      call User_Output_Settings_Done( status )
      IF_NOTOK_RETURN(status=1)
    end if 
    

    if ( forecast_data ) then
        call user_output_forecast_done(status)
        IF_NOTOK_RETURN(status=1)
    endif

    ! settings output enabled ?
    if ( settings_data ) then
      ! done with module:
      call User_Output_Settings_Done( status )
      IF_NOTOK_RETURN(status=1)
    end if 
    
    ! write the mean mixing ratio fields to file
    if ( mmix_data ) then
      call write_mmix(status)
      IF_NOTOK_RETURN(status=1)
      call mmix_Done(status)
      IF_NOTOK_RETURN(status=1)
    end if
    
    if ( station_data) then 
       call free_stationfields(status)
       IF_NOTOK_RETURN(status=1)
    endif

    if ( noaa_data) then 
       call write_noaa_events(status)
       IF_NOTOK_RETURN(status=1)
    endif

    if(flask_data) then
       call user_output_flask_done(status)
      IF_NOTOK_RETURN(status=1)
    endif

    if ( mix_data ) then 
       call output_mix_close( status )
       IF_NOTOK_RETURN(status=1)
    endif
    
#ifdef with_retro_output
    if ( output_retro ) then
      call Output_Retro_Done( status )
      IF_NOTOK_RETURN(status=1)
    end if
#endif

#ifdef with_cf_output
    if ( output_cf ) then
      call Output_cf_Done( status )
      IF_NOTOK_RETURN(status=1)
    end if
#endif
    ! ok
    status = 0

    ! done with common stuff:
    call User_Output_Common_Done( status )
    IF_NOTOK_RETURN(status=1)

  end subroutine user_output_done



  !-------------------------------------------------------------
  ! user_output_step:
  !      Define user-specified model output for the region given
  !      Called every time step
  !-------------------------------------------------------------

  subroutine user_output_step( region, status )

    use dims,                 only : itaur, newsrun, itaui
    use datetime,             only : tau2date
    use user_output_station,  only : output_stationconc  
    use user_output_noaa,     only : get_noaa  
    use user_output_forecast, only : get_sample
    use user_output_flight,   only : get_flightdata
    use user_output_mix,      only : output_mix, write_mix
    use user_output_mmix,     only : accumulate_mmix
    use user_output_flask,		only : user_output_flask_sample
#ifdef with_retro_output
    use user_output_retro   , only : Output_Retro_Step
#endif
#ifdef with_cf_output
    use user_output_cf      , only : Output_cf_Step
#endif

    ! --- in/out ------------------------------
    
    integer, intent(in)       ::  region
    integer, intent(inout)      ::  status
    
    ! --- const ------------------------------

    character(len=*), parameter ::  rname = mname//'/user_output_step'
    
    ! --- local ------------------------------
    
    integer,dimension(6)            :: idate_f

    ! --- begin ------------------------------
    
    call tau2date(itaur(region),idate_f)

    if (forecast_data) then
        call get_sample(region, status)
        IF_NOTOK_RETURN(status=1)
    endif

    if ( mmix_data ) then
       call accumulate_mmix( region, status ) 
       IF_NOTOK_RETURN(status=1)
    endif

    if ( station_data ) then
       call output_stationconc(region, status)
       IF_NOTOK_RETURN(status=1)
    endif

    ! The third keyword here ("force") is for instantaneous sampling.  Default
    ! value of .false. yields a four-hour window centered on sample time.
    !
    if ( noaa_data ) call get_noaa(region,itaur(region),.false.)

    if ( flight_data )  call get_flightdata(region,idate_f)
    if ( mix_data ) then
      call output_mix(region, status )
      IF_NOTOK_RETURN(status=1)
      if ( modulo(itaur(region)-itaui,mix_data_dhour*3600) == 0 ) then
        call write_mix(region, status )
         IF_NOTOK_RETURN(status=1)
      endif
      !call output_mix(region)
    end if

    if(flask_data) then
       call user_output_flask_sample(region,itaur(region),status)
      IF_NOTOK_RETURN(status=1)
    endif

#ifdef with_retro_output
    if ( output_retro ) then
      if ( (modulo(idate_f(4),output_retro_dhour)==0) .and. all(idate_f(5:6)==0) ) then
        call Output_Retro_Step( region, idate_f, status )
        IF_NOTOK_RETURN(status=1)
      end if
    end if
#endif

#ifdef with_cf_output
    if ( output_cf ) then
      if ( (modulo(idate_f(4),output_cf_dhour)==0) .and. all(idate_f(5:6)==0) ) then
        call Output_CF_Step( region, idate_f, status )
        IF_NOTOK_RETURN(status=1)
      end if
    end if
#endif

    ! ok
    status = 0

  end subroutine user_output_step
  
  
  !
  ! called from tm5 main
  !
  
  subroutine user_output_mean(status)
  use dims, only : itau, ndyn_max
  use user_output_station, only : evaluate_stationconc, reset_stationconc_accumulator, write_stationconc

  implicit none

  integer, intent(inout)    :: status

  character(len=*), parameter ::  rname = mname//'/user_output_mean'
   
    IF(station_data)THEN
      IF(mod(itau, ndyn_max) == 0) THEN
         CALL evaluate_stationconc(status)
         IF_NOTOK_RETURN(status=1)
         CALL write_stationconc(status)
         IF_NOTOK_RETURN(status=1)
         CALL reset_stationconc_accumulator
      ENDIF
    ENDIF
  
   ! ok
   status = 0
  end subroutine user_output_mean
  
  
end module user_output
