################################################################################
# ca():  Computation of Simple CA
################################################################################
# ca.matrix() # ca methods below
ca.matrix <- function(obj, 
               nd        = NA, 
               suprow    = NA, 
               supcol    = NA,
               subsetrow = NA,
               subsetcol = NA,
               ...){
  nd0 <- nd
  I   <- dim(obj)[1] ; J <- dim(obj)[2]
  rn  <- dimnames(obj)[[1]]
  cn  <- dimnames(obj)[[2]]
  N   <- matrix(as.matrix(obj), nrow = I, ncol = J)
 # Temporary remove supplementray rows/columns:
  Ntemp <- N ; NtempC <- NtempR <- N
  suprow <- sort(suprow) ; supcol <- sort(supcol)
 # back to supplementary profiles:
  if (!is.na(supcol[1]) & !is.na(suprow[1])) { 
    NtempC <- Ntemp[-suprow,] 
    NtempR <- Ntemp[,-supcol] 
    }
  if (!is.na(supcol[1])) { 
    SC     <- as.matrix(NtempC[,supcol])
    Ntemp  <- Ntemp[,-supcol]
    cs.sum <- apply(SC, 2, sum)
    }
  if (!is.na(suprow[1])) {
    SR     <- matrix(as.matrix(NtempR[suprow,]), nrow = length(suprow))
    Ntemp  <- Ntemp[-suprow,]
    rs.sum <- apply(SR, 1, sum)
    }
  N <- matrix(as.matrix(Ntemp), nrow = dim(Ntemp)[1], ncol = dim(Ntemp)[2])
 # Adjustment for subset CA
  subsetrowt <- subsetrow
  if (!is.na(subsetrow[1]) & !is.na(suprow[1])) {
    subsetrowi <- subsetrow
    subsetrowt <- sort(c(subsetrow, suprow))
    subsetrowt <- subsetrowt[!duplicated(subsetrowt)]
    I <- length(subsetrowt)
   # adjust subset index
    for (q in length(suprow):1) {
      subsetrow <- subsetrow[subsetrow != suprow[q]]
      subsetrow <- subsetrow - as.numeric(suprow[q] < subsetrow)
      }
   # adjust supplementary row indexes:
    for (q in 1:length(suprow)) suprow[q] <- (1:length(subsetrowt))[subsetrowt == suprow[q]]
    }
  subsetcolt <- subsetcol
  if (!is.na(subsetcol[1]) & !is.na(supcol[1])) {
    subsetcoli <- subsetcol
    subsetcolt <- sort(c(subsetcol, supcol))
    subsetcolt <- subsetcolt[!duplicated(subsetcolt)]
    J <- length(subsetcolt)
   # adjust subset index
    for (q in length(supcol):1) {
      subsetcol <- subsetcol[subsetcol != supcol[q]]
      subsetcol <- subsetcol - as.numeric(supcol[q] < subsetcol)
      }
   # adjust supplementary column indexes:
    for (q in 1:length(supcol)) supcol[q] <- (1:length(subsetcolt))[subsetcolt == supcol[q]]
    }
 # check for subset CA
  dim.N <- dim(N)
  if (!is.na(subsetrow[1])) {
    if (!is.na(supcol[1])) SC <- as.matrix(SC[subsetrow,])
    }
  if (!is.na(subsetcol[1])) {
    if (!is.na(suprow[1])) SR <- matrix(as.matrix(SR[,subsetcol]), nrow = length(suprow))
    }
 # end subset CA
  if (is.na(subsetrow[1]) & is.na(subsetcol[1])) {
    nd.max <- min(dim.N) - 1
    } else { # subset-case below:
    N00 <- N
    if (!is.na(subsetrow[1])) N00 <- N00[subsetrow,]
    if (!is.na(subsetcol[1])) N00 <- N00[,subsetcol]
    dim.N  <- dim(N00)
    nd.max <- min(dim.N)
    if (!is.na(subsetrow[1]) & is.na(subsetcol[1])){
      if (dim.N[1] > dim.N[2]) nd.max <- min(dim.N) - 1
      } else {
      if (is.na(subsetrow[1]) & !is.na(subsetcol[1])){
        if (dim.N[2] > dim.N[1]){ 
          nd.max <- min(dim.N) - 1
          } 
        }
      }
    }
  if (is.na(nd) | nd > nd.max ) nd <- nd.max
 # Init:
  n  <- sum(N) ; P <- N/n
  rm <- apply(P, 1, sum) ; cm <- apply(P, 2, sum)
 # SVD:
  eP <- rm %*% t(cm)
  eN <- eP * n
  S  <- (P-eP)/sqrt(eP)
 # subset CA
  if (!is.na(subsetcol[1])) { 
    S  <- S[,subsetcol] 
    cm <- cm[subsetcol]
    cn <- cn[subsetcolt]
    }
  if (!is.na(subsetrow[1])) { 
    S  <- S[subsetrow,]
    rm <- rm[subsetrow]
    rn <- rn[subsetrowt]
    }
 # end sCA
  chimat <- S^2 * n
  dec    <- svd(S)
  sv     <- dec$d[1:nd.max]
  u      <- dec$u
  v      <- dec$v
  ev     <- sv^2
  cumev  <- cumsum(ev)
 # Inertia:
  totin <- sum(ev)
  rin   <- apply(S^2, 1, sum)
  cin   <- apply(S^2, 2, sum)
 # chidist
  rachidist <- sqrt(rin / rm)
  cachidist <- sqrt(cin / cm)
  rchidist  <- rep(NA, I) 
  cchidist  <- rep(NA, J) 
  if (!is.na(subsetrow[1])) {
    obj <- obj[subsetrowt,]
    }
  if (!is.na(subsetcol[1])) {
    obj <- obj[,subsetcolt]
    }
 # supplementary rows/columns:
  if (!is.na(suprow[1])) {
    if (is.na(supcol[1])) {
      P.stemp <- matrix(as.matrix(obj[suprow,]), nrow = length(suprow))
      } else{
      P.stemp <- matrix(as.matrix(obj[suprow, -supcol]), nrow = length(suprow))
      }
    P.stemp           <- P.stemp / apply(P.stemp, 1, sum)
    P.stemp           <- t((t(P.stemp) - cm) / sqrt(cm))
    rschidist         <- sqrt(apply(P.stemp^2, 1, sum))
    rchidist[-suprow] <- rachidist
    rchidist[suprow]  <- rschidist
    } else rchidist <- rachidist
  if (!is.na(supcol[1])) {
    if (is.na(suprow[1])) {
      P.stemp <- as.matrix(obj[, supcol])
      } else {
      P.stemp <- as.matrix(obj[-suprow, supcol])
      }
    P.stemp           <- t(t(P.stemp) / apply(P.stemp, 2, sum))
    P.stemp           <- (P.stemp - rm) / sqrt(rm)
    cschidist         <- sqrt(apply(P.stemp^2, 2, sum))
    cchidist[-supcol] <- cachidist
    cchidist[supcol]  <- cschidist
    } else {
    cchidist <- cachidist
    }
 # Standard coordinates:
  phi <- as.matrix(u[,1:nd]) / sqrt(rm)
  gam <- as.matrix(v[,1:nd]) / sqrt(cm)
 # Standard coordinates for supplementary rows/columns
  if (!is.na(suprow[1])) {
    cs             <- cm
    gam.00         <- gam
    base2          <- SR / matrix(rs.sum, nrow = nrow(SR), ncol = ncol(SR))
    base2          <- t(base2)
    cs.0           <- matrix(cs, nrow = nrow(base2), ncol = ncol(base2))
    svphi          <- matrix(sv[1:nd], nrow = length(suprow), ncol = nd, byrow = TRUE) 
    base2          <- base2 - cs.0
    phi2           <- (t(as.matrix(base2)) %*% gam.00) / svphi
    phi3           <- matrix(NA, ncol = nd, nrow = I)
    phi3[suprow,]  <- phi2
    phi3[-suprow,] <- phi
    rm0            <- rep(NA, I)
    rm0[-suprow]   <- rm
    P.star         <- SR / n
    rm0[suprow]    <- NA # apply(P.star, 1, sum)
    rin0           <- rep(NA, I)
    rin0[-suprow]  <- rin
    rin            <- rin0
	rm.old <- rm
    rm <- rm0
    }
  if (!is.na(supcol[1])) {
    if (!is.na(suprow[1])) {
      rs <- rm.old
      } else {
      rs <- rm
      }
    phi.00         <- phi
    base2          <- SC / matrix(cs.sum, nrow = nrow(SC), ncol = ncol(SC), byrow = TRUE)
    rs.0           <- matrix(rs, nrow = nrow(base2), ncol = ncol(base2))
    svgam          <- matrix(sv[1:nd], nrow = length(supcol), ncol = nd, byrow = TRUE)
    base2          <- base2 - rs.0
    gam2           <- (as.matrix(t(base2)) %*% phi.00) / svgam
    gam3           <- matrix(NA, ncol = nd, nrow = J)
    gam3[supcol,]  <- gam2
    gam3[-supcol,] <- gam
    cm0            <- rep(NA, J)
    cm0[-supcol]   <- cm
    P.star         <- SC / n
    cm0[supcol]    <- NA
    cin0           <- rep(NA, J)
    cin0[-supcol]  <- cin
    cin            <- cin0
    cm <- cm0
    }
  if (exists("phi3")){
    phi <- phi3
    }
  if (exists("gam3")){
    gam <- gam3
    }
#  if (exists("rm0")){
#    rm <- rm0
#    }
#  if (exists("cm0")){
#    cm <- cm0
#    }
  dims <- paste0("Dim", seq_along(sv))[1:nd] 
  dimnames(phi) <- list(rn, dims)
  dimnames(gam) <- list(cn, dims)
 ca.output <- list(sv         = sv, 
                   nd         = nd0,
                   rownames   = rn, 
                   rowmass    = rm, 
                   rowdist    = rchidist,
                   rowinertia = rin, 
                   rowcoord   = phi, 
                   rowsup     = suprow, 
                   colnames   = cn, 
                   colmass    = cm, 
                   coldist    = cchidist,
                   colinertia = cin, 
                   colcoord   = gam, 
                   colsup     = supcol,
                   N          = N,
                   call       = match.call())
  class(ca.output) <- "ca"
  return(ca.output)  
  }
