parametersCheck <- function(pars, inppars, logger){
  inpnames <- c("BreedingCows", "ECRefLW", "LW_Prim", "annualMilkProdL", 
                "CvSsnalDist", "HfCalvIntv", "CowsCalvIntv", "PreCalvingDryMths",
                "wAge", "BullsPerCow", "CowsReplRate", "Birth", "Calving1", 
                "MilkFatProp", "MilkProtProp", "climateRegion")
  
  diffPars <- setdiff(inpnames, names(inppars)) 
  
  if(length(diffPars) && !(diffPars %in% names(pars))){
      log4r::fatal(logger, paste0(paste0(diffPars, collapse = "' ,'"), "' are not parameters. Check for possible typo."))
      stop()
  }else if(length(diffPars) && diffPars %in% names(pars)){
      log4r::warn(logger, paste0("Parameters '", paste0(diffPars, collapse = "' ,'"), "' are not in Input file. Default values will be considered."))
  }
  
  floatPars <- c("BreedingCows", "ECRefLW", "LW_Prim", "MilkProdL", "PreCalvingDryMths", 
                 "BullsPerCow", "CowsReplRate", "Birth", "Calving1", "MilkFatProp",
                 "MilkProtProp", "Cows_breed_group", "AgeFirstBirth", "WeightBulls",
                 "CowCarcassYield") # the 4 latter ones are not used in the code

  integerPars <- c("HfCalvIntv", "CowsCalvIntv", "wAge")

  stringPars <- c("climateRegion")

  NAvalues <- c()
  
  for(v in floatPars){
    if(v %in% names(inppars)){
      auxvar <- turnIntoVector(inpvar = inppars[[v]])
      
      if(!is.na(auxvar)){
        pars[[v]] <- auxvar
      }else if(is.na(inppars[[v]])){
        NAvalues <- c(NAvalues, v)
      }
    }
  }
  
  if(any(!is.na(NAvalues))){
    log4r::warn(logger, paste0("Parameters '", paste0(NAvalues, collapse = "', '"),"' defined as NA in input file, intern default value (float) is considered."))
  }
  
  if(pars$MilkFatProp < 2.5 | pars$MilkFatProp > 7){
    pars$MilkFatProp <- max(2.5, min(7, pars$MilkFatProp))
    log4r::warn(logger, paste0("Parameter MilkFatProp out of bound: value set to ", pars$MilkFatProp))
  }
  
  if(pars$MilkProtProp < 2.5 | pars$MilkProtProp > 5){
    pars$MilkProtProp <- max(2.5, min(5, pars$MilkProtProp))
    log4r::warn(logger, paste0("Parameter MilkProtProp out of bound: value set to ", pars$MilkProtProp))
  }
  
  NAvalues <- c()
  INTvalues <- c()
  
  for(v in integerPars){
    if(v %in% names(inppars)){
      auxvar <- turnIntoVector(inpvar = inppars[[v]])
      
      if(!is.na(auxvar)){
        if(!is.numeric(auxvar)){
          log4r::warn(logger, paste0("Parameter ", v, " should be an integer. Intern default value is considered."))
        }else{
          if(!is.integer(auxvar)){
            INTvalues <- c(INTvalues, v)
          }
          pars[[v]] <- as.integer(auxvar)
        }
      }else{
        NAvalues <- c(NAvalues, v)
      }
    }
  }
  
  if(any(!is.na(NAvalues))){
    log4r::warn(logger, paste0("Parameters '", paste0(NAvalues, collapse = "', '"),"' defined as NA in input file, intern default value (integer) is considered."))
  }
  
  if(any(!is.na(INTvalues))){
    log4r::warn(logger, paste0("Parameters '", paste0(INTvalues, collapse = "', '"),"' should be integers, so it's value has been rounded."))
  }
  
  NAvalues <- c()
  stringDefault <- c("sp", "mg", "go")
  
  for(v in stringPars){
    if(v %in% names(inppars)){
      if(is.character(inppars[[v]])){
        if(tolower(inppars[[v]]) %in% stringDefault){
          pars[[v]] <- tolower(inppars[[v]])
        }else{
          log4r::warn(logger, paste0("In parameter '", v,"': name '", inppars[[v]], "' not supported, intern default value is considered."))
        }
      }else if(is.na(inppars[[v]])){
        NAvalues <- c(NAvalues, v)
      }
    }
  }
  
  if(any(!is.na(NAvalues))){
    log4r::warn(logger, paste0("Parameters '", paste0(NAvalues, collapse = "', '"),"' defined as NA in input file, intern default value (string) is considered."))
  }
  
  if("CvSsnalDist" %in% names(inppars)){
    if(!is.character(inppars[["CvSsnalDist"]])){
      log4r::warn(logger, "CvSsnalDist must be 12 values separated by comma. Intern default value is considered.")
    }else{
      auxvar <- gsub(";", ",", inppars[["CvSsnalDist"]])
      auxvar <- turnIntoVector(inpvar = auxvar)
      
      if(length(auxvar) != 12){
        log4r::warn(logger, "CvSsnalDist must be 12 values separated by comma. Intern default value is considered.")
      }else{
        pars[["CvSsnalDist"]] <- auxvar
      }
    }
  }
 
  return(pars)
}

