#' Generate p-Rep Test-Control Designs: Method I
#'
#' Constructs a partially replicated (p-rep) test-control design
#' with one fixed control treatment. The total number of test lines
#' must be a perfect square.
#'
#' @param v Total number of test lines. Must be a perfect square
#'   greater than or equal to 9; for example, 9, 16, 25, 36, or 49.
#'
#' @return A list containing design parameters, non-randomized layouts,
#'   and randomized layouts.
#'
#' @export
TCpRep1 <- function(v) {
  
  ############################################################
  ## Input Validation
  ############################################################
  
  if (length(v) != 1L ||
      is.na(v) ||
      v < 9 ||
      v != as.integer(v)) {
    
    stop(
      "'v' must be a single integer representing the total number of test lines.",
      call. = FALSE
    )
    
  }
  
  s <- sqrt(v)
  
  if (s != as.integer(s)) {
    
    stop(
      "'v' must be a perfect square; for example: 9, 16, 25, 36, or 49.",
      call. = FALSE
    )
    
  }
  
  s <- as.integer(s)
  
  # One control is always included.
  control <- 1L
  
  ############################################################
  ## 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:v,
    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 One Fixed Control to Every Block
  ############################################################
  
  Design_TC <- lapply(
    environments,
    function(env) {
      
      env <- as.matrix(env)
      
      cbind(
        env,
        C = rep("C", nrow(env))
      )
    }
  )
  
  ############################################################
  ## Randomized Layout
  ############################################################
  
  Randomized_TC <- lapply(
    Design_TC,
    function(env) {
      
      randomized <- t(
        apply(
          env,
          1,
          sample
        )
      )
      
      rownames(randomized) <- rownames(env)
      
      randomized
    }
  )
  
  ############################################################
  ## Design 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(
      v,
      control,
      s,
      s * (s + 1),
      s + 1,
      s * (s + 1),
      s + 1
    ),
    
    stringsAsFactors = FALSE
  )
  
  ############################################################
  ## 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
  ############################################################
  
  structure(
    list(
      Parameters = Parameters,
      NonRandomized_Layout = NonRandomized_Layout,
      Randomized_Layout = Randomized_Layout
    ),
    class = "TCpRep"
  )
  
}

#' Print p-Rep Test-Control Design
#'
#' @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)
  
}

