#' Frequency Distribution of Many Discrete Variables
#'
#' @param ... Discrete/categorical variables to be tabulated
#' @param sortrow = 0  not to sort the rows of the result (category values)
#' @param sortcol = 1  to sort the column of the result (variable names)
#' @param useNA = "ifany" if the frequency of NA is needed.
#' @param debug = 1 to print intermediate result
#'
#' @details
#' If \code{X} is a matrix consisting of discrete variables, \cr
#' \code{freqc(X)} is equivaleet to
#' \preformatted{
#'   freq=lapply(as.list(X),table)
#'   res2=mapply( function(x,name){
#'     y=matrix(x,1); colnames(y)=names(x); rownames(y)=name;
#'     return(as.data.frame(y))  }
#'     ,  freq, names(freq) )
#' }
#' 
#' Space or Blank values will be denoted as V1.
#'
#' @return
#' A values x variables matrix containing the frequencies. \cr
#' \code{F <- freqc( a, b )} returns a matrix \code{F}
#' whose i-j element contains the frequency of value \code{rownames(F)[i]}
#' in the variable \code{colnames(F)[j]}.
#'
#' @examples
#' set.seed(1701)
#' a <- sample(1:9,20,replace=1)
#' b <- letters[sample(1:9,20,replace=1)]
#' c <- sample(3:5,20,replace=1)
#' d <- letters[sample(5:9,20,replace=1)]
#'
#' a[9] <- NA
#' b[3:4] <- NA
#'
#' data <- data.frame( a, b )
#'
#' res1 <- freqc(a,b,c,d)
#' res2 <- freqc(data,c,d)
#' res3 <- freqc(c,d,a,b)
#' Print(res1,res2,res3)
#' res4 <- freqc(c,d,a,b, sortrow=0)
#' res5 <- freqc(c,d,a,b, sortcol=1)
#' Print(res1,res4,res5)
#'
#' res11 <- freqc(a,b,c,d, useNA="ifany")
#' res21 <- freqc(data,c,d, useNA="ifany")
#' Print(res11,res21)
#'
#' @export
#'

freqc <- function( ..., useNA="no", sortrow=1, sortcol=0, debug=0 ){
 # univariate freq dist of many discrete varaibles
 # Shin-ichi Mayekawa
 # 20200830c, 0921
 # input as ...: 20200922
 # bugfix for factor: 20221023
 # simplify in mapply: 20221024
 # When ... consists of a single matrix: 20230118
 # sort as.numeric: 20230118
 # 
 
 # analyze ...
 temp=analyze_three_dots( ... )
 name=temp$name
 val=temp$val
 n=length(name)
 
 allmat=unlist( lapply(val,is.matrix) )
 
 # error
 if( n == 0 ){
  cat("\nerror1:(freqc) The argument is empty. \n")
  stop()
 }
 
 val2=NULL
 name2=NULL
 for( i in 1:n ){
  if(is.vector(val[[i]]) | is.factor(val[[i]]) ){
   val2=append(val2,list(val[[i]]))
   name2=c(name2,name[i])
  }
  else{
   vv=data.frame(val[[i]])
   val2=append(val2, as.list(vv))
   name2=c(name2,colnames(vv))
   n=length(val2)
  }
 }
 names(val2)=name2
 
 
 
 
 if( debug ){
  Print(name2)
  if( debug >= 9 ) Print(name2,val2)
 }
 
 # tabulate all:  result is a list
 freq=lapply(val2, table, useNA=useNA)
 names(freq)=name2
 
 if( debug ) Print(freq)
 
 # change NA in the names to "<NA>"
 freq=lapply( freq, function(x){ names(x)[is.na(names(x))]="<NA>"; x} )
 
 if( debug ) Print("NA",freq)
 
 if(0){
  # blanks
  freq=lapply( freq, function(x){
   names(x)[grep("[ ]+",names(x))]="sp";
   return(x)
  })
 }
 
 # convert the list elements to a data frame with rownames
 res2=mapply( function(x,name){
  y=matrix(x,1);
  colnames(y)=names(x);
  rownames(y)=name;
  return(as.data.frame(y))  }
  ,  freq, names(freq), SIMPLIFY=FALSE )
 
 if( debug ) Print("df", res2, names(res2))
 
 if( n == 1 ){
  res3=matrix(unlist(res2),,1)
  rownames(res3)=names(res2[[1]])
  colnames(res3)=names(res2)[[1]]
 }
 else{
  # stack them all
  res3=Reduce( stack_df, res2 )
  
  if( debug ) Print("n>1", res3)
  
  # transpose the result
  if( debug ) Print(colnames(res3))
  res3=t(res3)
 }
 
 if( debug ) Print("after t", res3)
 
 # sort by the rownames=category values
 if( sortrow == 1 ){
  if( is.number(rownames(res3)) ) od=order(as.numeric(rownames(res3))) 
  else od=order(rownames(res3))
  res3=res3[od,,drop=0]
 }
 if( sortcol == 1 ){
  od=order(colnames(res3))
  res3=res3[,od,drop=0]
 }
 
 # move "<NA>" to the very bottom
 locna=which(rownames(res3) == "<NA>")
 if( length(locna) > 0 ){
  res3=rbind(res3[-locna,,drop=0],res3[locna,,drop=0])
 }
 
 return( res3 )
 
} # end of freqc


