#' Generate p-Rep Test-Control Designs: Method I
#'
#' Constructs a family of partially replicated (p-rep)
#' test-control designs for early generation varietal
#' trials conducted across multiple environments.
#' The method is based on mutually orthogonal Latin
#' squares (MOLS) and permits the inclusion of one or
#' more control treatments with higher replication than
#' the test treatments.
#'
#' @param s An integer (\eqn{s \ge 3}) specifying the
#' order of the construction.
#' @param control Number of control treatments.
#'
#' @return A list containing design parameters,
#' non-randomized layouts, and randomized layouts.
#'
#' @export
TCpRep1 <- function(s, control){

  # Input Validation
  if(s < 3)
    stop("s must be at least 3")
  if(control < 0 || control != as.integer(control))
    stop("'control' must be a non-negative integer")

  # Construct MOLS
  mols <- vector("list", s - 1)

  for(m in 1:(s - 1)){

    L <- matrix(0, s, s)

    for(i in 0:(s - 1)){
      for(j in 0:(s - 1)){
        L[i + 1, j + 1] <- (i + m * j) %% s
      }
    }

    mols[[m]] <- L
  }

  # Treatment Array
  Tmat <- matrix(1:(s^2), nrow = s, byrow = TRUE)

  # Parallel Classes
  P <- list()

  P[[1]] <- split(
    as.vector(t(Tmat)),
    rep(1:s, each = s)
  )

  P[[2]] <- lapply(
    1:s,
    function(j) Tmat[, j]
  )

  pc <- 3

  for(m in 1:(s - 1)){

    blocks <- vector("list", s)

    for(a in 0:(s - 1)){

      pos <- which(
        mols[[m]] == a,
        arr.ind = TRUE
      )

      blocks[[a + 1]] <- Tmat[pos]
    }

    P[[pc]] <- blocks
    pc <- pc + 1
  }

  # Environment Formation
  environments <- list()

  for(i in 1:s){

    env <- P[[i]]

    env[[s + 1]] <- P[[s + 1]][[i]]

    env.mat <- do.call(
      rbind,
      lapply(env, as.vector)
    )

    rownames(env.mat) <- paste0("B", 1:(s + 1))

    environments[[i]] <- env.mat
  }

  names(environments) <- paste0(
    "Environment_",
    1:s
  )

  # Add Controls
  Design_TC <- lapply(
    environments,
    function(env){

      env <- as.matrix(env)

      if(control > 0){

        control_mat <- matrix(
          rep(
            paste0("C", 1:control),
            each = nrow(env)
          ),
          nrow = nrow(env),
          ncol = control,
          byrow = FALSE
        )

        colnames(control_mat) <- paste0(
          "C",
          1:control
        )

        env <- cbind(
          env,
          control_mat
        )
      }

      env
    }
  )

  # Randomized Layout
  Randomized_TC <- lapply(
    Design_TC,
    function(env){
      rnd <- t(apply(env, 1, sample))
      rownames(rnd) <- rownames(env)
      rnd
    }
  )


  # Parameters
  Parameters <- data.frame(
    Parameter = c(
      "Number of Test Treatments (vt)",
      "Number of Controls (vc)",
      "Number of Environments (e)",
      "Number of Blocks (b)",
      "Test Replication (rt)",
      "Control Replication (rc)",
      "Block Size (k)"
    ),
    Value = c(
      s^2,
      control,
      s,
      s * (s + 1),
      s + 1,
      if(control > 0) s * (s + 1) else 0,
      s + control
    )
  )

  # Non-Randomized Layout
  NonRandomized_Layout <- lapply(
    Design_TC,
    function(env){

      data.frame(
        Block = rownames(env),
        Lines = apply(
          env,
          1,
          function(x) paste(x, collapse = " ")
        ),
        row.names = NULL,
        stringsAsFactors = FALSE
      )

    }
  )

  # Randomized Layout
  Randomized_Layout <- lapply(
    Randomized_TC,
    function(env){

      data.frame(
        Block = rownames(env),
        Lines = apply(
          env,
          1,
          function(x) paste(x, collapse = " ")
        ),
        row.names = NULL,
        stringsAsFactors = FALSE
      )

    }
  )

  # Output
  return(
    structure(
      list(
        Parameters = Parameters,
        NonRandomized_Layout = NonRandomized_Layout,
        Randomized_Layout = Randomized_Layout
      ),
      class = "TCpRep"
    )
  )
}
#' Print p-Rep Test-Control Design
#'
#' Prints the design parameters together with the
#' non-randomized and randomized layouts.
#'
#' @param x An object of class "TCpRep".
#' @param ... Further arguments.
#'
#' @return The input object invisibly.
#'
#' @exportS3Method print TCpRep
print.TCpRep <- function(x, ...){

  cat("\nDesign Parameters\n\n")

  print(
    x$Parameters,
    row.names = FALSE
  )

  cat(
    "\n----------------------------------------\n\n"
  )

  cat(
    "Non-Randomized Layout of the p-Rep Test-Control Design\n\n"
  )

  for(i in names(x$NonRandomized_Layout)){

    cat(
      sub("Environment_", "Environment ", i),
      "\n"
    )

    print(
      x$NonRandomized_Layout[[i]],
      row.names = FALSE
    )

    cat("\n")
  }

  cat(
    "----------------------------------------\n\n"
  )

  cat(
    "Randomized Layout of the p-Rep Test-Control Design\n\n"
  )

  for(i in names(x$Randomized_Layout)){

    cat(
      sub("Environment_", "Environment ", i),
      "\n"
    )

    print(
      x$Randomized_Layout[[i]],
      row.names = FALSE
    )

    cat("\n")
  }

  invisible(x)
}
