context("s2dv::ProjectField tests")

##############################################
  # dat1
  set.seed(1)
  dat1 <- array(rnorm(120), dim = c(sdate = 10, lat = 6, lon = 2))
  lat1 <- seq(10, 30, length.out = 6)
  lon1 <- c(10, 12)
  eof1 <- EOF(dat1, lat1, lon1, neofs = 10)
  reof1 <- REOF(dat1, lat1, lon1, ntrunc = 3)

  # dat2
  set.seed(1)
  dat2 <- array(rnorm(48), dim = c(dat = 1, memb = 1, sdate = 6, ftime = 1, lat = 4, lon = 2))
  lat2 <- seq(10, 30, length.out = 4)
  lon2 <- c(-5, 5)
  eof2 <- EOF(dat2, lat2, lon2, neofs = 6)
 
  # dat3
  dat3 <- dat2
  dat3[1, 1, 1, 1, , ] <- NA
  names(dim(dat3)) <- names(dim(dat2))
  lat3 <- lat2
  lon3 <- lon2
  eof3 <- eof2

  # dat4
  set.seed(1)
  dat4 <- array(rnorm(288*2), dim = c(dat = 2, memb = 2, sdate = 6, ftime = 3, lat = 4, lon = 2))
  lat4 <- seq(-10, -30, length.out = 4)
  lon4 <- c(350, 355)
  set.seed(2)
  tmp <- array(rnorm(144), dim = c(dat = 2, sdate = 6, lat = 4, lon = 2))
  eof4 <- EOF(tmp, lat4, lon4, neofs = 6)
  reof4 <- REOF(tmp, lat4, lon4, ntrunc = 6)

  # dat5
  set.seed(1)
  dat5 <- array(rnorm(144*3), dim = c(dat = 1, memb = 2, sdate = 6, ftime = 3, lat = 4, lon = 3))
  lat5 <- seq(-10, 10, length.out = 4)
  lon5 <- c(0, 5, 10)
  set.seed(2)
  tmp <- array(rnorm(72), dim = c(sdate = 6, lat = 4, lon = 3))
  eof5 <- EOF(tmp, lat5, lon5, neofs = 6)