inpCalculates <- function(inpList, annualMilk){
  
  # fraction of total annual nitrogen excretion for each manure management system in each climate region (%)
  inpList$MS     <- matrix(ncol = 3, nrow = 3, dimnames = list(c("anaerobic lagoon", "biodigester", "solid storage"), c("sp", "mg", "go")))
  inpList$MS[1,] <- c(11.69, 13.49, 6.81)
  inpList$MS[2,] <- c(0.08, 0.13, 0.12)
  inpList$MS[3,] <- c(11.69, 13.49, 6.81)
  
  # methane correction factor for each manure management system in each climate region (%)
  inpList$MCF     <- matrix(ncol = 3, nrow = 3, dimnames = list(c("anaerobic lagoon", "biodigester", "solid storage"), c("sp", "mg", "go")))
  inpList$MCF[1,] <- c(78, 78, 79)
  inpList$MCF[2,] <- c(10, 10, 10)
  inpList$MCF[3,] <- c(4, 4, 4)
  
  # Fator de perda de N por volatilização (fração)
  inpList$Frac <- c("anaerobic lagoon" = 0.35, "biodigester" = 0, "solid storage" = 0.3)
  inpList$Ncdg <- c("anaerobic lagoon" = 0, "biodigester" = 0, "solid storage" = 0)
  
  inpList$EFCH4  <- c("anaerobic lagoon" = 128.6, "biodigester" = 3.7, "solid storage" = 8)   # Fator de emissão de CH4 (g CH4 / kg VS)
  inpList$EFN2Od <- c("anaerobic lagoon" = 0, "biodigester" = 0.0006, "solid storage" = 0.01) # Fator de emissão direta de N (kg N2O-N / kg Nex)
  
  # Turning percentage (0 to 100) to proportion (0 to 1)
  inpList$CowsReplRate  <- inpList$CowsReplRate/100
  inpList$MilkFatProp   <- inpList$MilkFatProp/100
  inpList$MilkProtProp  <- inpList$MilkProtProp/100
  inpList$CvSsnalDist   <- inpList$CvSsnalDist/sum(inpList$CvSsnalDist)
  inpList$LW_Prim       <- inpList$LW_Prim/100
  inpList$PropUreaSuppl <- inpList$PropUreaSuppl/100
  inpList$PropUreaPast  <- inpList$PropUreaPast/100
  
  inpList$mthnames   <- c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
  inpList$DinMth     <- c(31, 28.25, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
  inpList$Calving1   <- ifelse(is.na(inpList$Calving1), inpList$ECRefLW * inpList$LW_Prim, inpList$Calving1) # First calving weight (kg)    
  inpList$DIYr       <- sum(inpList$DinMth)                        # days in a year
  inpList$meanDiM    <- mean(inpList$DinMth)                       # avg number of days in a month
  
  inpList$milkProd        <- inpList$MilkProdL * inpList$milkDensity    # L to kg
  inpList$annualMilkProdL <- ifelse(is.na(annualMilk), inpList$annualMilkProdL, annualMilk)
  inpList$FPCM            <- inpList$annualMilkProdL * ((inpList$fatCorrFactor * inpList$MilkFatProp)
                                                        + (inpList$protCorrFactor * inpList$MilkProtProp) + 0.2534)

  return(inpList)
}

parametersDefault <- function(){
  
  # Fixed input lists ####
  pars <- list(
    BreedingCows      = 100,            # Number of breeding cows - exclude pregnant heifers (float)
    ECRefLW           = 500,            # Empty cows reference liveweight  (kg:float)
    LW_Prim           = 90,             # Relative liveweight of primiparous cows (%)
    annualMilkProdL   = 12000,          # Annual milk production in lactation (L:float)
    CvSsnalDist       = rep(100/12,12), # Vector of length = 12 and sum = 100 with seasonal calving distribution (dimensionless:numeric vector) (%)
    HfCalvIntv        = 13,             # Heifers calving interval (months, integer)
    CowsCalvIntv      = 13,             # Cows calving interval (months, integer)
    PreCalvingDryMths = 2,              
    wAge              = 2,              # Weaning age (months, integer)
    BullsPerCow       = 0.25,           # Number of cows per bull (float)
    CowsReplRate      = 25,             # Cows replacement rate (%)
    Birth       = 32,     # Calves birth weight (kg)
    Calving1    = NULL,   # First calving weight (kg)
    Ym          = 0.065,  # Proportion of gross energy intake as methane energy emission
    EfFeces     = 0.002,  # N2O emission factor for feces (g N2O/g N in feces)
    EfFertPast  = 0.0125, # N2O emission factor fertilizers in pastures (g N2O/g N in fertilizers)
    EfFertOther = 0.0125, # N2O emission factor fertilizers in other areas (g N2O/g N in fertilizers)
    EfManure    = 0.02,   # N2O emission factor for manure - mixed urine and feces (g N2O/g N in manure)
    EfUrine     = 0.02,   # N2O emission factor for urine (g N2O/g N in urine)
    EfCO2Liming = 0.12,   # CO2 emission factor for limestone (g CO2/g limestone)
    EfCO2Urea   = 0.22,   # CO2 emission factor for urea (g CO2/g urea)
    GWPN2O      = 273,    # IPCC 2021
    GWPCH4      = 27,     # IPCC 2021
    ActivityFactor = 0.17,   # Proportion of maintenance increased due to extra physical activity
    BreedMaint     = 1,      # Breed maintenance multiplier factor 
    CMaintBeef     = 0.322,  # Beef maintenance req. per unit of metabolic weight (MJ/LW^0.75)
    CMaintDairy    = 0.386,  # Dairy maintenance req. per unit of metabolic weight (MJ/LW^0.75)
    CPDig          = 0.65,   # Crude protein digestibility (dimensionless)  
    FFM_Req        = 1.47,   # Net energy req. for the production of fat-free milk (MJ/kg)  
    MFat_Req       = 40,     # Net energy req. for the production of milk fat (MJ/kg)
    MilkFatProp    = 3.5,    # milk fat proportion (%)
    MilkProtProp   = 3.5,    # protein fat proportion (%)
    N2O_N     = 3.2857,      # N2O mass corresponding to one unit of mass of N
    CO2_C     = 44/12,       # CO2 mass corresponding to one unit of mass of C
    CH4Energy = 55.65,       # CH4 energy concentration (kJ/g)
    pregLen   = 9,           # pregnancy duration (mth)
    GEFeed    = 18.45,       # gross energy concentration of feed 
    NinCP     = 0.16,        # nitrogen concentration in crude protein (dimensionless)
    maxSize   = 100,         # maximum size of the age vector. # maxSize must be greater than the age (mth) at the 2nd calving
    milkDensity    = 1.032,  # milk density (kg/L)
    fatCorrFactor  = 0.1226, # correction factor for fat
    protCorrFactor = 0.0776, # correction factor for protein
    wastingManageType = "anaerobic lagoon",
    climateRegion     = "sp",
    VSrate = 7.9,   # Volatile solid excretion rate (kg VS / 1000 kg animal mass / day) (IPCC 2006)
    Nrate  = 0.39,  # Nitrogen excretion rate (kg N / 1000 kg animal mass / day) (IPCC 2006)
    EFN2Oi = 0.01,  # Fator de emissão indireta de N (kg N2O-N / (kg NH3-N + NOx-N volatilised)) (IPCC 2006)
    delta.t = 20,
    areaCategory = c("pastagem degradada"                                           = "pastArea",
                     "pastagem de média produtividade"                              = "pastArea", 
                     "pastagem de alta produtividade"                               = "pastArea",
                     "milho para silagem (1 safra e pousio) - plantio convencional" = "supplArea",
                     "milho para silagem (1 safra e pousio) - plantio direto"       = "supplArea",
                     "milho para silagem (2 safras) - convencional"                 = "supplArea",
                     "milho para silagem (2 safras) - direto"                       = "supplArea",
                     "integração lavoura-pecuária (sistema santa-fé)"               = "supplArea"),
    B0 = 0.13 # Maximum CH4 productivity capacity (kg CH4/VS)
  )
  
  return(pars)
}

parametersSetting <- function(filepath, logger, annualMilk){
  
  Parameters <- parametersDefault()

  # Read user's parameter file and assign variables to existing lists
  df <- readDF(filepath = filepath, sht = "Parameters", logger = logger)
  
  if(length(df) == 0){
    log4r::fatal(logger, "Input file has empty Parameters sheet.")
    stop()
  }
  
  allCol <- c("Parameter", "Description", "Unit", "Value")
  if(!all(colnames(df) %in% allCol)){
    log4r::fatal(logger, paste0("Parameters' sheet columns must be: '", paste0(allCol, collapse = "', '"), "', respectively."))
    stop()
  }
  
  inputParameters <- setNames(as.list(df[,"Value"]), df[,"Parameter"])
  
  Parameters <- parametersCheck(pars = Parameters, inppars = inputParameters, logger = logger)
  
  # Calculated parameters #
  Parameters <- inpCalculates(inpList = Parameters, annualMilk = annualMilk)
  
  return(Parameters)
}


