!  FPAKC main program
PROGRAM fpakc
  USE moduleCompTime
  USE moduleCaseParam
  USE moduleInput
  USE moduleInject
  USE moduleSolver
  USE moduleMesh
  USE moduleProbe
  USE moduleErrors
  USE OMP_LIB
  IMPLICIT NONE

  ! arg1 = Input argument 1 (input file)
  CHARACTER(200):: arg1
  ! inputFile = path+name of input file
  CHARACTER(:), ALLOCATABLE:: inputFile
  ! generic integer for time step
  INTEGER:: t

  tStep = omp_get_wtime()
  !Gets the input file
  CALL getarg(1, arg1)
  inputFile = TRIM(arg1)
  !If no input file is declared, a critical error is called
  IF (inputFile == "") CALL criticalError("No input file provided", "fpakc")

  !Reads the json configuration file
  CALL readConfig(inputFile)

  !Create output folder and initial files
  CALL initOutput(inputFile)

  !Do '0' iteration
  timeStep = tInitial

  !$OMP PARALLEL DEFAULT(SHARED)
  !$OMP SINGLE
  ! Initial reset of probes
  CALL resetProbes()

  CALL verboseError("Initial scatter of particles...")
  !$OMP END SINGLE
  CALL doScatter()

  !$OMP SINGLE
  CALL verboseError("Calculating initial EM field...")
  ! Update EM boundary models
  call boundariesEM_update()

  !$OMP END SINGLE
  CALL doEMField()
  !$OMP END PARALLEL

  tStep = omp_get_wtime() - tStep

  !Output initial state
  CALL doOutput()
  CALL verboseError('Starting main loop...')
  !$OMP PARALLEL DEFAULT(SHARED) 
  DO t = tInitial + 1, tFinal
    !$OMP SINGLE
    tStep = omp_get_wtime()

    ! Update global time step index
    timeStep = t

    ! Update Particle boundary models
    call boundariesParticle_update()

    ! Update EM boundary models
    call boundariesEM_update()

    ! Update injects
    call updateInjects()

    !Checks if a species needs to me moved in this iteration
    CALL solver%updatePushSpecies()

    !Checks if probes need to be calculated this iteration
    CALL resetProbes()
    tPush = omp_get_wtime()
    !$OMP END SINGLE

    !Injects new particles
    CALL doInjects()

    !Push old particles
    CALL doPushes()

    !$OMP SINGLE
    tPush = omp_get_wtime() - tPush

    !Collisions
    tColl = omp_get_wtime()
    !$OMP END SINGLE

    IF (doMCCollisions) THEN
      CALL meshForMCC%doCollisions()

    END IF

    !$OMP SINGLE
    tColl = omp_get_wtime() - tColl
    
    !Coulomb scattering
    tCoul = omp_get_wTime()
    !$OMP END SINGLE

    IF (doCoulombScattering) THEN
      CALL mesh%doCoulomb()

    END IF

    !$OMP SINGLE
    tCoul = omp_get_wTime() - tCoul

    !Reset particles
    tReset = omp_get_wtime()
    !$OMP END SINGLE

    CALL doReset()

    !$OMP SINGLE
    tReset = omp_get_wtime() - tReset

    !Weight
    tWeight = omp_get_wtime()
    !$OMP END SINGLE

    CALL doScatter()

    !$OMP SINGLE
    tWeight = omp_get_wtime() - tWeight

    tEMField = omp_get_wtime()
    !$OMP END SINGLE

    CALL doEMField()

    !$OMP SINGLE
    tEMField = omp_get_wtime() - tEMField

    CALL doAverage()

    tStep = omp_get_wtime() - tStep

    !Output data
    CALL doOutput()
    !$OMP END SINGLE

  END DO
  !$OMP END PARALLEL

END PROGRAM fpakc