################################################################################
# generic ca()
ca <- function(obj, ...){
  UseMethod("ca")
  }
# ca.xtabs()
ca.xtabs <- function(obj, ...){
  if ((m <- length(dim(obj))) > 2L){
    stop(gettextf("Frequency table is %d-dimensional", m), domain = NA)
    }
  ca.matrix(obj, ...)
  }
# ca.formula()
ca.formula <- function (formula, data = parent.frame(), ...){
  rhs <- formula[[length(formula)]]
  if (length(rhs[[2L]]) > 1L || length(rhs[[3L]]) > 1L){
    stop("Higher-way table requested. Only 2-way allowed")
    }
  tab <- table(eval(rhs[[2L]], data), eval(rhs[[3L]], data))
  names(dimnames(tab)) <- as.character(c(rhs[[2L]], rhs[[3L]]))
  ca.matrix(tab, ...)
  }
# ca.data.frame()
ca.data.frame <- function (obj, ...){
  ca.matrix(as.matrix(obj), ...)
  }
# ca.table()
ca.table <- function (obj, ...){
  if ((m <- length(dim(obj))) > 2L){
    stop(gettextf("Frequency table is %d-dimensional", m), domain = NA)
    }
  class(obj) <- "matrix"
  ca.matrix(obj, ...)
  }
# ca.default()
ca.default <- function (obj, ...){
  stop(paste("class", class(obj), "Objects are not valid for ca" ))
  }
################################################################################
