##' Draw MCMC samples from the Spatial GLMM with known link function
##'
##' The four-parameter prior for \code{phi} is defined by
##' \deqn{\propto (\phi - \theta_4)^{\theta_2 -1} \exp\{-(\frac{\phi -
##' \theta_4}{\theta_1})^{\theta_3}\}}{propto (phi -
##' phiprior[4])^(phiprior[2]-1) *
##' exp(-((phi-phiprior[4])/phiprior[1])^phiprior[3])} for \eqn{\phi >
##' \theta_4}{phi > phiprior[4]}. The prior for \code{omg} is similar.
##' The prior parameters correspond to scale, shape, exponent, and
##' location. See \code{arXiv:1005.3274} for details of this
##' distribution.
##'
##' The GEV (Generalised Extreme Value) link is defined by \deqn{\mu =
##' 1 - \exp\{-\max(0, 1 + \nu x)^{\frac{1}{\nu}}\}}{mu = 1 -
##' \exp[-max(0, 1 + nu x)^(1/nu)]} for any real \eqn{\nu}{nu}. At
##' \eqn{\nu = 0}{nu = 0} it reduces to the complementary log-log
##' link.
##' @title MCMC samples from the Spatial GLMM
##' @param formula A representation of the model in the form
##'   \code{response ~ terms}. The response must be set to \code{NA}'s
##'   at the prediction locations (see the examples on how to do this
##'   using the function \code{\link{stackdata}}). At the observed
##'   locations the response is assumed to be a total of replicated
##'   measurements. The number of replications is inputted using the
##'   argument \code{weights}.
##' @param family The distribution of the data. The
##'   \code{"GEVbinomial"} family is the binomial family with link the
##'   GEV link (see Details).
##' @param data An optional data frame containing the variables in the
##'   model.
##' @param weights An optional vector of weights. Number of replicated
##'   samples for Gaussian and gamma, number of trials for binomial,
##'   time length for Poisson.
##' @param subset An optional vector specifying a subset of
##'   observations to be used in the fitting process.
##' @param offset See \code{\link[stats]{lm}}.
##' @param atsample A formula in the form \code{~ x1 + x2 + ... + xd}
##'   with the coordinates of the sampled locations.
##' @param corrfcn Spatial correlation function. See
##'   \code{\link{geoBayes_correlation}} for details.
##' @param linkp Parameter of the link function. A scalar value.
##' @param phi Optional starting value for the MCMC for the
##'   spatial range parameter \code{phi}. Defaults to the mean of its
##'   prior. If \code{corrtuning[["phi"]]} is 0, then this argument is required and
##'   it corresponds to the fixed value of \code{phi}. This can be a
##'   vector of the same length as Nout.
##' @param omg Optional starting value for the MCMC for the
##'   relative nugget parameter \code{omg}. Defaults to the mean of
##'   its prior. If \code{corrtuning[["omg"]]} is 0, then this argument is required
##'   and it corresponds to the fixed value of \code{omg}. This can be
##'   a vector of the same length as Nout.
##' @param kappa Optional starting value for the MCMC for the
##'   spatial correlation parameter \code{kappa} (Matern smoothness or
##'   exponential power). Defaults to the mean of
##'   its prior. If \code{corrtuning[["kappa"]]} is 0 and it is needed for
##'   the chosen correlation function, then this argument is required
##'   and it corresponds to the fixed value of \code{kappa}. This can be
##'   a vector of the same length as Nout.
##' @param Nout Number of MCMC samples to return. This can be a vector
##'   for running independent chains.
##' @param Nthin The thinning of the MCMC algorithm.
##' @param Nbi The burn-in of the MCMC algorithm.
##' @param betm0 Prior mean for beta (a vector or scalar).
##' @param betQ0 Prior standardised precision (inverse variance)
##'   matrix. Can be a scalar, vector or matrix. The first two imply a
##'   diagonal with those elements. Set this to 0 to indicate a flat
##'   improper prior.
##' @param ssqdf Degrees of freedom for the scaled inverse chi-square
##'   prior for the partial sill parameter.
##' @param ssqsc Scale for the scaled inverse chi-square prior for the
##'   partial sill parameter.
##' @param corrpriors A list with the components \code{phi},
##'   \code{omg} and \code{kappa} as needed. These correspond to the
##'   prior distribution parameters. For \code{phi} and \code{omg} it
##'   must be a vector of length 4. The generalized inverse gamma
##'   prior is assumed and the input corresponds to the parameters
##'   scale, shape, exponent, location in that order (see Details).
##'   For \code{kappa} it must be a vector of length 2. A uniform
##'   prior is assumed and the input corresponds to the lower and
##'   upper bounds in that order.
##' @param corrtuning A vector or list with the components \code{phi},
##'   \code{omg} and \code{kappa} as needed. These correspond to the
##'   random walk parameter for the Metropolis-Hastings step. Smaller values
##'   increase the acceptance ratio. Set this to 0 for fixed
##'   parameter value.
##' @param malatuning Tuning parameter for the MALA updates.
##' @param dispersion The fixed dispersion parameter.
##' @param longlat How to compute the distance between locations. If
##'   \code{FALSE}, Euclidean distance, if \code{TRUE} Great Circle
##'   distance. See \code{\link[sp]{spDists}}.
##' @param test Whether this is a trial run to monitor the acceptance
##'   ratio of the random walk for \code{phi} and \code{omg}. If set
##'   to \code{TRUE}, the acceptance ratio will be printed on the
##'   screen every 100 iterations of the MCMC. Tune the \code{phisc}
##'   and \code{omgsc} parameters in order to achive 20 to 30\%
##'   acceptance. Set this to a positive number to change the default
##'   100. No thinning or burn-in are done when testing.
##' @return A list containing the objects \code{MODEL}, \code{DATA},
##'   \code{FIXED}, \code{MCMC} and \code{call}. The MCMC samples are
##'   stored in the object \code{MCMC} as follows:
##' \itemize{
##'  \item \code{z} A matrix containing the MCMC samples for the
##' spatial random field. Each column is one sample.
##'  \item \code{mu} A matrix containing the MCMC samples for the
##' mean response (a transformation of z). Each column is one sample.
##'  \item \code{beta} A matrix containing the MCMC samples for the
##' regressor coefficients. Each column is one sample.
##'  \item \code{ssq} A vector with the MCMC samples for the partial
## sill parameter.
##'  \item \code{phi} A vector with the MCMC samples for the spatial
##' range parameter, if sampled.
##'  \item \code{omg} A vector with the MCMC samples for the relative
##' nugget parameter, if sampled.
##'  \item \code{logLik} A vector containing the value of the
##' log-likelihood evaluated at each sample.
##'  \item \code{acc_ratio} The acceptance ratio for the joint update
##' of the parameters \code{phi} and \code{omg}, if sampled.
##'  \item \code{sys_time} The total computing time for the MCMC sampling.
##'  \item \code{Nout}, \code{Nbi},  \code{Nthin} As in input. Used
##' internally in other functions.
##' }
##' The other objects contain input variables. The object \code{call}
##'   contains the function call.
##' @examples \dontrun{
##' data(rhizoctonia)
##'
##' ### Create prediction grid
##' predgrid <- mkpredgrid2d(rhizoctonia[c("Xcoord", "Ycoord")],
##'                          par.x = 100, chull = TRUE, exf = 1.2)
##'
##' ### Combine observed and prediction locations
##' rhizdata <- stackdata(rhizoctonia, predgrid$grid)
##' ##'
##' ### Define the model
##' corrf <- "spherical"
##' family <- "binomial.probit"
##' kappa <- 0
##' ssqdf <- 1
##' ssqsc <- 1
##' betm0 <- 0
##' betQ0 <- .01
##' phiprior <- c(100, 1, 1000, 100) # U(100, 200)
##' phisc <- 3
##' omgprior <- c(2, 1, 1, 0)        # Exp(mean = 2)
##' omgsc <- .1
##' ##'
##' ### MCMC sizes
##' Nout <- 100
##' Nthin <- 1
##' Nbi <- 0
##'
##' ### Trial run
##' emt <- mcsglmm_mala(Infected ~ 1, family, rhizdata, weights = Total,
##'                atsample = ~ Xcoord + Ycoord,
##'                Nout = Nout, Nthin = Nthin, Nbi = Nbi,
##'                betm0 = betm0, betQ0 = betQ0, ssqdf = ssqdf, ssqsc = ssqsc,
##'                corrpriors = list(phi = phiprior, omg = omgprior), 
##'                corrfcn = corrf, kappa = kappa,
##'                corrtuning = list(phi = phisc, omg = omgsc, kappa = 0),
##'                malatuning = .003, dispersion = 1, test = 10)
##'
##' ### Full run
##' emc <- update(emt, test = FALSE)
##'
##' emcmc <- mcmcmake(emc)
##' summary(emcmc[, c("phi", "omg", "beta", "ssq")])
##' plot(emcmc[, c("phi", "omg", "beta", "ssq")])
##' }
##' @importFrom sp spDists
##' @importFrom stats model.matrix model.response model.weights
##'   as.formula update model.offset
##' @useDynLib geoBayes mcspsamtry mcspsample
##' @export
mcsglmm_mala <- function (formula, family = "gaussian",
                          data, weights, subset, offset,
                          atsample, corrfcn = "matern",
                          linkp, phi, omg, kappa,
                          Nout, Nthin = 1, Nbi = 0, betm0, betQ0, ssqdf, ssqsc,
                          corrpriors, corrtuning, malatuning, 
                          dispersion = 1, longlat = FALSE, test = FALSE) {
  cl <- match.call()
  ## Family
  ifam <- .geoBayes_family(family)
  if (ifam) {
    family <- .geoBayes_models$family[ifam]
  } else {
    stop ("This family has not been implemented.")
  }
  if (.geoBayes_models$needlinkp[ifam]) {
    if (missing(linkp))
      stop ("Missing input linkp.")
  } else {
    linkp <- 0
  }

  ## Correlation function
  icf <- .geoBayes_correlation(corrfcn)
  corrfcn <- .geoBayes_corrfcn$corrfcn[icf]
  needkappa <- .geoBayes_corrfcn$needkappa[icf]

  ## Design matrix and data
  if (missing(data)) data <- environment(formula)
  if (length(formula) != 3) stop ("The formula input is incomplete.")
  if ("|" == all.names(formula[[2]], TRUE, 1)) formula[[2]] <- formula[[2]][[2]]
  mfc <- match.call(expand.dots = FALSE)
  m <- match(c("formula", "data", "subset", "weights", "offset"),
             names(mfc), 0L)
  mfc <- mfc[c(1L, m)]
  mfc$formula <- formula
  mfc$drop.unused.levels <- TRUE
  mfc$na.action <- "na.pass"
  mfc[[1L]] <- quote(stats::model.frame)
  mf <- eval(mfc, parent.frame())
  mt <- attr(mf, "terms")
  FF <- model.matrix(mt,mf)
  if (!all(is.finite(FF))) stop ("Non-finite values in the design matrix")
  p <- NCOL(FF)
  yy <- unclass(model.response(mf))
  if (!is.vector(yy)) {
    stop ("The response must be a vector")
  }
  yy <- as.double(yy)
  ll <- model.weights(mf)
  oofset <- as.vector(model.offset(mf))
  if (!is.null(oofset)) {
    if (length(oofset) != NROW(yy)) {
      stop(gettextf("number of offsets is %d, should equal %d (number of observations)", 
                    length(oofset), NROW(yy)), domain = NA)
    } else {
      oofset <- as.double(oofset)
    }
  } else {
    oofset <- double(NROW(yy))
  }

  ## All locations
  atsample <- update(atsample, NULL ~ . + 0) # No response and no intercept
  mfatc <- mfc
  mfatc$weights = NULL
  mfatc$formula = atsample
  mfat <- eval(mfatc, parent.frame())
  loc <- as.matrix(mfat)
  if (!all(is.finite(loc))) stop ("Non-finite values in the locations")
  if (corrfcn == "spherical" && NCOL(loc) > 3) {
    stop ("Cannot use the spherical correlation for dimensions
grater than 3.")
  }

  ## Split sample, prediction
  ii <- is.finite(yy)
  y <- yy[ii]
  k <- sum(ii)
  l <- ll[ii]
  l <- if (is.null(l)) rep.int(1.0, k) else as.double(l)
  if (any(!is.finite(l))) stop ("Non-finite values in the weights")
  if (any(l <= 0)) stop ("Non-positive weights not allowed")
  if (grepl("^binomial(\\..+)?$", family)) {
    l <- l - y # Number of failures
  }
  F <- FF[ii, , drop = FALSE]
  offset <- oofset[ii]
  dm <- sp::spDists(loc[ii, , drop = FALSE], longlat = longlat)
  k0 <- sum(!ii)
  if (k0 > 0) {
    F0 <- FF[!ii, , drop = FALSE]
    dmdm0 <- sp::spDists(loc[ii, , drop = FALSE], loc[!ii, , drop = FALSE],
                         longlat = longlat)
    offset0 <- oofset[!ii]
  } else {
    F0 <- dmdm0 <- offset0 <- numeric(0)
    dim(F0) <- c(0, p)
    dim(dmdm0) <- c(k, 0)
  }

  ## Prior for ssq
  ssqdf <- as.double(ssqdf)
  if (ssqdf <= 0) stop ("Argument ssqdf must > 0")
  ssqsc <- as.double(ssqsc)
  if (ssqsc <= 0) stop ("Argument ssqsc must > 0")

  ## Prior for beta
  betaprior <- getbetaprior(betm0, betQ0, p)
  betm0 <- betaprior$betm0
  betQ0 <- betaprior$betQ0

  ## Other fixed parameters
  dispersion <- as.double(dispersion)
  if (dispersion <= 0) stop ("Invalid argument dispersion")

  nu <- .geoBayes_getlinkp(linkp, ifam)

  ## MCMC samples
  Nout <- as.integer(Nout)
  if (any(Nout < 0)) stop ("Negative MCMC sample size entered.")
  nch <- length(Nout)         # Number of chains
  Nmc <- Nout                 # Size of each chain
  Nout <- sum(Nout)           # Total MCMC size
  Nbi <- as.integer(Nbi)
  Nthin <- as.integer(Nthin)
  lglk <- numeric(Nout)
  z <- matrix(0, k, Nout)
  z0 <- matrix(0, k0, Nout)
  beta <- matrix(0, p, Nout)
  ssq <- numeric(Nout)
  if (malatuning <= 0) stop ("Input malatuning must > 0.")

  ## Starting values for correlation parameters
  phisc <- corrtuning[["phi"]]
  if (is.null(phisc) || !is.numeric(phisc) || phisc < 0)
    stop ("Invalid tuning parameter for phi.")
  if (phisc > 0) {
    phipars <- check_gengamma_prior(corrpriors[["phi"]])
  } else phipars <- rep.int(0, 4)
  if (missing(phi)) {
    if (phisc == 0) {
      stop ("Argument phi needed for fixed phi")
    } else {
      if(phipars[2] == -1) {
        tmp <- .1/abs(phipars[3])
      } else {
        tmp <- abs((phipars[2]+1)/phipars[3])
      }
      phistart <- phipars[4] + phipars[1]*gamma(tmp)/
        gamma(phipars[2]/phipars[3])
    }
  } else {
    phistart <- as.double(phi)
    if (phisc > 0 && phistart <= phipars[4]) {
      stop ("Starting value for phi not in the support of its prior")
    }
  }
  phi <- numeric(Nout)
  phi[cumsum(c(1, Nmc[-nch]))] <- phistart

  omgsc <- corrtuning[["omg"]]
  if (is.null(omgsc) || !is.numeric(omgsc) || omgsc < 0)
    stop ("Invalid tuning parameter for omg.")
  if (omgsc > 0) {
    omgpars <- check_gengamma_prior(corrpriors[["omg"]])
  } else omgpars <- rep.int(0, 4)
  if (missing(omg)) {
    if (omgsc == 0) {
      stop ("Argument omg needed for fixed omg")
    } else {
      if(omgpars[2] == -1) {
        tmp <- .1/abs(omgpars[3])
      } else {
        tmp <- abs((omgpars[2]+1)/omgpars[3])
      }
      omgstart <- omgpars[4] + omgpars[1]*gamma(tmp)/
        gamma(omgpars[2]/omgpars[3])
    }
  } else {
    omgstart <- as.double(omg)
    if (omgsc > 0 && omgstart <= omgpars[4]) {
      stop ("Starting value for omg not in the support of its prior")
    }
  }
  omg <- numeric(Nout)
  omg[cumsum(c(1, Nmc[-nch]))] <- omgstart

  if (needkappa) {
    kappasc <- corrtuning[["kappa"]]
  } else {
    kappasc <- 0
    kappa <- 0
  }
  if (is.null(kappasc) || !is.numeric(kappasc) || kappasc < 0)
    stop ("Invalid tuning parameter for kappa.")
  if (kappasc > 0) {
    kappapars <- check_unif_prior(corrpriors[["kappa"]])
  } else kappapars <- c(0, 0)
  if (missing(kappa)) {
    if (kappasc == 0) {
      stop ("Argument kappa needed for fixed kappa")
    } else {
      kappastart <- (kappapars[1] + kappapars[2])*.5
    }
  } else {
    kappastart <- as.double(kappa)
  }
  if (kappasc > 0) {
    kappastart <- .geoBayes_getkappa(kappastart, icf)
    kappapars <- .geoBayes_getkappa(kappapars, icf)
    if (kappastart >= kappapars[2] || kappastart <= kappapars[1]) {
      stop ("Starting value for kappa not in the support of its prior")
    }
  }
  kappa <- numeric(Nout)
  kappa[cumsum(c(1, Nmc[-nch]))] <- kappastart

  ## Run code
  if (test > 0) { # Running a test
    if (is.logical(test)) test <- 100
    test <- as.integer(test)
    acc <- acc_z <- 0L
    tm <- system.time({
      RUN <- .Fortran("mcspsamtry_mala", ll = lglk, z = z, phi = phi, omg = omg,
                      kappa = kappa,
                      acc = acc,
                      as.double(y), as.double(l), as.double(F),
                      as.double(offset), 
                      as.double(betm0), as.double(betQ0), as.double(ssqdf),
                      as.double(ssqsc), as.double(phipars),
                      as.double(omgpars), as.double(kappapars),
                      as.double(phisc), as.double(omgsc), as.double(kappasc),
                      as.integer(icf),
                      as.double(nu), as.double(dispersion), as.double(dm),
                      as.integer(Nout), as.integer(test), as.integer(k),
                      as.integer(p), as.integer(ifam), as.double(malatuning), 
                      acc_z = acc_z, PACKAGE = "geoBayes")
    })
    ## Store samples
    ll <- RUN$ll
    zz0 <- matrix(NA, NROW(yy), Nout)
    zz0[ii, ] <- RUN$z
    mm0 <- NULL
    beta <- NULL
    ssq <- NULL
    phi <- RUN$phi
###     attr(phi, 'fixed') <- phisc == 0
    omg <- RUN$omg
###     attr(omg, 'fixed') <- omgsc == 0
###     attr(nu, 'fixed') <- TRUE
    kappa <- RUN$kappa
    acc_ratio <- RUN$acc/Nout
    acc_ratio_z <- RUN$acc_z/Nout
    Nthin <- 1
    Nbi <- 0
###     out <- list(z = zz0, beta = beta, ssq = ssq, phi = phi, omg = omg, nu = nu,
###                 logLik = ll, acc_ratio = acc_ratio, sys_time = tm,
###                 Nout = Nout, Nbi = Nbi, Nthin = Nthin,
###                 response = y, weights = l, modelmatrix = F, family = family,
###                 betm0 = betm0, betQ0 = betQ0, ssqdf = ssqdf, ssqsc = ssqsc,
###                 corrfcn = corrfcn, kappa = kappa,
###                 dispersion = dispersion, locations = loc[ii, , drop = FALSE],
###                 longlat = longlat, whichobs = ii)
  } else {
    acc <- acc_z <- integer(nch)
    tm <- system.time({
      RUN <- .Fortran("mcspsample_mala", ll = lglk, z = z, z0 = z0,
                      mu = z, mu0 = z0,
                      beta = beta, ssq = ssq,
                      phi = phi, omg = omg, kappa = kappa, acc = acc,
                      as.double(y), as.double(l), as.double(F),
                      as.double(offset), as.double(F0), as.double(offset0), 
                      as.double(betm0), as.double(betQ0), as.double(ssqdf),
                      as.double(ssqsc), as.double(phipars), as.double(omgpars),
                      as.double(kappapars),
                      as.double(phisc), as.double(omgsc), as.double(kappasc),
                      as.integer(icf),
                      as.double(nu), as.double(dispersion), as.double(dm),
                      as.double(dmdm0), as.integer(nch), as.integer(Nmc),
                      as.integer(Nout), as.integer(Nbi),
                      as.integer(Nthin), as.integer(k), as.integer(k0),
                      as.integer(p), as.integer(ifam), as.double(malatuning),
                      acc_z = acc_z, 
                      PACKAGE = "geoBayes")
    })
    ## Store samples
    ll <- RUN$ll
    zz0 <- mm0 <- matrix(NA, NROW(yy), Nout)
    zz0[ii, ] <- RUN$z
    zz0[!ii, ] <- RUN$z0
    mm0[ii, ] <- RUN$mu
    mm0[!ii, ] <- RUN$mu0
    beta <- RUN$beta
    ssq <- RUN$ssq
    phi <- RUN$phi
###    attr(phi, 'fixed') <- phisc == 0
    omg <- RUN$omg
###    attr(omg, 'fixed') <- omgsc == 0
###    attr(nu, 'fixed') <- TRUE
    kappa <- RUN$kappa
    acc_ratio <- RUN$acc/(Nmc*Nthin + max(Nthin, Nbi))
    acc_ratio_z <- RUN$acc_z/(Nmc*Nthin + max(Nthin, Nbi))
###     out <- list(z = zz0, mu = mm0,
###                 beta = beta, ssq = ssq, phi = phi, omg = omg, nu = nu,
###                 logLik = ll, acc_ratio = acc_ratio, sys_time = tm,
###                 Nout = Nout, Nbi = Nbi, Nthin = Nthin,
###                 response = y, weights = l, modelmatrix = F, family = family,
###                 betm0 = betm0, betQ0 = betQ0, ssqdf = ssqdf, ssqsc = ssqsc,
###                 corrfcn = corrfcn, kappa = kappa,
###                 dispersion = dispersion, locations = loc[ii, , drop = FALSE],
###                 longlat = longlat, whichobs = ii)
  }
  MCMC <- FIXED <- MODEL <- DATA <- list()
  MCMC$z <- zz0
  MCMC$mu <- mm0
  MCMC$beta <- beta
  MCMC$ssq <- ssq
  FIXED$linkp <- as.vector(linkp)
  FIXED$linkp_num <- nu
  if (phisc == 0) {
    FIXED$phi <- phi[1]
  } else {
    MCMC$phi <- phi
  }
  if (omgsc == 0) {
    FIXED$omg <- omg[1]
  } else {
    MCMC$omg <- omg
  }
  if (kappasc == 0) {
    FIXED$kappa <- kappa[1]
  } else {
    MCMC$kappa <- kappa
  }
  MCMC$logLik <- ll
  MCMC$acc_ratio <- acc_ratio
  MCMC$acc_ratio_z <- acc_ratio_z
  MCMC$sys_time <- tm
  MCMC$Nout <- Nout
  MCMC$Nbi <- Nbi
  MCMC$Nthin <- Nthin
  MCMC$whichobs <- ii
  DATA$response <- y
  DATA$weights <- l
  DATA$modelmatrix <- F
  DATA$offset <- offset
  DATA$locations <- loc[ii, , drop = FALSE]
  DATA$longlat <- longlat
  MODEL$family <- family
  MODEL$corrfcn <- corrfcn
  MODEL$betm0 <- betm0
  MODEL$betQ0 <- betQ0
  MODEL$ssqdf <- ssqdf
  MODEL$ssqsc <- ssqsc
  MODEL$phipars <- phipars
  MODEL$omgpars <- omgpars
  MODEL$dispersion <- dispersion
  out <- list(MODEL = MODEL, DATA = DATA, FIXED = FIXED, MCMC = MCMC, call = cl)
  class(out) <- "geomcmc"
  out
}

##' Draw MCMC samples from the transformed Gaussian model with known
##' link function
##'
##' Simulates from the posterior distribution of this model.
##' @title MCMC samples from the transformed Gaussian model
##' @param formula A representation of the model in the form
##' \code{response ~ terms}. The response must be set to \code{NA}'s
##' at the prediction locations (see the example in
##' \code{\link{mcsglmm}} for how to do this using
##' \code{\link{stackdata}}). At the observed locations the response
##' is assumed to be a total of replicated measurements. The number of
##' replications is inputted using the argument \code{weights}.
##' @param data An optional data frame containing the variables in the
##' model.
##' @param weights An optional vector of weights. Number of replicated
##' samples.
##' @param subset An optional vector specifying a subset of
##' observations to be used in the fitting process.
##' @param offset See \code{\link[stats]{lm}}.
##' @param atsample A formula in the form \code{~ x1 + x2 + ... + xd}
##' with the coordinates of the sampled locations.
##' @param corrfcn Spatial correlation function. See
##' \code{\link{geoBayes_correlation}} for details.
##' @param linkp Parameter of the link function. A scalar value.
##' @param phi Optional starting value for the MCMC for the
##'   spatial range parameter \code{phi}. Defaults to the mean of its
##'   prior. If \code{corrtuning[["phi"]]} is 0, then this argument is required and
##'   it corresponds to the fixed value of \code{phi}. This can be a
##'   vector of the same length as Nout.
##' @param omg Optional starting value for the MCMC for the
##'   relative nugget parameter \code{omg}. Defaults to the mean of
##'   its prior. If \code{corrtuning[["omg"]]} is 0, then this argument is required
##'   and it corresponds to the fixed value of \code{omg}. This can be
##'   a vector of the same length as Nout.
##' @param kappa Optional starting value for the MCMC for the
##'   spatial correlation parameter \code{kappa} (Matern smoothness or
##'   exponential power). Defaults to the mean of
##'   its prior. If \code{corrtuning[["kappa"]]} is 0 and it is needed for
##'   the chosen correlation function, then this argument is required
##'   and it corresponds to the fixed value of \code{kappa}. This can be
##'   a vector of the same length as Nout.
##' @param Nout Number of MCMC samples to return. This can be a vector
##'   for running independent chains.
##' @param Nthin The thinning of the MCMC algorithm.
##' @param Nbi The burn-in of the MCMC algorithm.
##' @param betm0 Prior mean for beta (a vector or scalar).
##' @param betQ0 Prior standardised precision (inverse variance)
##' matrix. Can be a scalar, vector or matrix. The first two imply a
##' diagonal with those elements. Set this to 0 to indicate a flat
##' improper prior.
##' @param ssqdf Degrees of freedom for the scaled inverse chi-square
##' prior for the partial sill parameter.
##' @param ssqsc Scale for the scaled inverse chi-square prior for the
##' partial sill parameter.
##' @param tsqdf Degrees of freedom for the scaled inverse chi-square
##' prior for the measurement error parameter.
##' @param tsqsc Scale for the scaled inverse chi-square prior for the
##' measurement error parameter.
##' @param corrpriors A list with the components \code{phi},
##'   \code{omg} and \code{kappa} as needed. These correspond to the
##'   prior distribution parameters. For \code{phi} and \code{omg} it
##'   must be a vector of length 4. The generalized inverse gamma
##'   prior is assumed and the input corresponds to the parameters
##'   scale, shape, exponent, location in that order (see Details).
##'   For \code{kappa} it must be a vector of length 2. A uniform
##'   prior is assumed and the input corresponds to the lower and
##'   upper bounds in that order.
##' @param malatuning Tuning parameter for the MALA updates.
##' @param corrtuning A vector or list with the components \code{phi},
##'   \code{omg} and \code{kappa} as needed. These correspond to the
##'   random walk parameter for the Metropolis-Hastings step. Smaller values
##'   increase the acceptance ratio. Set this to 0 for fixed
##'   parameter value.
##' @param longlat How to compute the distance between locations. If
##' \code{FALSE}, Euclidean distance, if \code{TRUE} Great Circle
##' distance. See \code{\link[sp]{spDists}}.
##' @param test Whether this is a trial run to monitor the acceptance
##' ratio of the random walk for \code{phi} and \code{omg}. If set to
##' \code{TRUE}, the acceptance ratio will be printed on the screen
##' every 100 iterations of the MCMC. Tune the \code{phisc} and
##' \code{omgsc} parameters in order to achive 20 to 30\% acceptance.
##' Set this to a positive number to change the default 100. No
##' thinning or burn-in are done when testing.
##' @return A list containing the objects \code{MODEL}, \code{DATA},
##'   \code{FIXED}, \code{MCMC} and \code{call}. The MCMC samples are
##'   stored in the object \code{MCMC} as follows:
##' \itemize{
##'  \item \code{z} A matrix containing the MCMC samples for the
##' spatial random field. Each column is one sample.
##'  \item \code{mu} A matrix containing the MCMC samples for the
##' mean response (a transformation of z). Each column is one sample.
##'  \item \code{beta} A matrix containing the MCMC samples for the
##' regressor coefficients. Each column is one sample.
##'  \item \code{ssq} A vector with the MCMC samples for the partial
## sill parameter.
##'  \item \code{tsq} A vector with the MCMC samples for the
##' measurement error variance.
##'  \item \code{phi} A vector with the MCMC samples for the spatial
##' range parameter, if sampled.
##'  \item \code{omg} A vector with the MCMC samples for the relative
##' nugget parameter, if sampled.
##'  \item \code{logLik} A vector containing the value of the
##' log-likelihood evaluated at each sample.
##'  \item \code{acc_ratio} The acceptance ratio for the joint update
##' of the parameters \code{phi} and \code{omg}, if sampled.
##'  \item \code{sys_time} The total computing time for the MCMC sampling.
##'  \item \code{Nout}, \code{Nbi},  \code{Nthin} As in input. Used
##' internally in other functions.
##' }
##' The other objects contain input variables. The object \code{call}
##'   contains the function call.
##' @examples \dontrun{
##' ### Load the data
##' data(rhizoctonia)
##' rhiz <- na.omit(rhizoctonia)
##' rhiz$IR <- rhiz$Infected/rhiz$Total # Incidence rate of the
##'                               # rhizoctonia disease
##'
##' ### Define the model
##' corrf <- "spherical"
##' ssqdf <- 1
##' ssqsc <- 1
##' tsqdf <- 1
##' tsqsc <- 1
##' betm0 <- 0
##' betQ0 <- diag(.01, 2, 2)
##' phiprior <- c(200, 1, 1000, 100) # U(100, 300)
##' phisc <- 1
##' omgprior <- c(3, 1, 1000, 0) # U(0, 3)
##' omgsc <- 1
##' linkp <- 1
##'
##' ## MCMC parameters
##' Nout <- 100
##' Nbi <- 0
##' Nthin <- 1
##'
##' samplt <- mcstrga_mala(Yield ~ IR, data = rhiz,
##'                   atsample = ~ Xcoord + Ycoord, corrf = corrf,
##'                   Nout = Nout, Nthin = Nthin,
##'                   Nbi = Nbi, betm0 = betm0, betQ0 = betQ0,
##'                   ssqdf = ssqdf, ssqsc = ssqsc,
##'                   tsqdf = tsqdf, tsqsc = tsqsc,
##'                   corrprior = list(phi = phiprior, omg = omgprior),
##'                   linkp = linkp,
##'                   corrtuning = list(phi = phisc, omg = omgsc, kappa = 0),
##'                   malatuning = .0002, test=10)
##'
##' sample <- update(samplt, test = FALSE)
##' }
##' @importFrom sp spDists
##' @importFrom stats model.matrix model.response model.weights
##'   as.formula update model.offset
##' @useDynLib geoBayes trgasamtry trgasample
##' @export
mcstrga_mala <- function (formula,
                          data, weights, subset, offset,
                          atsample, corrfcn = "matern",
                          linkp, phi, omg, kappa,
                          Nout, Nthin = 1, Nbi = 0, betm0, betQ0, ssqdf, ssqsc,
                          tsqdf, tsqsc,
                          corrpriors, corrtuning, malatuning, 
                          longlat = FALSE,
                          test = FALSE) {
  cl <- match.call()

  family <- "transformed.gaussian"

  ## Correlation function
  icf <- .geoBayes_correlation(corrfcn)
  corrfcn <- .geoBayes_corrfcn$corrfcn[icf]
  needkappa <- .geoBayes_corrfcn$needkappa[icf]

  ## Design matrix and data
  if (missing(data)) data <- environment(formula)
  if (length(formula) != 3) stop ("The formula input is incomplete.")
  if ("|" == all.names(formula[[2]], TRUE, 1)) formula[[2]] <- formula[[2]][[2]]
  mfc <- match.call(expand.dots = FALSE)
  m <- match(c("formula", "data", "subset", "weights", "offset"),
             names(mfc), 0L)
  mfc <- mfc[c(1L, m)]
  mfc$formula <- formula
  mfc$drop.unused.levels <- TRUE
  mfc$na.action <- "na.pass"
  mfc[[1L]] <- quote(stats::model.frame)
  mf <- eval(mfc, parent.frame())
  mt <- attr(mf, "terms")
  FF <- model.matrix(mt,mf)
  if (!all(is.finite(FF))) stop ("Non-finite values in the design matrix")
  p <- NCOL(FF)
  yy <- unclass(model.response(mf))
  if (!is.vector(yy)) {
    stop ("The response must be a vector")
  }
  yy <- as.double(yy)
  ll <- model.weights(mf)
  oofset <- as.vector(model.offset(mf))
  if (!is.null(oofset)) {
    if (length(oofset) != NROW(yy)) {
      stop(gettextf("number of offsets is %d, should equal %d (number of observations)", 
                    length(oofset), NROW(yy)), domain = NA)
    } else {
      oofset <- as.double(oofset)
    }
  } else {
    oofset <- double(NROW(yy))
  }

  ## All locations
  atsample <- update(atsample, NULL ~ . + 0) # No response and no intercept
  mfatc <- mfc
  mfatc$weights = NULL
  mfatc$formula = atsample
  mfat <- eval(mfatc, parent.frame())
  loc <- as.matrix(mfat)
  if (!all(is.finite(loc))) stop ("Non-finite values in the locations")
  if (corrfcn == "spherical" && NCOL(loc) > 3) {
    stop ("Cannot use the spherical correlation for dimensions
grater than 3.")
  }

  ## Split sample, prediction
  ii <- is.finite(yy)
  y <- yy[ii]
  k <- sum(ii)
  l <- ll[ii]
  l <- if (is.null(l)) rep.int(1.0, k) else as.double(l)
  if (any(!is.finite(l))) stop ("Non-finite values in the weights")
  if (any(l <= 0)) stop ("Non-positive weights not allowed")
  ybar <- y/l
  F <- FF[ii, , drop = FALSE]
  offset <- oofset[ii]
  dm <- sp::spDists(loc[ii, , drop = FALSE], longlat = longlat)
  k0 <- sum(!ii)
  if (k0 > 0) {
    F0 <- FF[!ii, , drop = FALSE]
    dmdm0 <- sp::spDists(loc[ii, , drop = FALSE], loc[!ii, , drop = FALSE],
                         longlat = longlat)
    offset0 <- oofset[!ii]
  } else {
    F0 <- dmdm0 <- offset0 <- numeric(0)
    dim(F0) <- c(0, p)
    dim(dmdm0) <- c(k, 0)
  }

  ## Prior for ssq
  ssqdf <- as.double(ssqdf)
  if (ssqdf <= 0) stop ("Argument ssqdf must > 0")
  ssqsc <- as.double(ssqsc)
  if (ssqsc <= 0) stop ("Argument ssqsc must > 0")

  ## Prior for beta
  betaprior <- getbetaprior(betm0, betQ0, p)
  betm0 <- betaprior$betm0
  betQ0 <- betaprior$betQ0

  ## Prior for tsq
  tsqdf <- as.double(tsqdf)
  if (tsqdf <= 0) stop ("Argument tsqdf must > 0")
  tsqsc <- as.double(tsqsc)
  if (tsqsc <= 0) stop ("Argument tsqsc must > 0")

  if (missing(linkp))
    stop ("Missing input linkp.")
  nu <- .geoBayes_getlinkp(linkp, family)

  ## MCMC samples
  Nout <- as.integer(Nout)
  if (any(Nout < 0)) stop ("Negative MCMC sample size entered.")
  nch <- length(Nout)         # Number of chains
  Nmc <- Nout                 # Size of each chain
  Nout <- sum(Nout)           # Total MCMC size
  Nbi <- as.integer(Nbi)
  Nthin <- as.integer(Nthin)
  lglk <- numeric(Nout)
  z <- matrix(0, k, Nout)
  z0 <- matrix(0, k0, Nout)
  beta <- matrix(0, p, Nout)
  ssq <- tsq <- numeric(Nout)
  if (malatuning <= 0) stop ("Input malatuning must > 0.")

  ## Starting values for correlation parameters
  phisc <- corrtuning[["phi"]]
  if (is.null(phisc) || !is.numeric(phisc) || phisc < 0)
    stop ("Invalid tuning parameter for phi.")
  if (phisc > 0) {
    phipars <- check_gengamma_prior(corrpriors[["phi"]])
  } else phipars <- rep.int(0, 4)
  if (missing(phi)) {
    if (phisc == 0) {
      stop ("Argument phi needed for fixed phi")
    } else {
      if(phipars[2] == -1) {
        tmp <- .1/abs(phipars[3])
      } else {
        tmp <- abs((phipars[2]+1)/phipars[3])
      }
      phistart <- phipars[4] + phipars[1]*gamma(tmp)/
        gamma(phipars[2]/phipars[3])
    }
  } else {
    phistart <- as.double(phi)
    if (phisc > 0 && phistart <= phipars[4]) {
      stop ("Starting value for phi not in the support of its prior")
    }
  }
  phi <- numeric(Nout)
  phi[cumsum(c(1, Nmc[-nch]))] <- phistart

  omgsc <- corrtuning[["omg"]]
  if (is.null(omgsc) || !is.numeric(omgsc) || omgsc < 0)
    stop ("Invalid tuning parameter for omg.")
  if (omgsc > 0) {
    omgpars <- check_gengamma_prior(corrpriors[["omg"]])
  } else omgpars <- rep.int(0, 4)
  if (missing(omg)) {
    if (omgsc == 0) {
      stop ("Argument omg needed for fixed omg")
    } else {
      if(omgpars[2] == -1) {
        tmp <- .1/abs(omgpars[3])
      } else {
        tmp <- abs((omgpars[2]+1)/omgpars[3])
      }
      omgstart <- omgpars[4] + omgpars[1]*gamma(tmp)/
        gamma(omgpars[2]/omgpars[3])
    }
  } else {
    omgstart <- as.double(omg)
    if (omgsc > 0 && omgstart <= omgpars[4]) {
      stop ("Starting value for omg not in the support of its prior")
    }
  }
  omg <- numeric(Nout)
  omg[cumsum(c(1, Nmc[-nch]))] <- omgstart

  if (needkappa) {
    kappasc <- corrtuning[["kappa"]]
  } else {
    kappasc <- 0
    kappa <- 0
  }
  if (is.null(kappasc) || !is.numeric(kappasc) || kappasc < 0)
    stop ("Invalid tuning parameter for kappa.")
  if (kappasc > 0) {
    kappapars <- check_unif_prior(corrpriors[["kappa"]])
  } else kappapars <- c(0, 0)
  if (missing(kappa)) {
    if (kappasc == 0) {
      stop ("Argument kappa needed for fixed kappa")
    } else {
      kappastart <- (kappapars[1] + kappapars[2])*.5
    }
  } else {
    kappastart <- as.double(kappa)
  }
  if (kappasc > 0) {
    kappastart <- .geoBayes_getkappa(kappastart, icf)
    kappapars <- .geoBayes_getkappa(kappapars, icf)
    if (kappastart >= kappapars[2] || kappastart <= kappapars[1]) {
      stop ("Starting value for kappa not in the support of its prior")
    }
  }
  kappa <- numeric(Nout)
  kappa[cumsum(c(1, Nmc[-nch]))] <- kappastart

  ## Run code
  if (test > 0) { # Running a test
    if (is.logical(test)) test <- 100
    test <- as.integer(test)
    acc <- acc_z <- 0L
    tm <- system.time({
      RUN <- .Fortran("trgasamtry_mala", ll = lglk, z = z, phi = phi, omg = omg,
                      kappa = kappa, acc = acc,
                      as.double(ybar), as.double(l), as.double(F),
                      as.double(offset), 
                      as.double(betm0), as.double(betQ0), as.double(ssqdf),
                      as.double(ssqsc), as.double(tsqdf), as.double(tsqsc),
                      as.double(phipars), as.double(omgpars),
                      as.double(kappapars),
                      as.double(phisc), as.double(omgsc),
                      as.double(kappasc), as.integer(icf),
                      as.double(nu), as.double(dm), as.integer(Nout),
                      as.integer(test), as.integer(k), as.integer(p),
                      as.double(malatuning), acc_z = acc_z,
                      PACKAGE = "geoBayes")
    })
    ## Store samples
    ll <- RUN$ll
    zz0 <- matrix(NA, NROW(yy), Nout)
    zz0[ii, ] <- RUN$z
    mm0 <- NULL
    beta <- NULL
    ssq <- NULL
    phi <- RUN$phi
###     attr(phi, 'fixed') <- phisc == 0
    omg <- RUN$omg
###     attr(omg, 'fixed') <- omgsc == 0
###     attr(nu, 'fixed') <- TRUE
    kappa <- RUN$kappa
    acc_ratio <- RUN$acc/Nout
    acc_ratio_z <- RUN$acc_z/Nout
    Nthin <- 1
    Nbi <- 0
###     out <- list(z = zz0, beta = beta, ssq = ssq, phi = phi, omg = omg, nu = nu,
###                 logLik = ll, acc_ratio = acc_ratio, sys_time = tm,
###                 Nout = Nout, Nbi = Nbi, Nthin = Nthin,
###                 response = y, weights = l, modelmatrix = F, family = family,
###                 betm0 = betm0, betQ0 = betQ0, ssqdf = ssqdf, ssqsc = ssqsc,
###                 corrfcn = corrfcn, kappa = kappa,
###                 tsqdf = tsqdf, tsqsc = tsqsc,
###                 locations = loc[ii, , drop = FALSE],
###                 longlat = longlat, whichobs = ii)
  } else {
    acc <- acc_z <- integer(nch)
    tm <- system.time({
      RUN <- .Fortran("trgasample_mala", ll = lglk, z = z, z0 = z0,
                      mu = z, mu0 = z0, beta = beta, ssq = ssq,
                      tsq = tsq, phi = phi, omg = omg,
                      kappa = kappa, acc = acc,
                      as.double(ybar),
                      as.double(l), as.double(F),
                      as.double(offset), as.double(F0), as.double(offset0), 
                      as.double(betm0), as.double(betQ0), as.double(ssqdf),
                      as.double(ssqsc), as.double(tsqdf), as.double(tsqsc),
                      as.double(phipars), as.double(omgpars),
                      as.double(kappapars),
                      as.double(phisc), as.double(omgsc), as.double(kappasc),
                      as.integer(icf),
                      as.double(nu), as.double(dm), as.double(dmdm0),
                      as.integer(nch), as.integer(Nmc),
                      as.integer(Nout), as.integer(Nbi), as.integer(Nthin),
                      as.integer(k), as.integer(k0), as.integer(p),
                      as.double(malatuning), acc_z = acc_z,
                      PACKAGE = "geoBayes")
    })
    ## Store samples
    ll <- RUN$ll
    zz0 <- mm0 <- matrix(NA, NROW(yy), Nout)
    zz0[ii, ] <- RUN$z
    zz0[!ii, ] <- RUN$z0
    mm0[ii, ] <- RUN$mu
    mm0[!ii, ] <- RUN$mu0
    beta <- RUN$beta
    ssq <- RUN$ssq
    tsq <- RUN$tsq
    phi <- RUN$phi
###     attr(phi, 'fixed') <- phisc == 0
    omg <- RUN$omg
###     attr(omg, 'fixed') <- omgsc == 0
###     attr(nu, 'fixed') <- TRUE
    kappa <- RUN$kappa
    acc_ratio <- RUN$acc/(Nmc*Nthin + max(Nthin, Nbi))
    acc_ratio_z <- RUN$acc_z/(Nmc*Nthin + max(Nthin, Nbi))
###     out <- list(z = zz0, mu = mm0, beta = beta, ssq = ssq, tsq = tsq,
###                 phi = phi, omg = omg, nu = nu,
###                 logLik = ll, acc_ratio = acc_ratio, sys_time = tm,
###                 Nout = Nout, Nbi = Nbi, Nthin = Nthin,
###                 response = ybar, weights = l, modelmatrix = F, family = family,
###                 betm0 = betm0, betQ0 = betQ0, ssqdf = ssqdf, ssqsc = ssqsc,
###                 corrfcn = corrfcn, kappa = kappa,
###                 tsqdf = tsqdf, tsqsc = tsqsc,
###                 locations = loc[ii, , drop = FALSE],
###                 longlat = longlat, whichobs = ii)
  }
  MCMC <- FIXED <- MODEL <- DATA <- list()
  MCMC$z <- zz0
  MCMC$mu <- mm0
  MCMC$beta <- beta
  MCMC$ssq <- ssq
  MCMC$tsq <- tsq
  FIXED$linkp <- linkp
  FIXED$linkp_num <- nu
  if (phisc == 0) {
    FIXED$phi <- phi[1]
  } else {
    MCMC$phi <- phi
  }
  if (omgsc == 0) {
    FIXED$omg <- omg[1]
  } else {
    MCMC$omg <- omg
  }
  if (kappasc == 0) {
    FIXED$kappa <- kappa[1]
  } else {
    MCMC$kappa <- kappa
  }
  MCMC$logLik <- ll
  MCMC$acc_ratio <- acc_ratio
  MCMC$acc_ratio_z <- acc_ratio_z
  MCMC$sys_time <- tm
  MCMC$Nout <- Nout
  MCMC$Nbi <- Nbi
  MCMC$Nthin <- Nthin
  MCMC$whichobs <- ii
  DATA$response <- ybar
  DATA$weights <- l
  DATA$modelmatrix <- F
  DATA$offset <- offset
  DATA$locations <- loc[ii, , drop = FALSE]
  DATA$longlat <- longlat
  MODEL$family <- family
  MODEL$corrfcn <- corrfcn
  MODEL$betm0 <- betm0
  MODEL$betQ0 <- betQ0
  MODEL$ssqdf <- ssqdf
  MODEL$ssqsc <- ssqsc
  MODEL$tsqdf <- tsqdf
  MODEL$tsqsc <- tsqsc
  MODEL$phipars <- phipars
  MODEL$omgpars <- omgpars
  out <- list(MODEL = MODEL, DATA = DATA, FIXED = FIXED, MCMC = MCMC, call = cl)
  class(out) <- "geomcmc"
  out
}