##############################################
test_that("1. Input checks", {

  # ano
  expect_error(
  ProjectField(c()),
  "Parameter 'ano' cannot be NULL."
  )
  expect_error(
    ProjectField(c(NA, NA)),
    "Parameter 'ano' must be a numeric array."
  )
  expect_error(
    ProjectField(list(a = array(rnorm(50), dim = c(dat = 5, sdate = 10)), b = c(1:4))),
    "Parameter 'ano' must be a numeric array."
  )
  expect_error(
    ProjectField(array(1:10, dim = c(2, 5))),
    "Parameter 'ano' must have dimension names."
  )
  # eof
  expect_error(
  ProjectField(dat1, c()),
  "Parameter 'eof' cannot be NULL."
  )
  expect_error(
  ProjectField(dat1, c(1, 2)),
  "Parameter 'eof' must be a list generated by EOF() or REOF().",
  fixed = TRUE
  )
  expect_error(
  ProjectField(dat1, list(a = 1)),
  paste0("Parameter 'eof' must be a list that contains 'EOFs' or 'REOFs'. ",
         "It can be generated by EOF() or REOF()."),
  fixed = TRUE
  )
  eof_fake <- list(EOFs = 'a', wght = 1:10)
  expect_error(
  ProjectField(dat1, eof_fake),
  "The component 'EOFs' or 'REOFs' of parameter 'eof' must be a numeric array."
  )
  eof_fake <- list(EOFs = array(rnorm(10), dim = c(mode = 1, lat = 2, lon = 5)), 
                   wght = c(1:10))
  expect_error(
  ProjectField(dat1, eof_fake),
  "The component 'wght' of parameter 'eof' must be a numeric array."
  )
  # time_dim
  expect_error(
    ProjectField(dat1, eof1, time_dim = 2),
    "Parameter 'time_dim' must be a character string."
  )
  expect_error(
    ProjectField(dat1, eof1, time_dim = c('a','sdate')),
    "Parameter 'time_dim' must be a character string."
  )
  # space_dim
  expect_error(
    ProjectField(dat1, eof1, space_dim = 'lat'),
    "Parameter 'space_dim' must be a character vector of 2."
  )
  expect_error(
    ProjectField(dat1, eof1, space_dim = c('latitude', 'longitude')),
    "Parameter 'space_dim' is not found in 'ano' dimension."
  )
  # eof (2)
  eof_fake <- list(EOFs = array(rnorm(10), dim = c(lat = 2, lon = 5)), 
                   wght = array(rnorm(10), dim = c(lat = 2, lon = 5)))
  expect_error(
  ProjectField(dat1, eof_fake),
  paste0("The component 'EOFs' or 'REOFs' of parameter 'eof' must be an array ",
         "with dimensions named as parameter 'space_dim' and 'mode'.")
  )
  eof_fake <- list(EOFs = array(rnorm(10), dim = c(mode = 1, lat = 6, lon = 2)),
                   wght = array(rnorm(10), dim = c(level = 6, lon = 2)))
  expect_error(
  ProjectField(dat1, eof_fake),
  paste0("The component 'wght' of parameter 'eof' must be an array ",
         "with dimensions named as parameter 'space_dim'.")
  )
  # mode
  expect_error(
    ProjectField(dat1, eof1, mode = -1),
    "Parameter 'mode' must be NULL or a positive integer."
  )
  expect_error(
    ProjectField(dat1, eof1, mode = 15),
    paste0("Parameter 'mode' is greater than the number of available ",
                "modes in 'eof'.")
  )
  # ncores
  expect_error(
    ProjectField(dat1, eof1, ncore = 3.5),
    "Parameter 'ncores' must be a positive integer."
  )

})
##############################################
test_that("2. dat1", {

  expect_equal(
  dim(ProjectField(dat1, eof = eof1, mode = 1)),
  c(sdate = 10)
  )
  expect_equal(
  dim(ProjectField(dat1, eof = eof1)),
  c(mode = 10, sdate = 10)
  )
  expect_equal(
  as.vector(ProjectField(dat1, eof1, mode = 1))[1:5],
  c(3.2061306, -0.1692669, 0.5420990, -2.5324441, -0.6143680),
  tolerance = 0.0001
  )
  expect_equal(
  as.vector(ProjectField(dat1, eof1, mode = 10))[1:5],
  c(-0.24848299, -0.19311118, -0.16951195, -0.10000207, 0.04554693),
  tolerance = 0.0001
  )
  expect_equal(
  as.vector(ProjectField(dat1, eof1, mode = 1)),
  as.vector(ProjectField(dat1, eof1)[1, ])
  )
  # reof
  expect_equal(
  dim(ProjectField(dat1, eof = reof1, mode = 1)),
  c(sdate = 10)
  )
  expect_equal(
  dim(ProjectField(dat1, eof = reof1)),
  c(mode = 3, sdate = 10)
  )
  expect_equal(
  as.vector(ProjectField(dat1, reof1, mode = 1))[1:5],
  c(3.1567219, -0.1023512, 0.6339372, -0.7998676, -1.3727226),
  tolerance = 0.0001
  )

})
##############################################
test_that("3. dat2", {
  expect_equal(
  dim(ProjectField(dat2, eof2, mode = 1)),
  c(sdate = 6, dat = 1, memb = 1, ftime = 1)
  )
  expect_equal(
  dim(ProjectField(dat2, eof2)),
  c(mode = 6, sdate = 6, dat = 1, memb = 1, ftime = 1)
  )
  expect_equal(
  ProjectField(dat2, eof2, mode = 1)[1:6],
  c(0.00118771, -1.20872474, -0.00821559, -2.06064916, -0.19245169, 2.26026937),
  tolerance = 0.0001
  )
  expect_equal(
  mean(ProjectField(dat2, eof2, mode = 6)),
  0.1741076,
  tolerance = 0.0001
  )
  expect_equal(
  as.vector(ProjectField(dat2, eof2, mode = 1)),
  as.vector(ProjectField(dat2, eof2)[1, , , , ])
  )
  expect_equal(
  as.vector(ProjectField(dat2, eof2, mode = 5)),
  as.vector(ProjectField(dat2, eof2)[5, , , , ])
  )

})

##############################################
test_that("4. dat3", {
  expect_equal(
  dim(ProjectField(dat3, eof3, mode = 1)),
  c(sdate = 6, dat = 1, memb = 1, ftime = 1)
  )
  expect_equal(
  ProjectField(dat3, eof3, mode = 1)[1:6],
  c(NA, -1.20872474, -0.00821559, -2.06064916, -0.19245169, 2.26026937),
  tolerance = 0.0001
  )

})
##############################################
test_that("5. dat4", {
  expect_equal(
  dim(ProjectField(dat4, eof4, mode = 1)),
  c(sdate = 6, dat = 2, memb = 2, ftime = 3)
  )
  expect_equal(
  mean(ProjectField(dat4, eof4, mode = 1)),
  0.078082,
  tolerance = 0.0001
  )
  expect_equal(
  ProjectField(dat4, eof4, mode = 1)[, 1, 2, 2],
  c(0.28137048, -0.17616154, -0.39155370, 0.08288953, 1.18465521, 0.81850535),
  tolerance = 0.0001
  )
  # reof
  expect_equal(
  dim(ProjectField(dat4, reof4)),
  c(mode = 6, sdate = 6, dat = 2, memb = 2, ftime = 3)
  )
  expect_equal(
  ProjectField(dat4, reof4, mode = 1)[, 1, 2, 2],
  c(-1.6923627, -0.4080116, 0.3044336, -0.7853220, -0.2670783, 0.6940482),
  tolerance = 0.0001
  )

})
##############################################
test_that("6. dat5", {
  expect_equal(
  dim(ProjectField(dat5, eof5, mode = 1)),
  c(sdate = 6, dat = 1, memb = 2, ftime = 3)
  )
  expect_equal(
  mean(ProjectField(dat5, eof5, mode = 1)),
  0.0907149,
  tolerance = 0.0001
  )
  expect_equal(
  ProjectField(dat5, eof5, mode = 1)[, 1, 2, 2],
  c(0.60881970, 0.93588392, 0.01982465, 0.82376024, -0.33147699, -1.35488289),
  tolerance = 0.0001
  )

})
